114 lines
4.6 KiB
Python
114 lines
4.6 KiB
Python
import re
|
|
import sys
|
|
import pip
|
|
|
|
from pip.req import InstallRequirement
|
|
from pip.log import logger
|
|
from pip.basecommand import Command
|
|
from pip.util import get_installed_distributions
|
|
from pip._vendor import pkg_resources
|
|
|
|
|
|
class FreezeCommand(Command):
|
|
"""Output installed packages in requirements format."""
|
|
name = 'freeze'
|
|
usage = """
|
|
%prog [options]"""
|
|
summary = 'Output installed packages in requirements format.'
|
|
|
|
def __init__(self, *args, **kw):
|
|
super(FreezeCommand, self).__init__(*args, **kw)
|
|
|
|
self.cmd_opts.add_option(
|
|
'-r', '--requirement',
|
|
dest='requirement',
|
|
action='store',
|
|
default=None,
|
|
metavar='file',
|
|
help="Use the order in the given requirements file and it's comments when generating output.")
|
|
self.cmd_opts.add_option(
|
|
'-f', '--find-links',
|
|
dest='find_links',
|
|
action='append',
|
|
default=[],
|
|
metavar='URL',
|
|
help='URL for finding packages, which will be added to the output.')
|
|
self.cmd_opts.add_option(
|
|
'-l', '--local',
|
|
dest='local',
|
|
action='store_true',
|
|
default=False,
|
|
help='If in a virtualenv that has global access, do not output globally-installed packages.')
|
|
|
|
self.parser.insert_option_group(0, self.cmd_opts)
|
|
|
|
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')
|
|
or line.startswith('--find-links')
|
|
or line.startswith('--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))
|