forked from mirrors/gecko-dev
		
	MozReview-Commit-ID: FeV1k9Piwuo --HG-- extra : rebase_source : 96ae191da76733e2d9c9a823d3f025025ff9244a
		
			
				
	
	
		
			336 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			336 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#!/usr/bin/env python
 | 
						|
# Copyright (c) 2002-2005 ActiveState Corp.
 | 
						|
# See LICENSE.txt for license details.
 | 
						|
# Author:
 | 
						|
#   Trent Mick (TrentM@ActiveState.com)
 | 
						|
# Home:
 | 
						|
#   http://trentm.com/projects/which/
 | 
						|
 | 
						|
r"""Find the full path to commands.
 | 
						|
 | 
						|
which(command, path=None, verbose=0, exts=None)
 | 
						|
    Return the full path to the first match of the given command on the
 | 
						|
    path.
 | 
						|
 | 
						|
whichall(command, path=None, verbose=0, exts=None)
 | 
						|
    Return a list of full paths to all matches of the given command on
 | 
						|
    the path.
 | 
						|
 | 
						|
whichgen(command, path=None, verbose=0, exts=None)
 | 
						|
    Return a generator which will yield full paths to all matches of the
 | 
						|
    given command on the path.
 | 
						|
    
 | 
						|
By default the PATH environment variable is searched (as well as, on
 | 
						|
Windows, the AppPaths key in the registry), but a specific 'path' list
 | 
						|
to search may be specified as well.  On Windows, the PATHEXT environment
 | 
						|
variable is applied as appropriate.
 | 
						|
 | 
						|
If "verbose" is true then a tuple of the form
 | 
						|
    (<fullpath>, <matched-where-description>)
 | 
						|
is returned for each match. The latter element is a textual description
 | 
						|
of where the match was found. For example:
 | 
						|
    from PATH element 0
 | 
						|
    from HKLM\SOFTWARE\...\perl.exe
 | 
						|
"""
 | 
						|
 | 
						|
_cmdlnUsage = """
 | 
						|
    Show the full path of commands.
 | 
						|
 | 
						|
    Usage:
 | 
						|
        which [<options>...] [<command-name>...]
 | 
						|
 | 
						|
    Options:
 | 
						|
        -h, --help      Print this help and exit.
 | 
						|
        -V, --version   Print the version info and exit.
 | 
						|
 | 
						|
        -a, --all       Print *all* matching paths.
 | 
						|
        -v, --verbose   Print out how matches were located and
 | 
						|
                        show near misses on stderr.
 | 
						|
        -q, --quiet     Just print out matches. I.e., do not print out
 | 
						|
                        near misses.
 | 
						|
 | 
						|
        -p <altpath>, --path=<altpath>
 | 
						|
                        An alternative path (list of directories) may
 | 
						|
                        be specified for searching.
 | 
						|
        -e <exts>, --exts=<exts>
 | 
						|
                        Specify a list of extensions to consider instead
 | 
						|
                        of the usual list (';'-separate list, Windows
 | 
						|
                        only).
 | 
						|
 | 
						|
    Show the full path to the program that would be run for each given
 | 
						|
    command name, if any. Which, like GNU's which, returns the number of
 | 
						|
    failed arguments, or -1 when no <command-name> was given.
 | 
						|
 | 
						|
    Near misses include duplicates, non-regular files and (on Un*x)
 | 
						|
    files without executable access.
 | 
						|
"""
 | 
						|
 | 
						|
__revision__ = "$Id: which.py 430 2005-08-20 03:11:58Z trentm $"
 | 
						|
__version_info__ = (1, 1, 0)
 | 
						|
__version__ = '.'.join(map(str, __version_info__))
 | 
						|
 | 
						|
import os
 | 
						|
import sys
 | 
						|
import getopt
 | 
						|
import stat
 | 
						|
 | 
						|
 | 
						|
#---- exceptions
 | 
						|
 | 
						|
class WhichError(Exception):
 | 
						|
    pass
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#---- internal support stuff
 | 
						|
 | 
						|
