diff options
Diffstat (limited to 'lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands')
10 files changed, 995 insertions, 0 deletions
diff --git a/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/__init__.py b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/__init__.py new file mode 100755 index 00000000..792d6005 --- /dev/null +++ b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/__init__.py @@ -0,0 +1 @@ +# diff --git a/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/bundle.py b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/bundle.py new file mode 100755 index 00000000..fb0f7570 --- /dev/null +++ b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/bundle.py @@ -0,0 +1,33 @@ +from pip.locations import build_prefix, src_prefix +from pip.util import display_path, backup_dir +from pip.log import logger +from pip.exceptions import InstallationError +from pip.commands.install import InstallCommand + + +class BundleCommand(InstallCommand): + name = 'bundle' + usage = '%prog [OPTIONS] BUNDLE_NAME.pybundle PACKAGE_NAMES...' + summary = 'Create pybundles (archives containing multiple packages)' + bundle = True + + def __init__(self): + super(BundleCommand, self).__init__() + + def run(self, options, args): + if not args: + raise InstallationError('You must give a bundle filename') + if not options.build_dir: + options.build_dir = backup_dir(build_prefix, '-bundle') + if not options.src_dir: + options.src_dir = backup_dir(src_prefix, '-bundle') + # We have to get everything when creating a bundle: + options.ignore_installed = True + logger.notify('Putting temporary build files in %s and source/develop files in %s' + % (display_path(options.build_dir), display_path(options.src_dir))) + self.bundle_filename = args.pop(0) + requirement_set = super(BundleCommand, self).run(options, args) + return requirement_set + + +BundleCommand() diff --git a/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/completion.py b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/completion.py new file mode 100755 index 00000000..d003b9ae --- /dev/null +++ b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/completion.py @@ -0,0 +1,60 @@ +import sys +from pip.basecommand import Command + +BASE_COMPLETION = """ +# pip %(shell)s completion start%(script)s# pip %(shell)s completion end +""" + +COMPLETION_SCRIPTS = { + 'bash': """ +_pip_completion() +{ + COMPREPLY=( $( COMP_WORDS="${COMP_WORDS[*]}" \\ + COMP_CWORD=$COMP_CWORD \\ + PIP_AUTO_COMPLETE=1 $1 ) ) +} +complete -o default -F _pip_completion pip +""", 'zsh': """ +function _pip_completion { + local words cword + read -Ac words + read -cn cword + reply=( $( COMP_WORDS="$words[*]" \\ + COMP_CWORD=$(( cword-1 )) \\ + PIP_AUTO_COMPLETE=1 $words[1] ) ) +} +compctl -K _pip_completion pip +"""} + + +class CompletionCommand(Command): + name = 'completion' + summary = 'A helper command to be used for command completion' + hidden = True + + def __init__(self): + super(CompletionCommand, self).__init__() + self.parser.add_option( + '--bash', '-b', + action='store_const', + const='bash', + dest='shell', + help='Emit completion code for bash') + self.parser.add_option( + '--zsh', '-z', + action='store_const', + const='zsh', + dest='shell', + help='Emit completion code for zsh') + + def run(self, options, args): + """Prints the completion code of the given shell""" + shells = COMPLETION_SCRIPTS.keys() + shell_options = ['--'+shell for shell in sorted(shells)] + if options.shell in shells: + script = COMPLETION_SCRIPTS.get(options.shell, '') + print BASE_COMPLETION % {'script': script, 'shell': options.shell} + else: + sys.stderr.write('ERROR: You must pass %s\n' % ' or '.join(shell_options)) + +CompletionCommand() diff --git a/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/freeze.py b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/freeze.py new file mode 100755 index 00000000..01b5df93 --- /dev/null +++ b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/freeze.py @@ -0,0 +1,109 @@ +import re +import sys +import pkg_resources +import pip +from pip.req import InstallRequirement +from pip.log import logger +from pip.basecommand import Command +from pip.util import get_installed_distributions + + +class FreezeCommand(Command): + name = 'freeze' + usage = '%prog [OPTIONS]' + summary = 'Output all currently installed packages (exact versions) to stdout' + + def __init__(self): + super(FreezeCommand, self).__init__() + self.parser.add_option( + '-r', '--requirement', + dest='requirement', + action='store', + default=None, + metavar='FILENAME', + help='Use the given requirements file as a hint about how to generate the new frozen requirements') + self.parser.add_option( + '-f', '--find-links', + dest='find_links', + action='append', + default=[], + metavar='URL', + help='URL for finding packages, which will be added to the frozen requirements file') + self.parser.add_option( + '-l', '--local', + dest='local', + action='store_true', + default=False, + help='If in a virtualenv, do not report globally-installed packages') + + def setup_logging(self): + logger.move_stdout_to_stderr() + + def run(self, options, args): + requirement = options.requirement + find_links = options.find_links or [] + local_only = options.local + ## FIXME: Obviously this should be settable: + find_tags = False + skip_match = None + + skip_regex = options.skip_requirements_regex + if skip_regex: + skip_match = re.compile(skip_regex) + + dependency_links = [] + + f = sys.stdout + + for dist in pkg_resources.working_set: + if dist.has_metadata('dependency_links.txt'): + dependency_links.extend(dist.get_metadata_lines('dependency_links.txt')) + for link in find_links: + if '#egg=' in link: + dependency_links.append(link) + for link in find_links: + f.write('-f %s\n' % link) + installations = {} + for dist in get_installed_distributions(local_only=local_only): + req = pip.FrozenRequirement.from_dist(dist, dependency_links, find_tags=find_tags) + installations[req.name] = req + if requirement: + req_f = open(requirement) + for line in req_f: + if not line.strip() or line.strip().startswith('#'): + f.write(line) + continue + if skip_match and skip_match.search(line): + f.write(line) + continue + elif line.startswith('-e') or line.startswith('--editable'): + if line.startswith('-e'): + line = line[2:].strip() + else: + line = line[len('--editable'):].strip().lstrip('=') + line_req = InstallRequirement.from_editable(line, default_vcs=options.default_vcs) + elif (line.startswith('-r') or line.startswith('--requirement') + or line.startswith('-Z') or line.startswith('--always-unzip') + or line.startswith('-f') or line.startswith('-i') + or line.startswith('--extra-index-url')): + f.write(line) + continue + else: + line_req = InstallRequirement.from_line(line) + if not line_req.name: + logger.notify("Skipping line because it's not clear what it would install: %s" + % line.strip()) + logger.notify(" (add #egg=PackageName to the URL to avoid this warning)") + continue + if line_req.name not in installations: + logger.warn("Requirement file contains %s, but that package is not installed" + % line.strip()) + continue + f.write(str(installations[line_req.name])) + del installations[line_req.name] + f.write('## The following requirements were added by pip --freeze:\n') + for installation in sorted(installations.values(), key=lambda x: x.name): + f.write(str(installation)) + + +FreezeCommand() diff --git a/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/help.py b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/help.py new file mode 100755 index 00000000..b0b36611 --- /dev/null +++ b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/help.py @@ -0,0 +1,32 @@ +from pip.basecommand import Command, command_dict, load_all_commands +from pip.exceptions import InstallationError +from pip.baseparser import parser + + +class HelpCommand(Command): + name = 'help' + usage = '%prog' + summary = 'Show available commands' + + def run(self, options, args): + load_all_commands() + if args: + ## FIXME: handle errors better here + command = args[0] + if command not in command_dict: + raise InstallationError('No command with the name: %s' % command) + command = command_dict[command] + command.parser.print_help() + return + parser.print_help() + print + print 'Commands available:' + commands = list(set(command_dict.values())) + commands.sort(key=lambda x: x.name) + for command in commands: + if command.hidden: + continue + print ' %s: %s' % (command.name, command.summary) + + +HelpCommand() diff --git a/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/install.py b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/install.py new file mode 100755 index 00000000..861c332b --- /dev/null +++ b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/install.py @@ -0,0 +1,247 @@ +import os, sys +from pip.req import InstallRequirement, RequirementSet +from pip.req import parse_requirements +from pip.log import logger +from pip.locations import build_prefix, src_prefix +from pip.basecommand import Command +from pip.index import PackageFinder +from pip.exceptions import InstallationError + + +class InstallCommand(Command): + name = 'install' + usage = '%prog [OPTIONS] PACKAGE_NAMES...' + summary = 'Install packages' + bundle = False + + def __init__(self): + super(InstallCommand, self).__init__() + self.parser.add_option( + '-e', '--editable', + dest='editables', + action='append', + default=[], + metavar='VCS+REPOS_URL[@REV]#egg=PACKAGE', + help='Install a package directly from a checkout. Source will be checked ' + 'out into src/PACKAGE (lower-case) and installed in-place (using ' + 'setup.py develop). You can run this on an existing directory/checkout (like ' + 'pip install -e src/mycheckout). This option may be provided multiple times. ' + 'Possible values for VCS are: svn, git, hg and bzr.') + self.parser.add_option( + '-r', '--requirement', + dest='requirements', + action='append', + default=[], + metavar='FILENAME', + help='Install all the packages listed in the given requirements file. ' + 'This option can be used multiple times.') + self.parser.add_option( + '-f', '--find-links', + dest='find_links', + action='append', + default=[], + metavar='URL', + help='URL to look for packages at') + self.parser.add_option( + '-i', '--index-url', '--pypi-url', + dest='index_url', + metavar='URL', + default='http://pypi.python.org/simple/', + help='Base URL of Python Package Index (default %default)') + self.parser.add_option( + '--extra-index-url', + dest='extra_index_urls', + metavar='URL', + action='append', + default=[], + help='Extra URLs of package indexes to use in addition to --index-url') + self.parser.add_option( + '--no-index', + dest='no_index', + action='store_true', + default=False, + help='Ignore package index (only looking at --find-links URLs instead)') + self.parser.add_option( + '-M', '--use-mirrors', + dest='use_mirrors', + action='store_true', + default=False, + help='Use the PyPI mirrors as a fallback in case the main index is down.') + self.parser.add_option( + '--mirrors', + dest='mirrors', + metavar='URL', + action='append', + default=[], + help='Specific mirror URLs to query when --use-mirrors is used') + + self.parser.add_option( + '-b', '--build', '--build-dir', '--build-directory', + dest='build_dir', + metavar='DIR', + default=None, + help='Unpack packages into DIR (default %s) and build from there' % build_prefix) + self.parser.add_option( + '-d', '--download', '--download-dir', '--download-directory', + dest='download_dir', + metavar='DIR', + default=None, + help='Download packages into DIR instead of installing them') + self.parser.add_option( + '--download-cache', + dest='download_cache', + metavar='DIR', + default=None, + help='Cache downloaded packages in DIR') + self.parser.add_option( + '--src', '--source', '--source-dir', '--source-directory', + dest='src_dir', + metavar='DIR', + default=None, + help='Check out --editable packages into DIR (default %s)' % src_prefix) + + self.parser.add_option( + '-U', '--upgrade', + dest='upgrade', + action='store_true', + help='Upgrade all packages to the newest available version') + self.parser.add_option( + '-I', '--ignore-installed', + dest='ignore_installed', + action='store_true', + help='Ignore the installed packages (reinstalling instead)') + self.parser.add_option( + '--no-deps', '--no-dependencies', + dest='ignore_dependencies', + action='store_true', + default=False, + help='Ignore package dependencies') + self.parser.add_option( + '--no-install', + dest='no_install', + action='store_true', + help="Download and unpack all packages, but don't actually install them") + self.parser.add_option( + '--no-download', + dest='no_download', + action="store_true", + help="Don't download any packages, just install the ones already downloaded " + "(completes an install run with --no-install)") + + self.parser.add_option( + '--install-option', + dest='install_options', + action='append', + help="Extra arguments to be supplied to the setup.py install " + "command (use like --install-option=\"--install-scripts=/usr/local/bin\"). " + "Use multiple --install-option options to pass multiple options to setup.py install. " + "If you are using an option with a directory path, be sure to use absolute path.") + + self.parser.add_option( + '--global-option', + dest='global_options', + action='append', + help="Extra global options to be supplied to the setup.py" + "call before the install command") + + self.parser.add_option( + '--user', + dest='use_user_site', + action='store_true', + help='Install to user-site') + + def _build_package_finder(self, options, index_urls): + """ + Create a package finder appropriate to this install command. + This method is meant to be overridden by subclasses, not + called directly. + """ + return PackageFinder(find_links=options.find_links, + index_urls=index_urls, + use_mirrors=options.use_mirrors, + mirrors=options.mirrors) + + def run(self, options, args): + if not options.build_dir: + options.build_dir = build_prefix + if not options.src_dir: + options.src_dir = src_prefix + if options.download_dir: + options.no_install = True + options.ignore_installed = True + options.build_dir = os.path.abspath(options.build_dir) + options.src_dir = os.path.abspath(options.src_dir) + install_options = options.install_options or [] + if options.use_user_site: + install_options.append('--user') + global_options = options.global_options or [] + index_urls = [options.index_url] + options.extra_index_urls + if options.no_index: + logger.notify('Ignoring indexes: %s' % ','.join(index_urls)) + index_urls = [] + + finder = self._build_package_finder(options, index_urls) + + requirement_set = RequirementSet( + build_dir=options.build_dir, + src_dir=options.src_dir, + download_dir=options.download_dir, + download_cache=options.download_cache, + upgrade=options.upgrade, + ignore_installed=options.ignore_installed, + ignore_dependencies=options.ignore_dependencies) + for name in args: + requirement_set.add_requirement( + InstallRequirement.from_line(name, None)) + for name in options.editables: + requirement_set.add_requirement( + InstallRequirement.from_editable(name, default_vcs=options.default_vcs)) + for filename in options.requirements: + for req in parse_requirements(filename, finder=finder, options=options): + requirement_set.add_requirement(req) + + if not requirement_set.has_requirements: + if options.find_links: + raise InstallationError('You must give at least one ' + 'requirement to %s (maybe you meant "pip install %s"?)' + % (self.name, " ".join(options.find_links))) + raise InstallationError('You must give at least one requirement ' + 'to %(name)s (see "pip help %(name)s")' % dict(name=self.name)) + + if (options.use_user_site and + sys.version_info < (2, 6)): + raise InstallationError('--user is only supported in Python version 2.6 and newer') + + import setuptools + if (options.use_user_site and + requirement_set.has_editables and + not getattr(setuptools, '_distribute', False)): + + raise InstallationError('--user --editable not supported with setuptools, use distribute') + + if not options.no_download: + requirement_set.prepare_files(finder, force_root_egg_info=self.bundle, bundle=self.bundle) + else: + requirement_set.locate_files() + + if not options.no_install and not self.bundle: + requirement_set.install(install_options, global_options) + installed = ' '.join([req.name for req in + requirement_set.successfully_installed]) + if installed: + logger.notify('Successfully installed %s' % installed) + elif not self.bundle: + downloaded = ' '.join([req.name for req in + requirement_set.successfully_downloaded]) + if downloaded: + logger.notify('Successfully downloaded %s' % downloaded) + elif self.bundle: + requirement_set.create_bundle(self.bundle_filename) + logger.notify('Created bundle in %s' % self.bundle_filename) + # Clean up + if not options.no_install: + requirement_set.cleanup_files(bundle=self.bundle) + return requirement_set + + +InstallCommand() diff --git a/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/search.py b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/search.py new file mode 100755 index 00000000..73da58ac --- /dev/null +++ b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/search.py @@ -0,0 +1,116 @@ +import sys +import xmlrpclib +import textwrap +import pkg_resources +import pip.download +from pip.basecommand import Command +from pip.util import get_terminal_size +from pip.log import logger +from distutils.version import StrictVersion, LooseVersion + + +class SearchCommand(Command): + name = 'search' + usage = '%prog QUERY' + summary = 'Search PyPI' + + def __init__(self): + super(SearchCommand, self).__init__() + self.parser.add_option( + '--index', + dest='index', + metavar='URL', + default='http://pypi.python.org/pypi', + help='Base URL of Python Package Index (default %default)') + + def run(self, options, args): + if not args: + logger.warn('ERROR: Missing required argument (search query).') + return + query = ' '.join(args) + index_url = options.index + + pypi_hits = self.search(query, index_url) + hits = transform_hits(pypi_hits) + + terminal_width = None + if sys.stdout.isatty(): + terminal_width = get_terminal_size()[0] + + print_results(hits, terminal_width=terminal_width) + + def search(self, query, index_url): + pypi = xmlrpclib.ServerProxy(index_url, pip.download.xmlrpclib_transport) + hits = pypi.search({'name': query, 'summary': query}, 'or') + return hits + + +def transform_hits(hits): + """ + The list from pypi is really a list of versions. We want a list of + packages with the list of versions stored inline. This converts the + list from pypi into one we can use. + """ + packages = {} + for hit in hits: + name = hit['name'] + summary = hit['summary'] + version = hit['version'] + score = hit['_pypi_ordering'] + + if name not in packages.keys(): + packages[name] = {'name': name, 'summary': summary, 'versions': [version], 'score': score} + else: + packages[name]['versions'].append(version) + + # if this is the highest version, replace summary and score + if version == highest_version(packages[name]['versions']): + packages[name]['summary'] = summary + packages[name]['score'] = score + + # each record has a unique name now, so we will convert the dict into a list sorted by score + package_list = sorted(packages.values(), lambda x, y: cmp(y['score'], x['score'])) + return package_list + + +def print_results(hits, name_column_width=25, terminal_width=None): + installed_packages = [p.project_name for p in pkg_resources.working_set] + for hit in hits: + name = hit['name'] + summary = hit['summary'] or '' + if terminal_width is not None: + # wrap and indent summary to fit terminal + summary = textwrap.wrap(summary, terminal_width - name_column_width - 5) + summary = ('\n' + ' ' * (name_column_width + 3)).join(summary) + line = '%s - %s' % (name.ljust(name_column_width), summary) + try: + logger.notify(line) + if name in installed_packages: + dist = pkg_resources.get_distribution(name) + logger.indent += 2 + try: + latest = highest_version(hit['versions']) + if dist.version == latest: + logger.notify('INSTALLED: %s (latest)' % dist.version) + else: + logger.notify('INSTALLED: %s' % dist.version) + logger.notify('LATEST: %s' % latest) + finally: + logger.indent -= 2 + except UnicodeEncodeError: + pass + + +def compare_versions(version1, version2): + try: + return cmp(StrictVersion(version1), StrictVersion(version2)) + # in case of abnormal version number, fall back to LooseVersion + except ValueError: + return cmp(LooseVersion(version1), LooseVersion(version2)) + + +def highest_version(versions): + return reduce((lambda v1, v2: compare_versions(v1, v2) == 1 and v1 or v2), versions) + + +SearchCommand() diff --git a/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/uninstall.py b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/uninstall.py new file mode 100755 index 00000000..7effd844 --- /dev/null +++ b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/uninstall.py @@ -0,0 +1,42 @@ +from pip.req import InstallRequirement, RequirementSet, parse_requirements +from pip.basecommand import Command +from pip.exceptions import InstallationError + +class UninstallCommand(Command): + name = 'uninstall' + usage = '%prog [OPTIONS] PACKAGE_NAMES ...' + summary = 'Uninstall packages' + + def __init__(self): + super(UninstallCommand, self).__init__() + self.parser.add_option( + '-r', '--requirement', + dest='requirements', + action='append', + default=[], + metavar='FILENAME', + help='Uninstall all the packages listed in the given requirements file. ' + 'This option can be used multiple times.') + self.parser.add_option( + '-y', '--yes', + dest='yes', + action='store_true', + help="Don't ask for confirmation of uninstall deletions.") + + def run(self, options, args): + requirement_set = RequirementSet( + build_dir=None, + src_dir=None, + download_dir=None) + for name in args: + requirement_set.add_requirement( + InstallRequirement.from_line(name)) + for filename in options.requirements: + for req in parse_requirements(filename, options=options): + requirement_set.add_requirement(req) + if not requirement_set.has_requirements: + raise InstallationError('You must give at least one requirement ' + 'to %(name)s (see "pip help %(name)s")' % dict(name=self.name)) + requirement_set.uninstall(auto_confirm=options.yes) + +UninstallCommand() diff --git a/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/unzip.py b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/unzip.py new file mode 100755 index 00000000..f83e1820 --- /dev/null +++ b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/unzip.py @@ -0,0 +1,9 @@ +from pip.commands.zip import ZipCommand + + +class UnzipCommand(ZipCommand): + name = 'unzip' + summary = 'Unzip individual packages' + + +UnzipCommand() diff --git a/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/zip.py b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/zip.py new file mode 100755 index 00000000..346fc051 --- /dev/null +++ b/lib/python2.7/site-packages/pip-0.8.1-py2.7.egg/pip/commands/zip.py @@ -0,0 +1,346 @@ +import sys +import re +import fnmatch +import os +import shutil +import zipfile +from pip.util import display_path, backup_dir +from pip.log import logger +from pip.exceptions import InstallationError +from pip.basecommand import Command + + +class ZipCommand(Command): + name = 'zip' + usage = '%prog [OPTIONS] PACKAGE_NAMES...' + summary = 'Zip individual packages' + + def __init__(self): + super(ZipCommand, self).__init__() + if self.name == 'zip': + self.parser.add_option( + '--unzip', + action='store_true', + dest='unzip', + help='Unzip (rather than zip) a package') + else: + self.parser.add_option( + '--zip', + action='store_false', + dest='unzip', + default=True, + help='Zip (rather than unzip) a package') + self.parser.add_option( + '--no-pyc', + action='store_true', + dest='no_pyc', + help='Do not include .pyc files in zip files (useful on Google App Engine)') + self.parser.add_option( + '-l', '--list', + action='store_true', + dest='list', + help='List the packages available, and their zip status') + self.parser.add_option( + '--sort-files', + action='store_true', + dest='sort_files', + help='With --list, sort packages according to how many files they contain') + self.parser.add_option( + '--path', + action='append', + dest='paths', + help='Restrict operations to the given paths (may include wildcards)') + self.parser.add_option( + '-n', '--simulate', + action='store_true', + help='Do not actually perform the zip/unzip operation') + + def paths(self): + """All the entries of sys.path, possibly restricted by --path""" + if not self.select_paths: + return sys.path + result = [] + match_any = set() + for path in sys.path: + path = os.path.normcase(os.path.abspath(path)) + for match in self.select_paths: + match = os.path.normcase(os.path.abspath(match)) + if '*' in match: + if re.search(fnmatch.translate(match+'*'), path): + result.append(path) + match_any.add(match) + break + else: + if path.startswith(match): + result.append(path) + match_any.add(match) + break + else: + logger.debug("Skipping path %s because it doesn't match %s" + % (path, ', '.join(self.select_paths))) + for match in self.select_paths: + if match not in match_any and '*' not in match: + result.append(match) + logger.debug("Adding path %s because it doesn't match anything already on sys.path" + % match) + return result + + def run(self, options, args): + self.select_paths = options.paths + self.simulate = options.simulate + if options.list: + return self.list(options, args) + if not args: + raise InstallationError( + 'You must give at least one package to zip or unzip') + packages = [] + for arg in args: + module_name, filename = self.find_package(arg) + if options.unzip and os.path.isdir(filename): + raise InstallationError( + 'The module %s (in %s) is not a zip file; cannot be unzipped' + % (module_name, filename)) + elif not options.unzip and not os.path.isdir(filename): + raise InstallationError( + 'The module %s (in %s) is not a directory; cannot be zipped' + % (module_name, filename)) + packages.append((module_name, filename)) + last_status = None + for module_name, filename in packages: + if options.unzip: + last_status = self.unzip_package(module_name, filename) + else: + last_status = self.zip_package(module_name, filename, options.no_pyc) + return last_status + + def unzip_package(self, module_name, filename): + zip_filename = os.path.dirname(filename) + if not os.path.isfile(zip_filename) and zipfile.is_zipfile(zip_filename): + raise InstallationError( + 'Module %s (in %s) isn\'t located in a zip file in %s' + % (module_name, filename, zip_filename)) + package_path = os.path.dirname(zip_filename) + if not package_path in self.paths(): + logger.warn( + 'Unpacking %s into %s, but %s is not on sys.path' + % (display_path(zip_filename), display_path(package_path), + display_path(package_path))) + logger.notify('Unzipping %s (in %s)' % (module_name, display_path(zip_filename))) + if self.simulate: + logger.notify('Skipping remaining operations because of --simulate') + return + logger.indent += 2 + try: + ## FIXME: this should be undoable: + zip = zipfile.ZipFile(zip_filename) + to_save = [] + for name in zip.namelist(): + if name.startswith(module_name + os.path.sep): + content = zip.read(name) + dest = os.path.join(package_path, name) + if not os.path.exists(os.path.dirname(dest)): + os.makedirs(os.path.dirname(dest)) + if not content and dest.endswith(os.path.sep): + if not os.path.exists(dest): + os.makedirs(dest) + else: + f = open(dest, 'wb') + f.write(content) + f.close() + else: + to_save.append((name, zip.read(name))) + zip.close() + if not to_save: + logger.info('Removing now-empty zip file %s' % display_path(zip_filename)) + os.unlink(zip_filename) + self.remove_filename_from_pth(zip_filename) + else: + logger.info('Removing entries in %s/ from zip file %s' % (module_name, display_path(zip_filename))) + zip = zipfile.ZipFile(zip_filename, 'w') + for name, content in to_save: + zip.writestr(name, content) + zip.close() + finally: + logger.indent -= 2 + + def zip_package(self, module_name, filename, no_pyc): + orig_filename = filename + logger.notify('Zip %s (in %s)' % (module_name, display_path(filename))) + logger.indent += 2 + if filename.endswith('.egg'): + dest_filename = filename + else: + dest_filename = filename + '.zip' + try: + ## FIXME: I think this needs to be undoable: + if filename == dest_filename: + filename = backup_dir(orig_filename) + logger.notify('Moving %s aside to %s' % (orig_filename, filename)) + if not self.simulate: + shutil.move(orig_filename, filename) + try: + logger.info('Creating zip file in %s' % display_path(dest_filename)) + if not self.simulate: + zip = zipfile.ZipFile(dest_filename, 'w') + zip.writestr(module_name + '/', '') + for dirpath, dirnames, filenames in os.walk(filename): + if no_pyc: + filenames = [f for f in filenames + if not f.lower().endswith('.pyc')] + for fns, is_dir in [(dirnames, True), (filenames, False)]: + for fn in fns: + full = os.path.join(dirpath, fn) + dest = os.path.join(module_name, dirpath[len(filename):].lstrip(os.path.sep), fn) + if is_dir: + zip.writestr(dest+'/', '') + else: + zip.write(full, dest) + zip.close() + logger.info('Removing old directory %s' % display_path(filename)) + if not self.simulate: + shutil.rmtree(filename) + except: + ## FIXME: need to do an undo here + raise + ## FIXME: should also be undone: + self.add_filename_to_pth(dest_filename) + finally: + logger.indent -= 2 + + def remove_filename_from_pth(self, filename): + for pth in self.pth_files(): + f = open(pth, 'r') + lines = f.readlines() + f.close() + new_lines = [ + l for l in lines if l.strip() != filename] + if lines != new_lines: + logger.info('Removing reference to %s from .pth file %s' + % (display_path(filename), display_path(pth))) + if not filter(None, new_lines): + logger.info('%s file would be empty: deleting' % display_path(pth)) + if not self.simulate: + os.unlink(pth) + else: + if not self.simulate: + f = open(pth, 'wb') + f.writelines(new_lines) + f.close() + return + logger.warn('Cannot find a reference to %s in any .pth file' % display_path(filename)) + + def add_filename_to_pth(self, filename): + path = os.path.dirname(filename) + dest = os.path.join(path, filename + '.pth') + if path not in self.paths(): + logger.warn('Adding .pth file %s, but it is not on sys.path' % display_path(dest)) + if not self.simulate: + if os.path.exists(dest): + f = open(dest) + lines = f.readlines() + f.close() + if lines and not lines[-1].endswith('\n'): + lines[-1] += '\n' + lines.append(filename+'\n') + else: + lines = [filename + '\n'] + f = open(dest, 'wb') + f.writelines(lines) + f.close() + + def pth_files(self): + for path in self.paths(): + if not os.path.exists(path) or not os.path.isdir(path): + continue + for filename in os.listdir(path): + if filename.endswith('.pth'): + yield os.path.join(path, filename) + + def find_package(self, package): + for path in self.paths(): + full = os.path.join(path, package) + if os.path.exists(full): + return package, full + if not os.path.isdir(path) and zipfile.is_zipfile(path): + zip = zipfile.ZipFile(path, 'r') + try: + zip.read(os.path.join(package, '__init__.py')) + except KeyError: + pass + else: + zip.close() + return package, full + zip.close() + ## FIXME: need special error for package.py case: + raise InstallationError( + 'No package with the name %s found' % package) + + def list(self, options, args): + if args: + raise InstallationError( + 'You cannot give an argument with --list') + for path in sorted(self.paths()): + if not os.path.exists(path): + continue + basename = os.path.basename(path.rstrip(os.path.sep)) + if os.path.isfile(path) and zipfile.is_zipfile(path): + if os.path.dirname(path) not in self.paths(): + logger.notify('Zipped egg: %s' % display_path(path)) + continue + if (basename != 'site-packages' and basename != 'dist-packages' + and not path.replace('\\', '/').endswith('lib/python')): + continue + logger.notify('In %s:' % display_path(path)) + logger.indent += 2 + zipped = [] + unzipped = [] + try: + for filename in sorted(os.listdir(path)): + ext = os.path.splitext(filename)[1].lower() + if ext in ('.pth', '.egg-info', '.egg-link'): + continue + if ext == '.py': + logger.info('Not displaying %s: not a package' % display_path(filename)) + continue + full = os.path.join(path, filename) + if os.path.isdir(full): + unzipped.append((filename, self.count_package(full))) + elif zipfile.is_zipfile(full): + zipped.append(filename) + else: + logger.info('Unknown file: %s' % display_path(filename)) + if zipped: + logger.notify('Zipped packages:') + logger.indent += 2 + try: + for filename in zipped: + logger.notify(filename) + finally: + logger.indent -= 2 + else: + logger.notify('No zipped packages.') + if unzipped: + if options.sort_files: + unzipped.sort(key=lambda x: -x[1]) + logger.notify('Unzipped packages:') + logger.indent += 2 + try: + for filename, count in unzipped: + logger.notify('%s (%i files)' % (filename, count)) + finally: + logger.indent -= 2 + else: + logger.notify('No unzipped packages.') + finally: + logger.indent -= 2 + + def count_package(self, path): + total = 0 + for dirpath, dirnames, filenames in os.walk(path): + filenames = [f for f in filenames + if not f.lower().endswith('.pyc')] + total += len(filenames) + return total + + +ZipCommand() |