1from __future__ import absolute_import
2
3import sys
4
5from pip._internal.cache import WheelCache
6from pip._internal.cli import cmdoptions
7from pip._internal.cli.base_command import Command
8from pip._internal.cli.status_codes import SUCCESS
9from pip._internal.models.format_control import FormatControl
10from pip._internal.operations.freeze import freeze
11from pip._internal.utils.compat import stdlib_pkgs
12from pip._internal.utils.deprecation import deprecated
13from pip._internal.utils.typing import MYPY_CHECK_RUNNING
14
15DEV_PKGS = {'pip', 'setuptools', 'distribute', 'wheel'}
16
17if MYPY_CHECK_RUNNING:
18    from optparse import Values
19    from typing import List
20
21
22class FreezeCommand(Command):
23    """
24    Output installed packages in requirements format.
25
26    packages are listed in a case-insensitive sorted order.
27    """
28
29    usage = """
30      %prog [options]"""
31    log_streams = ("ext://sys.stderr", "ext://sys.stderr")
32
33    def add_options(self):
34        # type: () -> None
35        self.cmd_opts.add_option(
36            '-r', '--requirement',
37            dest='requirements',
38            action='append',
39            default=[],
40            metavar='file',
41            help="Use the order in the given requirements file and its "
42                 "comments when generating output. This option can be "
43                 "used multiple times.")
44        self.cmd_opts.add_option(
45            '-f', '--find-links',
46            dest='find_links',
47            action='append',
48            default=[],
49            metavar='URL',
50            help='URL for finding packages, which will be added to the '
51                 'output.')
52        self.cmd_opts.add_option(
53            '-l', '--local',
54            dest='local',
55            action='store_true',
56            default=False,
57            help='If in a virtualenv that has global access, do not output '
58                 'globally-installed packages.')
59        self.cmd_opts.add_option(
60            '--user',
61            dest='user',
62            action='store_true',
63            default=False,
64            help='Only output packages installed in user-site.')
65        self.cmd_opts.add_option(cmdoptions.list_path())
66        self.cmd_opts.add_option(
67            '--all',
68            dest='freeze_all',
69            action='store_true',
70            help='Do not skip these packages in the output:'
71                 ' {}'.format(', '.join(DEV_PKGS)))
72        self.cmd_opts.add_option(
73            '--exclude-editable',
74            dest='exclude_editable',
75            action='store_true',
76            help='Exclude editable package from output.')
77        self.cmd_opts.add_option(cmdoptions.list_exclude())
78
79        self.parser.insert_option_group(0, self.cmd_opts)
80
81    def run(self, options, args):
82        # type: (Values, List[str]) -> int
83        format_control = FormatControl(set(), set())
84        wheel_cache = WheelCache(options.cache_dir, format_control)
85        skip = set(stdlib_pkgs)
86        if not options.freeze_all:
87            skip.update(DEV_PKGS)
88
89        if options.excludes:
90            skip.update(options.excludes)
91
92        cmdoptions.check_list_path_option(options)
93
94        if options.find_links:
95            deprecated(
96                "--find-links option in pip freeze is deprecated.",
97                replacement=None,
98                gone_in="21.2",
99                issue=9069,
100            )
101
102        freeze_kwargs = dict(
103            requirement=options.requirements,
104            find_links=options.find_links,
105            local_only=options.local,
106            user_only=options.user,
107            paths=options.path,
108            isolated=options.isolated_mode,
109            wheel_cache=wheel_cache,
110            skip=skip,
111            exclude_editable=options.exclude_editable,
112        )
113
114        for line in freeze(**freeze_kwargs):
115            sys.stdout.write(line + '\n')
116        return SUCCESS
117