def _getRegisteredExecutable(exeName):
 | 
						|
    """Windows allow application paths to be registered in the registry."""
 | 
						|
    registered = None
 | 
						|
    if sys.platform.startswith('win'):
 | 
						|
        if os.path.splitext(exeName)[1].lower() != '.exe':
 | 
						|
            exeName += '.exe'
 | 
						|
        import _winreg
 | 
						|
        try:
 | 
						|
            key = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" +\
 | 
						|
                  exeName
 | 
						|
            value = _winreg.QueryValue(_winreg.HKEY_LOCAL_MACHINE, key)
 | 
						|
            registered = (value, "from HKLM\\"+key)
 | 
						|
        except _winreg.error:
 | 
						|
            pass
 | 
						|
        if registered and not os.path.exists(registered[0]):
 | 
						|
            registered = None
 | 
						|
    return registered
 | 
						|
 | 
						|
def _samefile(fname1, fname2):
 | 
						|
    if sys.platform.startswith('win'):
 | 
						|
        return ( os.path.normpath(os.path.normcase(fname1)) ==\
 | 
						|
            os.path.normpath(os.path.normcase(fname2)) )
 | 
						|
    else:
 | 
						|
        return os.path.samefile(fname1, fname2)
 | 
						|
 | 
						|
def _cull(potential, matches, verbose=0):
 | 
						|
    """Cull inappropriate matches. Possible reasons:
 | 
						|
        - a duplicate of a previous match
 | 
						|
        - not a disk file
 | 
						|
        - not executable (non-Windows)
 | 
						|
    If 'potential' is approved it is returned and added to 'matches'.
 | 
						|
    Otherwise, None is returned.
 | 
						|
    """
 | 
						|
    for match in matches:  # don't yield duplicates
 | 
						|
        if _samefile(potential[0], match[0]):
 | 
						|
            if verbose:
 | 
						|
                sys.stderr.write("duplicate: %s (%s)\n" % potential)
 | 
						|
            return None
 | 
						|
    else:
 | 
						|
        if not stat.S_ISREG(os.stat(potential[0]).st_mode):
 | 
						|
            if verbose:
 | 
						|
                sys.stderr.write("not a regular file: %s (%s)\n" % potential)
 | 
						|
        elif not os.access(potential[0], os.X_OK):
 | 
						|
            if verbose:
 | 
						|
                sys.stderr.write("no executable access: %s (%s)\n"\
 | 
						|
                                 % potential)
 | 
						|
        else:
 | 
						|
            matches.append(potential)
 | 
						|
            return potential
 | 
						|
 | 
						|
        
 | 
						|
#---- module API
 | 
						|
 | 
						|
