From bf6fd6f69d3da110372520aa7d9befde5f246925 Mon Sep 17 00:00:00 2001 From: Packit Service Date: Jan 04 2021 09:47:27 +0000 Subject: Changes after running %prep ignore: true --- diff --git a/lib/contrib/__init__.py b/lib/contrib/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/lib/contrib/__init__.py +++ /dev/null diff --git a/lib/contrib/debian/__init__.py b/lib/contrib/debian/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/lib/contrib/debian/__init__.py +++ /dev/null diff --git a/lib/contrib/debian/dblatex b/lib/contrib/debian/dblatex deleted file mode 100755 index fbf01fb..0000000 --- a/lib/contrib/debian/dblatex +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python - -# Register the Debian error analyser -from dbtexmf.core import error -from dbtexmf.contrib.debian.errorhandler import DebianHandler -error.set_errhandler(DebianHandler()) - -from dbtexmf.dblatex import dblatex -dblatex.main('/usr/share/dblatex') diff --git a/lib/contrib/debian/errorhandler.py b/lib/contrib/debian/errorhandler.py deleted file mode 100644 index 4faee90..0000000 --- a/lib/contrib/debian/errorhandler.py +++ /dev/null @@ -1,195 +0,0 @@ -# -# Attempt to analyse a dblatex failure occured on a Debian platform. -# -# Author: Andreas Hoenen -# -import subprocess -import sys -import apt -import os - -from dbtexmf.core.error import ErrorHandler -from dbtexmf.core.imagedata import ImageConverter -from dbtexmf.core.dbtex import DbTexCommand - -class AptSilentProgress(apt.progress.text.OpProgress): - """ - Avoid the annoying progress messages when building the apt cache: - Reading package lists... Done - Building dependency tree - Reading state information... Done - Building data structures... Done - """ - def __init__(self, outfile=None): - pass - def done(self): - pass - def update(self, percent=None): - pass - -class DebianHandler(ErrorHandler): - def __init__(self): - ErrorHandler.__init__(self) - self.object = None - self.aptcache = None - - def signal(self, failed_object, *args, **kwargs): - self.object = failed_object - if not self.aptcache: - self.aptcache = apt.Cache(progress=AptSilentProgress()) - if (isinstance(self.object, DbTexCommand)): - error_handled = self._check_dbtexrun() - elif (isinstance(self.object, ImageConverter)): - error_handled = self._check_imagerun(*args) - else: - error_handled = False - if not error_handled: - super(DebianHandler, self).signal(failed_object, *args, **kwargs) - - def _check_dbtexrun(self): - # First, check the XML input sanity - if (self._check_input()): - return True - # Check that all the required utilities are there - if (self._check_dependencies()): - return True - # Check some alternative reasons - if (self._check_cyrillic()): - return True - return False - - def _check_imagerun(self, cmd): - """ - In case of failed image converter calls check on dependency problems. - - In Debian dblatex package dependencies on image converters are not - absolute, as image conversion is not dblatex's core functionality. - Thus the converters may be not installed. Therefore check for each one: - If it is used but missing, dump an appropriate hint. - """ - aptcache = self.aptcache - warn_msgs = [] - if ((cmd.startswith('convert') or cmd.find('&& convert') > -1) - and not aptcache['graphicsmagick-imagemagick-compat'].is_installed - and not aptcache['imagemagick'].is_installed): - warn_msgs.append('For image conversion one of Debian packages' - + ' graphicsmagick-imagemagick-compat') - warn_msgs.append('or imagemagick is needed') - if ((cmd.startswith('epstopdf') or cmd.find('&& epstopdf') > -1) - and not aptcache['ghostscript'].is_installed): - warn_msgs.append('For image conversion Debian package ghostscript' - + ' is needed') - if ((cmd.startswith('fig2dev') or cmd.find('&& fig2dev') > -1) - and not aptcache['transfig'].is_installed): - warn_msgs.append('For image conversion Debian package transfig is' - + ' needed') - if ((cmd.startswith('inkscape') or cmd.find('&& inkscape') > -1) - and not aptcache['inkscape'].is_installed): - warn_msgs.append('For image conversion Debian package inkscape is' - + ' needed') - if warn_msgs: - print >> sys.stderr, "\n" + "\n".join(warn_msgs) + "\n" - return True - else: - return False - - def _check_input(self): - """ - In case of failed processing try to validate the input. - - As invalid DocBook sometimes results in strange TeX error messages, a - hint about the failure cause may be helpful. - Post failure validation is a convenience function and thus works in - a best effort approach, that is it will silently skip any problems, - e.g. the external validation program xmllint not installed. - """ - obj = self.object.run - nulldev0 = open(os.devnull, "r") - nulldev1 = open(os.devnull, "w") - try: - rc = subprocess.Popen(['xmllint', '--noout', '--postvalid', - '--xinclude', obj.input], - stdin=nulldev0, - stderr=nulldev1, - stdout=nulldev1).wait() - except: - rc = -1 - - nulldev0.close() - nulldev1.close() - - if rc == 3 or rc == 4: - print >> sys.stderr - print >> sys.stderr, 'A possible reason for transformation', - print >> sys.stderr, 'failure is invalid DocBook' - print >> sys.stderr, '(as reported by xmllint)' - print >> sys.stderr - return True - else: - return False - - def _check_dependencies(self): - """ - In case of failed processing check on dependency problems. - - For not commonly used dblatex functionality the Debian package - dependencies are not absolute, thus the functionality may be not - installed. Therefore check for each one: - If it is used but a needed dependency is missing, dump an appropriate - hint. - """ - obj = self.object.run - aptcache = self.aptcache - warn_msgs = [] - if obj.backend == 'xetex': - for debian_pkg in 'texlive-xetex', 'lmodern': - if not aptcache[debian_pkg].is_installed: - warn_msgs.append('For xetex backend Debian package ' - + debian_pkg + ' is needed') - if obj.input_format == 'sgml': - for debian_pkg in 'docbook', 'opensp': - if not aptcache[debian_pkg].is_installed: - warn_msgs.append('For SGML documents Debian package ' - + debian_pkg + ' is needed') - if obj.runtex.texer.encoding == 'utf8': - debian_pkg = 'texlive-lang-cyrillic' - if not aptcache[debian_pkg].is_installed: - warn_msgs.append('For utf8 encoding Debian package ' - + debian_pkg + ' is needed') - if warn_msgs: - print >> sys.stderr, "\n" + "\n".join(warn_msgs) + "\n" - return True - else: - return False - - def _check_cyrillic(self): - obj = self.object.run - """ - In case of failed processing check on the "cyrillic scenario": - - Transforming cyrillic documents will fail when neither using the - XeTeX backend nor setting option latex.unicode.use - In this case a hint to XeTeX (as the preferred way) may be helpful. - Post failure validation is a convenience function and thus works in - a best effort approach, that is it will silently skip any problems. - """ - # This kind of error cannot occur with backends that natively support - # Unicode - if obj.backend == 'xetex': - return False - - try: - for log_entry in obj.runtex.texer.tex.log.get_errors(): - if (log_entry['text'] - == r'Undefined control sequence \cyrchar.'): - print >> sys.stderr - print >> sys.stderr, 'Transformation failure', - print >> sys.stderr, 'might be caused by handling a', - print >> sys.stderr, 'cyrillic document' - print >> sys.stderr, 'without the XeTeX backend' - print >> sys.stderr - return True - except: - pass - return False - diff --git a/lib/contrib/debian/installer.py b/lib/contrib/debian/installer.py deleted file mode 100644 index 98ac272..0000000 --- a/lib/contrib/debian/installer.py +++ /dev/null @@ -1,73 +0,0 @@ -# -# dblatex - Installer extensions for Debian -# -import os -import glob -import shutil - -class DebianInstaller: - """ - Adapt the setup tool installation to match debian specific rules. - The first step is to adpat the paths, the second step to provide the - required links. - - The known limitations: - - The dblatex script assumes the install prefix is standard - - The documentation is not installed - - The latex packages are found only when installed in standard tex dirs - """ - def __init__(self, install_object): - self.install_obj = install_object - - def adapt_paths(self): - # Add debian-specific python modules to install - self.install_obj.distribution.packages += ['dbtexmf.contrib', - 'dbtexmf.contrib.debian'] - self.install_obj.distribution.package_dir['dbtexmf.contrib'] = \ - 'lib/contrib' - - # Which latex dirs to maintain under share - texdirs = glob.glob("latex/*") - tex_share = [] - for _dir in texdirs: - if not(os.path.basename(_dir) in ("contrib", "style", "misc")): - tex_share.append(_dir) - - # Redefine the data install paths - self.install_obj.distribution.data_files = \ - [('share/dblatex/latex', tex_share), - ('share/xml/docbook/stylesheet/dblatex', ['xsl']), - ('share/texmf/tex/latex/dblatex', ['latex/contrib', - 'latex/style', - 'latex/misc']), - ('share/man/man1', ['docs/manpage/dblatex.1.gz'])] - - def finalize(self): - texdir = os.path.join(self.install_obj.install_data, - "share/texmf/tex/latex/dblatex") - - # Add the links to the debian standard paths - contrib_lnk = os.path.join(self.install_obj.install_data, - 'share/dblatex/latex/contrib') - xsl_lnk = os.path.join(self.install_obj.install_data, - 'share/dblatex/xsl') - - if not(os.path.exists(contrib_lnk)): - os.symlink("../../texmf/tex/latex/dblatex/contrib", contrib_lnk) - - if not(os.path.exists(xsl_lnk)): - os.symlink("../xml/docbook/stylesheet/dblatex/xsl", xsl_lnk) - - # Remove useless latex packages or license files - for _file in ("passivetex/LICENSE", - "attachfile.sty", - "bibtopic.sty", - "enumitem.sty", - "lastpage.sty", - "ragged2e.sty"): - os.remove("%s" % (os.path.join(texdir, "misc", _file))) - - # Overwrite the dblatex script with the debian specific one - shutil.copy("lib/contrib/debian/dblatex", - self.install_obj.install_scripts) - diff --git a/lib/contrib/which/LICENSE.txt b/lib/contrib/which/LICENSE.txt deleted file mode 100644 index de85cd5..0000000 --- a/lib/contrib/which/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -Copyright (c) 2002-2005 ActiveState Corp. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/lib/contrib/which/README.txt b/lib/contrib/which/README.txt deleted file mode 100644 index 6ece7f6..0000000 --- a/lib/contrib/which/README.txt +++ /dev/null @@ -1,229 +0,0 @@ -which.py -- a portable GNU which replacement -============================================ - -Download the latest which.py packages from here: - (source) http://trentm.com/downloads/which/1.1.0/which-1.1.0.zip - - -Home : http://trentm.com/projects/which/ -License : MIT (see LICENSE.txt) -Platforms : Windows, Linux, Mac OS X, Unix -Current Version : 1.1 -Dev Status : mature, has been heavily used in a commercial product for - over 2 years -Requirements : Python >= 2.3 (http://www.activestate.com/ActivePython/) - - -What's new? ------------ - -I have moved hosting of `which.py` from my old [Starship -pages](http://starship.python.net/~tmick/) to this site. These starter -docs have been improved a little bit. See the [Change Log](#changelog) -below for more. - -**WARNING**: If you are upgrading your `which.py` and you also use my -[process.py](../process/) module, you must upgrade `process.py` as well -because of the `_version_/__version__` change in v1.1.0. - - -Why which.py? -------------- - -`which.py` is a small GNU-which replacement. It has the following -features: - -- it is portable (Windows, Linux, Mac OS X, Un*x); -- it understands PATHEXT and "App Paths" registration on Windows - (i.e. it will find everything that `start` does from the command shell); -- it can print all matches on the PATH; -- it can note "near misses" on the PATH (e.g. files that match but may - not, say, have execute permissions); and -- it can be used as a Python module. - -I also would be happy to have this be a replacement for the `which.py` in the -Python CVS tree at `dist/src/Tools/scripts/which.py` which is -Unix-specific and not usable as a module; and perhaps for inclusion in -the stdlib. - -Please send any feedback to [Trent Mick](mailto:TrentM@ActiveState.com). - - -Install Notes -------------- - -Download the latest `which.py` source package, unzip it, and run -`python setup.py install`: - - unzip which-1.1.0.zip - cd which-1.1.0 - python setup.py install - -If your install fails then please visit [the Troubleshooting -FAQ](http://trentm.com/faq.html#troubleshooting-python-package-installation). - -`which.py` can be used both as a module and as a script. By default, -`which.py` will be installed into your Python's `site-packages` -directory so it can be used as a module. On *Windows only*, `which.py` -(and the launcher stub `which.exe`) will be installed in the Python -install dir to (hopefully) put `which` on your PATH. - -On Un*x platforms (including Linux and Mac OS X) there is often a -`which` executable already on your PATH. To use this `which` instead of -your system's on those platforms you can manually do one of the -following: - -- Copy `which.py` to `which` somewhere on your PATH ahead of the system - `which`. This can be a symlink, as well: - - ln -s /PATH/TO/site-packages/which.py /usr/local/bin/which - -- Python 2.4 users might want to use Python's new '-m' switch and setup - and alias: - - alias which='python -m which' - - or stub script like this: - - #!/bin/sh - python -m which $@ - - -Getting Started ---------------- - -Currently the best intro to using `which.py` as a module is its module -documentation. Either install `which.py` and run: - - pydoc which - -take a look at `which.py` in your editor or [here](which.py), or read -on. Most commonly you'll use the `which()` method to find an -executable: - - >>> import which - >>> which.which("perl") - '/usr/local/bin/perl' - -Or you might want to know if you have multiple versions on your path: - - >>> which.whichall("perl") - ['/usr/local/bin/perl', '/usr/bin/perl'] - -Use `verbose` to see where your executable is being found. (On Windows -this might not always be so obvious as your PATH environment variable. -There is an "App Paths" area of the registry where the `start` command -will find "registered" executables -- `which.py` mimics this.) - - >>> which.whichall("perl", verbose=True) - [('/usr/local/bin/perl', 'from PATH element 10'), - ('/usr/bin/perl', 'from PATH element 15')] - -You can restrict the searched path: - - >>> which.whichall("perl", path=["/usr/bin"]) - ['/usr/bin/perl'] - -There is a generator interface: - - >>> for perl in which.whichgen("perl"): - ... print "found a perl here:", perl - ... - found a perl here: /usr/local/bin/perl - found a perl here: /usr/bin/perl - -An exception is raised if your executable is not found: - - >>> which.which("fuzzywuzzy") - Traceback (most recent call last): - ... - which.WhichError: Could not find 'fuzzywuzzy' on the path. - >>> - -There are some other options too: - - >>> help(which.which) - ... - -Run `which --help` to see command-line usage: - - $ which --help - Show the full path of commands. - - Usage: - which [...] [...] - - 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 , --path= - An alternative path (list of directories) may - be specified for searching. - -e , --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 was given. - - Near misses include duplicates, non-regular files and (on Un*x) - files without executable access. - - -Change Log ----------- - -### v1.1.0 -- Change version attributes and semantics. Before: had a _version_ - tuple. After: __version__ is a string, __version_info__ is a tuple. - -### v1.0.3 -- Move hosting of which.py to trentm.com. Tweaks to associated bits - (README.txt, etc.) - -### v1.0.2: -- Rename mainline handler function from _main() to main(). I can - conceive of it being called from externally. - -### v1.0.1: -- Add an optimization for Windows to allow the optional - specification of a list of exts to consider when searching the - path. - -### v1.0.0: -- Simpler interface: What was which() is now called whichgen() -- it - is a generator of matches. The simpler which() and whichall() - non-generator interfaces were added. - -### v0.8.1: -- API change: 0.8.0's API change making "verbose" output the default - was a mistake -- it breaks backward compatibility for existing - uses of which in scripts. This makes verbose, once again, optional - but NOT the default. - -### v0.8.0: -- bug fix: "App Paths" lookup had been crippled in 0.7.0. Restore that. -- feature/module API change: Now print out (and return for the module - interface) from where a match was found, e.g. "(from PATH element 3)". - The module interfaces now returns (match, from-where) tuples. -- bug fix: --path argument was broken (-p shortform was fine) - -### v0.7.0: -- bug fix: Handle "App Paths" registered executable that does not - exist. -- feature: Allow an alternate PATH to be specified via 'path' - optional argument to which.which() and via -p|--path command line - option. - -### v0.6.1: -- first public release - diff --git a/lib/contrib/which/TODO.txt b/lib/contrib/which/TODO.txt deleted file mode 100644 index 6df2de7..0000000 --- a/lib/contrib/which/TODO.txt +++ /dev/null @@ -1,113 +0,0 @@ -# High Priority - -- Figure out the script story on the various platforms. On Windows, look into - the launcher thing that effbot has. Unix, don't install the script my - default. They can always do "python -m which ..." with Python >= 2.4. - Suggest an alias that some folks might want to use for that. - - -# Medium Priority - -- define __all__? -- improve test suite -- test with other versions of Python -- get the PATHEXT attached extension to reflect the actual canonical - case of file matches on Windows, currently the extension from PATHEXT - is always uppercase -- What to do with Change 145624 by shanec. It is a bit of a - bastardization. Maybe allow this with a special option to allow the change - in semantics. - - > Change 145624 by shanec@shanec-ocelotl on 2005/05/24 16:51:55 - > - > make which work better on OSX - > - add support for searching /Applications and /Network/Applications - > - add support for .app bundles - > - > Affected files ... - > - > ... //depot/main/Apps/Komodo-devel/src/python-sitelib/which.py#7 edit - > - > Differences ... - > - > ==== //depot/main/Apps/Komodo-devel/src/python-sitelib/which.py#7 (text) ==== - > - > @@ -126,10 +126,11 @@ - > sys.stderr.write("duplicate: %s (%s)\n" % potential) - > return None - > else: - > - if not stat.S_ISREG(os.stat(potential[0]).st_mode): - > + darwinApp = sys.platform == 'darwin' and potential[0][-4:]=='.app' - > + if not darwinApp and 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): - > + elif not darwinApp and not os.access(potential[0], os.X_OK): - > if verbose: - > sys.stderr.write("no executable access: %s (%s)\n"\ - > % potential) - > @@ -166,6 +167,9 @@ - > path = os.environ.get("PATH", "").split(os.pathsep) - > if sys.platform.startswith("win"): - > path.insert(0, os.curdir) # implied by Windows shell - > + if sys.platform == 'darwin': - > + path.insert(0, '/Network/Applications') - > + path.insert(0, '/Applications') - > else: - > usingGivenPath = 1 - > - > @@ -182,6 +186,9 @@ - > exts = ['.COM', '.EXE', '.BAT'] - > elif not isinstance(exts, list): - > raise TypeError("'exts' argument must be a list or None") - > + elif sys.platform == 'darwin': - > + if exts is None: - > + exts = ['.app'] - > else: - > if exts is not None: - > raise WhichError("'exts' argument is not supported on "\ - > @@ -202,7 +209,8 @@ - > for ext in ['']+exts: - > absName = os.path.abspath( - > os.path.normpath(os.path.join(dirName, command+ext))) - > - if os.path.isfile(absName): - > + if os.path.isfile(absName) or (sys.platform == 'darwin' and \ - > + absName[-4:]=='.app' and os.path.isdir(absName)): - > if usingGivenPath: - > fromWhere = "from given path element %d" % i - > elif not sys.platform.startswith("win"): - - Here is a start with slight improvements: - - > Index: which.py - > =================================================================== - > --- which.py (revision 270) - > +++ which.py (working copy) - > @@ -126,9 +126,18 @@ - > sys.stderr.write("duplicate: %s (%s)\n" % potential) - > return None - > else: - > - if not stat.S_ISREG(os.stat(potential[0]).st_mode): - > + st_mode = os.stat(potential[0]).st_mode - > + isMacAppBundle = sys.platform == "darwin" \ - > + and potential[0].endswith(".app") \ - > + and stat.S_ISDIR(st_mode) - > + if not isMacAppBundle and not stat.S_ISREG(st_mode): - > if verbose: - > - sys.stderr.write("not a regular file: %s (%s)\n" % potential) - > + if sys.platform == "darwin": - > + sys.stderr.write("not a regular file or .app bundle: " - > + "%s (%s)\n" % potential) - > + else: - > + 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"\ - - -# Low Priority - -- have a version for pre-generators (i.e. Python 2.1) -- add a "logging" interface - diff --git a/lib/contrib/which/__init__.py b/lib/contrib/which/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/lib/contrib/which/__init__.py +++ /dev/null diff --git a/lib/contrib/which/which.py b/lib/contrib/which/which.py deleted file mode 100644 index 4d28ebd..0000000 --- a/lib/contrib/which/which.py +++ /dev/null @@ -1,335 +0,0 @@ -#!/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 - (, ) -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: - -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 , --path= - An alternative path (list of directories) may - be specified for searching. - -e , --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 was given. - - Near misses include duplicates, non-regular files and (on Un*x) - files without executable access. -""" - -__revision__ = "$Id$" -__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 (, ). - """ - 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.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) ) - -