PageRenderTime 67ms CodeModel.GetById 38ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/lynx/lynx-1.0.0/scripts/which.py

https://bitbucket.org/yomagg/2012-12-12-clusterwatch
Python | 250 lines | 227 code | 8 blank | 15 comment | 16 complexity | 781c146e6131d37a38989f8568df512b MD5 | raw file
  1. #!/usr/bin/env python
  2. """ Which - locate a command
  3. * adapted from proposal__ by Erik Demaine and patch__ by Brian Curtin, which adds this feature__ to shutil
  4. __ http://bugs.python.org/file8185/find_in_path.py
  5. __ http://bugs.python.org/file15381/shutil_which.patch
  6. __ http://bugs.python.org/issue444582
  7. * which_files() returns generator, which() returns first match,
  8. or raises IOError(errno.ENOENT)
  9. * searches current directory before ``PATH`` on Windows,
  10. but not before an explicitly passed path
  11. * accepts both string or iterable for an explicitly passed path, or pathext
  12. * accepts an explicitly passed empty path, or pathext (either '' or [])
  13. * does not search ``PATH`` for files that have a path specified in their name already
  14. * uses ``PATHEXT`` on Windows, providing a default value for different Windows versions
  15. .. function:: which_files(file [, mode=os.F_OK | os.X_OK[, path=None[, pathext=None]]])
  16. Generate full paths, where the *file* is accesible under *mode*
  17. and is located in the directory passed as a part of the *file* name,
  18. or in any directory on *path* if a base *file* name is passed.
  19. The *mode* matches an existing executable file by default.
  20. The *path* defaults to the ``PATH`` environment variable,
  21. or to :const:`os.defpath` if the ``PATH`` variable is not set.
  22. On Windows, a current directory is searched before directories in the ``PATH`` variable,
  23. but not before directories in an explicitly passed *path* string or iterable.
  24. The *pathext* is used to match files with any of the extensions appended to *file*.
  25. On Windows, it defaults to the ``PATHEXT`` environment variable.
  26. If the ``PATHEXT`` variable is not set, then the default *pathext* value is hardcoded
  27. for different Windows versions, to match the actual search performed on command execution.
  28. On Windows <= 4.x, ie. NT and older, it defaults to '.COM;.EXE;.BAT;.CMD'.
  29. On Windows 5.x, ie. 2k/XP/2003, the extensions '.VBS;.VBE;.JS;.JSE;.WSF;.WSH' are appended,
  30. On Windows >= 6.x, ie. Vista/2008/7, the extension '.MSC' is further appended.
  31. The actual search on command execution may differ under Wine_,
  32. which may use a `different default value`__, that is `not treated specially here`__.
  33. In each directory, the *file* is first searched without any additional extension,
  34. even when a *pathext* string or iterable is explicitly passed.
  35. .. _Wine: http://www.winehq.org/
  36. __ http://source.winehq.org/source/programs/cmd/wcmdmain.c#L1019
  37. __ http://wiki.winehq.org/DeveloperFaq#detect-wine
  38. .. function:: which(file [, mode=os.F_OK | os.X_OK[, path=None[, pathext=None]]])
  39. Return the first full path matched by :func:`which_files`,
  40. or raise :exc:`IOError` (:const:`errno.ENOENT`).
  41. """
  42. __docformat__ = 'restructuredtext en'
  43. __all__ = 'which which_files'.split()
  44. import sys, os, os.path
  45. _windows = sys.platform.startswith('win')
  46. if _windows:
  47. def _getwinpathext(*winver):
  48. """ Return the default PATHEXT value for a particular Windows version.
  49. On Windows <= 4.x, ie. NT and older, it defaults to '.COM;.EXE;.BAT;.CMD'.
  50. On Windows 5.x, ie. 2k/XP/2003, the extensions '.VBS;.VBE;.JS;.JSE;.WSF;.WSH' are appended,
  51. On Windows >= 6.x, ie. Vista/2008/7, the extension '.MSC' is further appended.
  52. Availability: Windows
  53. >>> def test(extensions, *winver):
  54. ... result = _getwinpathext(*winver)
  55. ... expected = os.pathsep.join(['.%s' % ext.upper() for ext in extensions.split()])
  56. ... assert result == expected, 'getwinpathext: %s != %s' % (result, expected)
  57. >>> test('com exe bat cmd', 3)
  58. >>> test('com exe bat cmd', 4)
  59. >>> test('com exe bat cmd vbs vbe js jse wsf wsh', 5)
  60. >>> test('com exe bat cmd vbs vbe js jse wsf wsh msc', 6)
  61. >>> test('com exe bat cmd vbs vbe js jse wsf wsh msc', 7)
  62. """
  63. if not winver:
  64. winver = sys.getwindowsversion()
  65. return os.pathsep.join('.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC'.split(';')[:(
  66. winver[0] < 5 and 4 or winver[0] < 6 and -1 or None )])
  67. def which_files(file, mode=os.F_OK | os.X_OK, path=None, pathext=None):
  68. """ Generate full paths, where the file*is accesible under mode
  69. and is located in the directory passed as a part of the file name,
  70. or in any directory on path if a base file name is passed.
  71. The mode matches an existing executable file by default.
  72. The path defaults to the PATH environment variable,
  73. or to os.defpath if the PATH variable is not set.
  74. On Windows, a current directory is searched before directories in the PATH variable,
  75. but not before directories in an explicitly passed path string or iterable.
  76. The pathext is used to match files with any of the extensions appended to file.
  77. On Windows, it defaults to the ``PATHEXT`` environment variable.
  78. If the PATHEXT variable is not set, then the default pathext value is hardcoded
  79. for different Windows versions, to match the actual search performed on command execution.
  80. On Windows <= 4.x, ie. NT and older, it defaults to '.COM;.EXE;.BAT;.CMD'.
  81. On Windows 5.x, ie. 2k/XP/2003, the extensions '.VBS;.VBE;.JS;.JSE;.WSF;.WSH' are appended,
  82. On Windows >= 6.x, ie. Vista/2008/7, the extension '.MSC' is further appended.
  83. The actual search on command execution may differ under Wine,
  84. which may use a different default value, that is not treated specially here.
  85. In each directory, the file is first searched without any additional extension,
  86. even when a pathext string or iterable is explicitly passed.
  87. >>> def test(expected, *args, **argd):
  88. ... result = list(which_files(*args, **argd))
  89. ... assert result == expected, 'which_files: %s != %s' % (result, expected)
  90. ...
  91. ... try:
  92. ... result = [ which(*args, **argd) ]
  93. ... except IOError:
  94. ... result = []
  95. ... assert result[:1] == expected[:1], 'which: %s != %s' % (result[:1], expected[:1])
  96. >>> ### Set up
  97. >>> import stat, tempfile
  98. >>> dir = tempfile.mkdtemp(prefix='test-')
  99. >>> ext = '.ext'
  100. >>> tmp = tempfile.NamedTemporaryFile(prefix='command-', suffix=ext, dir=dir)
  101. >>> name = tmp.name
  102. >>> file = os.path.basename(name)
  103. >>> here = os.path.join(os.curdir, file)
  104. >>> nonexistent = '%s-nonexistent' % name
  105. >>> path = os.pathsep.join([ nonexistent, name, dir, dir ])
  106. ... # Test also that duplicates are removed, and non-existent objects
  107. ... # or non-directories in path do not trigger any exceptions.
  108. >>> ### Test permissions
  109. >>> test(_windows and [name] or [], file, path=path)
  110. >>> test(_windows and [name] or [], file, mode=os.X_OK, path=path)
  111. ... # executable flag is not needed on Windows
  112. >>> test([name], file, mode=os.F_OK, path=path)
  113. >>> test([name], file, mode=os.R_OK, path=path)
  114. >>> test([name], file, mode=os.W_OK, path=path)
  115. >>> test([name], file, mode=os.R_OK|os.W_OK, path=path)
  116. >>> os.chmod(name, stat.S_IRWXU)
  117. >>> test([name], file, mode=os.R_OK|os.W_OK|os.X_OK, path=path)
  118. >>> ### Test paths
  119. >>> _save_path = os.environ.get('PATH', '')
  120. >>> cwd = os.getcwd()
  121. >>> test([], file, path='')
  122. >>> test([], file, path=nonexistent)
  123. >>> test([], nonexistent, path=path)
  124. >>> test([name], file, path=path)
  125. >>> test([name], name, path=path)
  126. >>> test([name], name, path='')
  127. >>> test([name], name, path=nonexistent)
  128. >>> os.chdir(dir)
  129. >>> test([name], file, path=path)
  130. >>> test([here], file, path=os.curdir)
  131. >>> test([name], name, path=os.curdir)
  132. >>> test([], file, path='')
  133. >>> test([], file, path=nonexistent)
  134. >>> os.environ['PATH'] = path
  135. >>> test(_windows and [here] or [name], file)
  136. ... # current directory is always searched first on Windows
  137. >>> os.environ['PATH'] = os.curdir
  138. >>> test([here], file)
  139. >>> test([name], name)
  140. >>> os.environ['PATH'] = ''
  141. >>> test(_windows and [here] or [], file)
  142. >>> os.environ['PATH'] = nonexistent
  143. >>> test(_windows and [here] or [], file)
  144. >>> os.chdir(cwd)
  145. >>> os.environ['PATH'] = path
  146. >>> test([name], file)
  147. >>> os.environ['PATH'] = _save_path
  148. >>> ### Test extensions
  149. >>> test([], file[:-4], path=path, pathext='')
  150. >>> test([], file[:-4], path=path, pathext=nonexistent)
  151. >>> test([name], file[:-4], path=path, pathext=ext)
  152. >>> test([name], file, path=path, pathext=ext)
  153. >>> test([name], file, path=path, pathext='')
  154. >>> test([name], file, path=path, pathext=nonexistent)
  155. >>> ### Tear down
  156. >>> tmp.close()
  157. >>> os.rmdir(dir)
  158. """
  159. filepath, file = os.path.split(file)
  160. if filepath:
  161. path = (filepath,)
  162. elif path is None:
  163. path = os.environ.get('PATH', os.defpath).split(os.pathsep)
  164. if _windows and not os.curdir in path:
  165. path.insert(0, os.curdir) # current directory is always searched first on Windows
  166. elif isinstance(path, basestring):
  167. path = path.split(os.pathsep)
  168. if pathext is None:
  169. pathext = ['']
  170. if _windows:
  171. pathext += (os.environ.get('PATHEXT', '') or _getwinpathext()).lower().split(os.pathsep)
  172. elif isinstance(pathext, basestring):
  173. pathext = pathext.split(os.pathsep)
  174. if not '' in pathext:
  175. pathext.insert(0, '') # always check command without extension, even for an explicitly passed pathext
  176. seen = set()
  177. for dir in path:
  178. if dir: # only non-empty directories are searched
  179. id = os.path.normcase(os.path.abspath(dir))
  180. if not id in seen: # each directory is searched only once
  181. seen.add(id)
  182. woex = os.path.join(dir, file)
  183. for ext in pathext:
  184. name = woex + ext
  185. if os.path.exists(name) and os.access(name, mode):
  186. yield name
  187. def which(file, mode=os.F_OK | os.X_OK, path=None, pathext=None):
  188. """ Return the first full path matched by which_files(), or raise IOError(errno.ENOENT).
  189. >>> # See which_files() for a doctest.
  190. """
  191. try:
  192. return iter(which_files(file, mode, path, pathext)).next()
  193. except StopIteration:
  194. try:
  195. from errno import ENOENT
  196. except ImportError:
  197. ENOENT = 2
  198. raise IOError(ENOENT, '%s not found' % (mode & os.X_OK and 'command' or 'file'), file)
  199. if __name__ == '__main__':
  200. import doctest
  201. doctest.testmod()