def whichgen(command, path=None, verbose=0, exts=None):
 | 
						|
    """Return a generator of full paths to the given command.
 | 
						|
    
 | 
						|
    "command" is a the name of the executable to search for.
 | 
						|
    "path" is an optional alternate path list to search. The default it
 | 
						|
        to use the PATH environment variable.
 | 
						|
    "verbose", if true, will cause a 2-tuple to be returned for each
 | 
						|
        match. The second element is a textual description of where the
 | 
						|
        match was found.
 | 
						|
    "exts" optionally allows one to specify a list of extensions to use
 | 
						|
        instead of the standard list for this system. This can
 | 
						|
        effectively be used as an optimization to, for example, avoid
 | 
						|
        stat's of "foo.vbs" when searching for "foo" and you know it is
 | 
						|
        not a VisualBasic script but ".vbs" is on PATHEXT. This option
 | 
						|
        is only supported on Windows.
 | 
						|
 | 
						|
    This method returns a generator which yields either full paths to
 | 
						|
    the given command or, if verbose, tuples of the form (<path to
 | 
						|
    command>, <where path found>).
 | 
						|
    """
 | 
						|
    matches = []
 | 
						|
    if path is None:
 | 
						|
        usingGivenPath = 0
 | 
						|
        path = os.environ.get("PATH", "").split(os.pathsep)
 | 
						|
        if sys.platform.startswith("win"):
 | 
						|
            path.insert(0, os.curdir)  # implied by Windows shell
 | 
						|
    else:
 | 
						|
        usingGivenPath = 1
 | 
						|
 | 
						|
    # Windows has the concept of a list of extensions (PATHEXT env var).
 | 
						|
    if sys.platform.startswith("win"):
 | 
						|
        if exts is None:
 | 
						|
            exts = os.environ.get("PATHEXT", "").split(os.pathsep)
 | 
						|
            # If '.exe' is not in exts then obviously this is Win9x and
 | 
						|
            # or a bogus PATHEXT, then use a reasonable default.
 | 
						|
            for ext in exts:
 | 
						|
                if ext.lower() == ".exe":
 | 
						|
                    break
 | 
						|
            else:
 | 
						|
                exts = ['.COM', '.EXE', '.BAT']
 | 
						|
        elif not isinstance(exts, list):
 | 
						|
            raise TypeError("'exts' argument must be a list or None")
 | 
						|
    else:
 | 
						|
        if exts is not None:
 | 
						|
            raise WhichError("'exts' argument is not supported on "\
 | 
						|
                             "platform '%s'" % sys.platform)
 | 
						|
        exts = []
 | 
						|
 | 
						|
    # File name cannot have path separators because PATH lookup does not
 | 
						|
    # work that way.
 | 
						|
    if os.sep in command or os.altsep and os.altsep in command:
 | 
						|
        pass
 | 
						|
    else:
 | 
						|
        for i in range(len(path)):
 | 
						|
            dirName = path[i]
 | 
						|
            # On windows the dirName *could* be quoted, drop the quotes
 | 
						|
            if sys.platform.startswith("win") and len(dirName) >= 2\
 | 
						|
               and dirName[0] == '"' and dirName[-1] == '"':
 | 
						|
                dirName = dirName[1:-1]
 | 
						|
            for ext in ['']+exts:
 | 
						|
                absName = os.path.abspath(
 | 
						|
                    os.path.expanduser(
 | 
						|
                    os.path.normpath(os.path.join(dirName, command+ext))))
 | 
						|
                if os.path.isfile(absName):
 | 
						|
                    if usingGivenPath:
 | 
						|
                        fromWhere = "from given path element %d" % i
 | 
						|
                    elif not sys.platform.startswith("win"):
 | 
						|
                        fromWhere = "from PATH element %d" % i
 | 
						|
                    elif i == 0:
 | 
						|
                        fromWhere = "from current directory"
 | 
						|
                    else:
 | 
						|
                        fromWhere = "from PATH element %d" % (i-1)
 | 
						|
                    match = _cull((absName, fromWhere), matches, verbose)
 | 
						|
                    if match:
 | 
						|
                        if verbose:
 | 
						|
                            yield match
 | 
						|
                        else:
 | 
						|
                            yield match[0]
 | 
						|
        match = _getRegisteredExecutable(command)
 | 
						|
        if match is not None:
 | 
						|
            match = _cull(match, matches, verbose)
 | 
						|
            if match:
 | 
						|
                if verbose:
 | 
						|
                    yield match
 | 
						|
                else:
 | 
						|
                    yield match[0]
 | 
						|
 | 
						|
 | 
						|
def which(command, path=None, verbose=0, exts=None):
 | 
						|
    """Return the full path to the first match of the given command on
 | 
						|
    the path.
 | 
						|
    
 | 
						|
    "command" is a the name of the executable to search for.
 | 
						|
    "path" is an optional alternate path list to search. The default it
 | 
						|
        to use the PATH environment variable.
 | 
						|
    "verbose", if true, will cause a 2-tuple to be returned. The second
 | 
						|
        element is a textual description of where the match was found.
 | 
						|
    "exts" optionally allows one to specify a list of extensions to use
 | 
						|
        instead of the standard list for this system. This can
 | 
						|
        effectively be used as an optimization to, for example, avoid
 | 
						|
        stat's of "foo.vbs" when searching for "foo" and you know it is
 | 
						|
        not a VisualBasic script but ".vbs" is on PATHEXT. This option
 | 
						|
        is only supported on Windows.
 | 
						|
 | 
						|
    If no match is found for the command, a WhichError is raised.
 | 
						|
    """
 | 
						|
    try:
 | 
						|
        match = whichgen(command, path, verbose, exts).next()
 | 
						|
    except StopIteration:
 | 
						|
        raise WhichError("Could not find '%s' on the path." % command)
 | 
						|
    return match
 | 
						|
 | 
						|
 | 
						|
