Mercurial > hg
changeset 7732:3793802ea41b
Make util.find_exe alway returns existing file, fixing issue1459
It seems like the old behaviour with different handling for commands with and
without path was intended, but I think this behaviour of util.find_exe is
better:
* Always returns existing file
* or None if command not found - no default
* Windows: Returned file thus always ends with extension from PATHEXT
This fixes http://www.selenic.com/mercurial/bts/issue1459. The change might
fix other unintended behaviour too.
author | Mads Kiilerich <mads@kiilerich.com> |
---|---|
date | Sun, 25 Jan 2009 21:20:13 +0100 |
parents | 737f274d1915 |
children | 30e95eafc1d0 |
files | mercurial/patch.py mercurial/util.py tests/test-merge-tools.out |
diffstat | 3 files changed, 50 insertions(+), 48 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/patch.py Sun Jan 25 21:20:11 2009 +0100 +++ b/mercurial/patch.py Sun Jan 25 21:20:13 2009 +0100 @@ -1137,7 +1137,7 @@ try: return internalpatch(patchname, ui, strip, cwd, files) except NoHunks: - patcher = util.find_exe('gpatch') or util.find_exe('patch') + patcher = util.find_exe('gpatch') or util.find_exe('patch') or 'patch' ui.debug(_('no valid hunks found; trying with %r instead\n') % patcher) if util.needbinarypatch():
--- a/mercurial/util.py Sun Jan 25 21:20:11 2009 +0100 +++ b/mercurial/util.py Sun Jan 25 21:20:13 2009 +0100 @@ -653,7 +653,7 @@ elif main_is_frozen(): set_hgexecutable(sys.executable) else: - set_hgexecutable(find_exe('hg', 'hg')) + set_hgexecutable(find_exe('hg') or 'hg') return _hgexecutable def set_hgexecutable(path): @@ -1270,29 +1270,33 @@ def isowner(fp, st=None): return True - def find_in_path(name, path, default=None): - '''find name in search path. path can be string (will be split - with os.pathsep), or iterable thing that returns strings. if name - found, return path to name. else return default. name is looked up - using cmd.exe rules, using PATHEXT.''' - if isinstance(path, str): - path = path.split(os.pathsep) - + def find_exe(command): + '''Find executable for command searching like cmd.exe does. + If command is a basename then PATH is searched for command. + PATH isn't searched if command is an absolute or relative path. + An extension from PATHEXT is found and added if not present. + If command isn't found None is returned.''' pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD') - pathext = pathext.lower().split(os.pathsep) - isexec = os.path.splitext(name)[1].lower() in pathext + pathexts = [ext for ext in pathext.lower().split(os.pathsep)] + if os.path.splitext(command)[1].lower() in pathexts: + pathexts = [''] + + def findexisting(pathcommand): + 'Will append extension (if needed) and return existing file' + for ext in pathexts: + executable = pathcommand + ext + if os.path.exists(executable): + return executable + return None - for p in path: - p_name = os.path.join(p, name) - - if isexec and os.path.exists(p_name): - return p_name - - for ext in pathext: - p_name_ext = p_name + ext - if os.path.exists(p_name_ext): - return p_name_ext - return default + if os.sep in command: + return findexisting(command) + + for path in os.environ.get('PATH', '').split(os.pathsep): + executable = findexisting(os.path.join(path, command)) + if executable is not None: + return executable + return None def set_signal_handler(): try: @@ -1458,33 +1462,32 @@ st = fstat(fp) return st.st_uid == os.getuid() - def find_in_path(name, path, default=None): - '''find name in search path. path can be string (will be split - with os.pathsep), or iterable thing that returns strings. if name - found, return path to name. else return default.''' - if isinstance(path, str): - path = path.split(os.pathsep) - for p in path: - p_name = os.path.join(p, name) - if os.path.exists(p_name): - return p_name - return default + def find_exe(command): + '''Find executable for command searching like which does. + If command is a basename then PATH is searched for command. + PATH isn't searched if command is an absolute or relative path. + If command isn't found None is returned.''' + if sys.platform == 'OpenVMS': + return command + + def findexisting(executable): + 'Will return executable if existing file' + if os.path.exists(executable): + return executable + return None + + if os.sep in command: + return findexisting(command) + + for path in os.environ.get('PATH', '').split(os.pathsep): + executable = findexisting(os.path.join(path, command)) + if executable is not None: + return executable + return None def set_signal_handler(): pass -def find_exe(name, default=None): - '''find path of an executable. - if name contains a path component, return it as is. otherwise, - use normal executable search path.''' - - if os.sep in name or sys.platform == 'OpenVMS': - # don't check the executable bit. if the file isn't - # executable, whoever tries to actually run it will give a - # much more useful error message. - return name - return find_in_path(name, os.environ.get('PATH', ''), default=default) - def mktempcopy(name, emptyok=False, createmode=None): """Create a temporary file with the same contents from name
--- a/tests/test-merge-tools.out Sun Jan 25 21:20:11 2009 +0100 +++ b/tests/test-merge-tools.out Sun Jan 25 21:20:13 2009 +0100 @@ -117,7 +117,6 @@ true.priority=1 # hg update -C 1 # hg merge -r 2 --config merge-tools.true.executable=/bin/nonexistingmergetool -sh: /bin/nonexistingmergetool: No such file or directory merging f merging f failed! 0 files updated, 0 files merged, 0 files removed, 1 files unresolved @@ -224,7 +223,7 @@ true.executable=cat # hg update -C 1 # hg merge -r 2 --config merge-patterns.f=true --config merge-tools.true.executable=/bin/nonexistingmergetool -sh: /bin/nonexistingmergetool: No such file or directory +couldn't find merge tool true specified for f merging f merging f failed! 0 files updated, 0 files merged, 0 files removed, 1 files unresolved