which.py
上传用户:lswyart
上传日期:2008-06-12
资源大小:3441k
文件大小:12k
源码类别:

杀毒

开发平台:

Visual C++

  1. #!/usr/bin/env python
  2. # Copyright (c) 2002-2003 ActiveState Corp.
  3. # Author: Trent Mick (TrentM@ActiveState.com)
  4. r"""Find the full path to commands.
  5. which(command, path=None, verbose=0, exts=None)
  6.     Return the full path to the first match of the given command on the
  7.     path.
  8. whichall(command, path=None, verbose=0, exts=None)
  9.     Return a list of full paths to all matches of the given command on
  10.     the path.
  11. whichgen(command, path=None, verbose=0, exts=None)
  12.     Return a generator which will yield full paths to all matches of the
  13.     given command on the path.
  14.     
  15. By default the PATH environment variable is searched (as well as, on
  16. Windows, the AppPaths key in the registry), but a specific 'path' list
  17. to search may be specified as well.  On Windows, the PATHEXT environment
  18. variable is applied as appropriate.
  19. If "verbose" is true then a tuple of the form
  20.     (<fullpath>, <matched-where-description>)
  21. is returned for each match. The latter element is a textual description
  22. of where the match was found. For example:
  23.     from PATH element 0
  24.     from HKLMSOFTWARE...perl.exe
  25. """
  26. _cmdlnUsage = """
  27.     Show the full path of commands.
  28.     Usage:
  29.         which [<options>...] [<command-name>...]
  30.     Options:
  31.         -h, --help      Print this help and exit.
  32.         -V, --version   Print the version info and exit.
  33.         -a, --all       Print *all* matching paths.
  34.         -v, --verbose   Print out how matches were located and
  35.                         show near misses on stderr.
  36.         -q, --quiet     Just print out matches. I.e., do not print out
  37.                         near misses.
  38.         -p <altpath>, --path=<altpath>
  39.                         An alternative path (list of directories) may
  40.                         be specified for searching.
  41.         -e <exts>, --exts=<exts>
  42.                         Specify a list of extensions to consider instead
  43.                         of the usual list (';'-separate list, Windows
  44.                         only).
  45.     Show the full path to the program that would be run for each given
  46.     command name, if any. Which, like GNU's which, returns the number of
  47.     failed arguments, or -1 when no <command-name> was given.
  48.     Near misses include duplicates, non-regular files and (on Un*x)
  49.     files without executable access.
  50. """
  51. #REQUIREMENTS:
  52. #   - Python >= 2.2 (because of the use of generators)
  53. #
  54. #TODO:
  55. #   - add a "logging" interface for Python 2.3
  56. #
  57. from __future__ import generators
  58. import os
  59. import sys
  60. import getopt
  61. import stat
  62. #---- exceptions
  63. class WhichError(Exception):
  64.     pass
  65. #---- global data
  66. _version_ = (1, 0, 2)
  67. #---- internal support stuff
  68. def _getRegisteredExecutable(exeName):
  69.     """Windows allow application paths to be registered in the registry."""
  70.     registered = None
  71.     if sys.platform.startswith('win'):
  72.         if os.path.splitext(exeName)[1].lower() != '.exe':
  73.             exeName += '.exe'
  74.         import _winreg
  75.         try:
  76.             key = "SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\" +
  77.                   exeName
  78.             value = _winreg.QueryValue(_winreg.HKEY_LOCAL_MACHINE, key)
  79.             registered = (value, "from HKLM\"+key)
  80.         except _winreg.error:
  81.             pass
  82.         if registered and not os.path.exists(registered[0]):
  83.             registered = None
  84.     return registered
  85. def _samefile(fname1, fname2):
  86.     if sys.platform.startswith('win'):
  87.         return ( os.path.normpath(os.path.normcase(fname1)) ==
  88.             os.path.normpath(os.path.normcase(fname2)) )
  89.     else:
  90.         return os.path.samefile(fname1, fname2)
  91. def _cull(potential, matches, verbose=0):
  92.     """Cull inappropriate matches. Possible reasons:
  93.         - a duplicate of a previous match
  94.         - not a disk file
  95.         - not executable (non-Windows)
  96.     If 'potential' is approved it is returned and added to 'matches'.
  97.     Otherwise, None is returned.
  98.     """
  99.     for match in matches:  # don't yield duplicates
  100.         if _samefile(potential[0], match[0]):
  101.             if verbose:
  102.                 sys.stderr.write("duplicate: %s (%s)n" % potential)
  103.             return None
  104.     else:
  105.         if not stat.S_ISREG(os.stat(potential[0]).st_mode):
  106.             if verbose:
  107.                 sys.stderr.write("not a regular file: %s (%s)n" % potential)
  108.         elif not os.access(potential[0], os.X_OK):
  109.             if verbose:
  110.                 sys.stderr.write("no executable access: %s (%s)n"
  111.                                  % potential)
  112.         else:
  113.             matches.append(potential)
  114.             return potential
  115.         
  116. #---- module API
  117. def whichgen(command, path=None, verbose=0, exts=None):
  118.     """Return a generator of full paths to the given command.
  119.     
  120.     "command" is a the name of the executable to search for.
  121.     "path" is an optional alternate path list to search. The default it
  122.         to use the PATH environment variable.
  123.     "verbose", if true, will cause a 2-tuple to be returned for each
  124.         match. The second element is a textual description of where the
  125.         match was found.
  126.     "exts" optionally allows one to specify a list of extensions to use
  127.         instead of the standard list for this system. This can
  128.         effectively be used as an optimization to, for example, avoid
  129.         stat's of "foo.vbs" when searching for "foo" and you know it is
  130.         not a VisualBasic script but ".vbs" is on PATHEXT. This option
  131.         is only supported on Windows.
  132.     This method returns a generator which yields either full paths to
  133.     the given command or, if verbose, tuples of the form (<path to
  134.     command>, <where path found>).
  135.     """
  136.     matches = []
  137.     if path is None:
  138.         usingGivenPath = 0
  139.         path = os.environ.get("PATH", "").split(os.pathsep)
  140.         if sys.platform.startswith("win"):
  141.             path.insert(0, os.curdir)  # implied by Windows shell
  142.     else:
  143.         usingGivenPath = 1
  144.     # Windows has the concept of a list of extensions (PATHEXT env var).
  145.     if sys.platform.startswith("win"):
  146.         if exts is None:
  147.             exts = os.environ.get("PATHEXT", "").split(os.pathsep)
  148.             # If '.exe' is not in exts then obviously this is Win9x and
  149.             # or a bogus PATHEXT, then use a reasonable default.
  150.             for ext in exts:
  151.                 if ext.lower() == ".exe":
  152.                     break
  153.             else:
  154.                 exts = ['.COM', '.EXE', '.BAT']
  155.         elif not isinstance(exts, list):
  156.             raise TypeError("'exts' argument must be a list or None")
  157.     else:
  158.         if exts is not None:
  159.             raise WhichError("'exts' argument is not supported on "
  160.                              "platform '%s'" % sys.platform)
  161.         exts = []
  162.     # File name cannot have path separators because PATH lookup does not
  163.     # work that way.
  164.     if os.sep in command or os.altsep and os.altsep in command:
  165.         pass
  166.     else:
  167.         for i in range(len(path)):
  168.             dirName = path[i]
  169.             # On windows the dirName *could* be quoted, drop the quotes
  170.             if sys.platform.startswith("win") and len(dirName) >= 2
  171.                and dirName[0] == '"' and dirName[-1] == '"':
  172.                 dirName = dirName[1:-1]
  173.             for ext in ['']+exts:
  174.                 absName = os.path.abspath(
  175.                     os.path.normpath(os.path.join(dirName, command+ext)))
  176.                 if os.path.isfile(absName):
  177.                     if usingGivenPath:
  178.                         fromWhere = "from given path element %d" % i
  179.                     elif not sys.platform.startswith("win"):
  180.                         fromWhere = "from PATH element %d" % i
  181.                     elif i == 0:
  182.                         fromWhere = "from current directory"
  183.                     else:
  184.                         fromWhere = "from PATH element %d" % (i-1)
  185.                     match = _cull((absName, fromWhere), matches, verbose)
  186.                     if match:
  187.                         if verbose:
  188.                             yield match
  189.                         else:
  190.                             yield match[0]
  191.         match = _getRegisteredExecutable(command)
  192.         if match is not None:
  193.             match = _cull(match, matches, verbose)
  194.             if match:
  195.                 if verbose:
  196.                     yield match
  197.                 else:
  198.                     yield match[0]
  199. def which(command, path=None, verbose=0, exts=None):
  200.     """Return the full path to the first match of the given command on
  201.     the path.
  202.     
  203.     "command" is a the name of the executable to search for.
  204.     "path" is an optional alternate path list to search. The default it
  205.         to use the PATH environment variable.
  206.     "verbose", if true, will cause a 2-tuple to be returned. The second
  207.         element is a textual description of where the match was found.
  208.     "exts" optionally allows one to specify a list of extensions to use
  209.         instead of the standard list for this system. This can
  210.         effectively be used as an optimization to, for example, avoid
  211.         stat's of "foo.vbs" when searching for "foo" and you know it is
  212.         not a VisualBasic script but ".vbs" is on PATHEXT. This option
  213.         is only supported on Windows.
  214.     If no match is found for the command, a WhichError is raised.
  215.     """
  216.     try:
  217.         match = whichgen(command, path, verbose, exts).next()
  218.     except StopIteration:
  219.         raise WhichError("Could not find '%s' on the path." % command)
  220.     return match
  221. def whichall(command, path=None, verbose=0, exts=None):
  222.     """Return a list of full paths to all matches of the given command
  223.     on the path.  
  224.     "command" is a the name of the executable to search for.
  225.     "path" is an optional alternate path list to search. The default it
  226.         to use the PATH environment variable.
  227.     "verbose", if true, will cause a 2-tuple to be returned for each
  228.         match. The second element is a textual description of where the
  229.         match was found.
  230.     "exts" optionally allows one to specify a list of extensions to use
  231.         instead of the standard list for this system. This can
  232.         effectively be used as an optimization to, for example, avoid
  233.         stat's of "foo.vbs" when searching for "foo" and you know it is
  234.         not a VisualBasic script but ".vbs" is on PATHEXT. This option
  235.         is only supported on Windows.
  236.     """
  237.     return list( whichgen(command, path, verbose, exts) )
  238. #---- mainline
  239. def main(argv):
  240.     all = 0
  241.     verbose = 0
  242.     altpath = None
  243.     exts = None
  244.     try:
  245.         optlist, args = getopt.getopt(argv[1:], 'haVvqp:e:',
  246.             ['help', 'all', 'version', 'verbose', 'quiet', 'path=', 'exts='])
  247.     except getopt.GetoptError, msg:
  248.         sys.stderr.write("which: error: %s. Your invocation was: %sn"
  249.                          % (msg, argv))
  250.         sys.stderr.write("Try 'which --help'.n")
  251.         return 1
  252.     for opt, optarg in optlist:
  253.         if opt in ('-h', '--help'):
  254.             print _cmdlnUsage
  255.             return 0
  256.         elif opt in ('-V', '--version'):
  257.             print "which %s" % '.'.join([str(i) for i in _version_])
  258.             return 0
  259.         elif opt in ('-a', '--all'):
  260.             all = 1
  261.         elif opt in ('-v', '--verbose'):
  262.             verbose = 1
  263.         elif opt in ('-q', '--quiet'):
  264.             verbose = 0
  265.         elif opt in ('-p', '--path'):
  266.             if optarg:
  267.                 altpath = optarg.split(os.pathsep)
  268.             else:
  269.                 altpath = []
  270.         elif opt in ('-e', '--exts'):
  271.             if optarg:
  272.                 exts = optarg.split(os.pathsep)
  273.             else:
  274.                 exts = []
  275.     if len(args) == 0:
  276.         return -1
  277.     failures = 0
  278.     for arg in args:
  279.         #print "debug: search for %r" % arg
  280.         nmatches = 0
  281.         for match in whichgen(arg, path=altpath, verbose=verbose, exts=exts):
  282.             if verbose:
  283.                 print "%s (%s)" % match
  284.             else:
  285.                 print match
  286.             nmatches += 1
  287.             if not all:
  288.                 break
  289.         if not nmatches:
  290.             failures += 1
  291.     return failures
  292. if __name__ == "__main__":
  293.     sys.exit( main(sys.argv) )
  294.