def whichall(command, path=None, verbose=0, exts=None):
 | 
						|
    """Return a list of full paths to all matches of the given command
 | 
						|
    on the path.  
 | 
						|
 | 
						|
    "command" is a the name of the executable to search for.
 | 
						|
    "path" is an optional alternate path list to search. The default it
 | 
						|
        to use the PATH environment variable.
 | 
						|
    "verbose", if true, will cause a 2-tuple to be returned for each
 | 
						|
        match. The second element is a textual description of where the
 | 
						|
        match was found.
 | 
						|
    "exts" optionally allows one to specify a list of extensions to use
 | 
						|
        instead of the standard list for this system. This can
 | 
						|
        effectively be used as an optimization to, for example, avoid
 | 
						|
        stat's of "foo.vbs" when searching for "foo" and you know it is
 | 
						|
        not a VisualBasic script but ".vbs" is on PATHEXT. This option
 | 
						|
        is only supported on Windows.
 | 
						|
    """
 | 
						|
    return list( whichgen(command, path, verbose, exts) )
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#---- mainline
 | 
						|
 | 
						|
def main(argv):
 | 
						|
    all = 0
 | 
						|
    verbose = 0
 | 
						|
    altpath = None
 | 
						|
    exts = None
 | 
						|
    try:
 | 
						|
        optlist, args = getopt.getopt(argv[1:], 'haVvqp:e:',
 | 
						|
            ['help', 'all', 'version', 'verbose', 'quiet', 'path=', 'exts='])
 | 
						|
    except getopt.GetoptError, msg:
 | 
						|
        sys.stderr.write("which: error: %s. Your invocation was: %s\n"\
 | 
						|
                         % (msg, argv))
 | 
						|
        sys.stderr.write("Try 'which --help'.\n")
 | 
						|
        return 1
 | 
						|
    for opt, optarg in optlist:
 | 
						|
        if opt in ('-h', '--help'):
 | 
						|
            print _cmdlnUsage
 | 
						|
            return 0
 | 
						|
        elif opt in ('-V', '--version'):
 | 
						|
            print "which %s" % __version__
 | 
						|
            return 0
 | 
						|
        elif opt in ('-a', '--all'):
 | 
						|
            all = 1
 | 
						|
        elif opt in ('-v', '--verbose'):
 | 
						|
            verbose = 1
 | 
						|
        elif opt in ('-q', '--quiet'):
 | 
						|
            verbose = 0
 | 
						|
        elif opt in ('-p', '--path'):
 | 
						|
            if optarg:
 | 
						|
                altpath = optarg.split(os.pathsep)
 | 
						|
            else:
 | 
						|
                altpath = []
 | 
						|
        elif opt in ('-e', '--exts'):
 | 
						|
            if optarg:
 | 
						|
                exts = optarg.split(os.pathsep)
 | 
						|
            else:
 | 
						|
                exts = []
 | 
						|
 | 
						|
    if len(args) == 0:
 | 
						|
        return -1
 | 
						|
 | 
						|
    failures = 0
 | 
						|
    for arg in args:
 | 
						|
        #print "debug: search for %r" % arg
 | 
						|
        nmatches = 0
 | 
						|
        for match in whichgen(arg, path=altpath, verbose=verbose, exts=exts):
 | 
						|
            if verbose:
 | 
						|
                print "%s (%s)" % match
 | 
						|
            else:
 | 
						|
                print match
 | 
						|
            nmatches += 1
 | 
						|
            if not all:
 | 
						|
                break
 | 
						|
        if not nmatches:
 | 
						|
            failures += 1
 | 
						|
    return failures
 | 
						|
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    sys.exit( main(sys.argv) )
 | 
						|
 | 
						|
 |