1#!/usr/bin/env python2
2from __future__ import print_function
3
4import os
5import os.path
6import pkgutil
7import shutil
8import sys
9import tempfile
10
11
12__all__ = ["version", "bootstrap"]
13
14
15_SETUPTOOLS_VERSION = "28.8.0"
16
17_PIP_VERSION = "9.0.1"
18
19_PROJECTS = [
20    ("setuptools", _SETUPTOOLS_VERSION),
21    ("pip", _PIP_VERSION),
22]
23
24
25def _run_pip(args, additional_paths=None):
26    # Add our bundled software to the sys.path so we can import it
27    if additional_paths is not None:
28        sys.path = additional_paths + sys.path
29
30    # Install the bundled software
31    import pip
32    pip.main(args)
33
34
35def version():
36    """
37    Returns a string specifying the bundled version of pip.
38    """
39    return _PIP_VERSION
40
41
42def _disable_pip_configuration_settings():
43    # We deliberately ignore all pip environment variables
44    # when invoking pip
45    # See http://bugs.python.org/issue19734 for details
46    keys_to_remove = [k for k in os.environ if k.startswith("PIP_")]
47    for k in keys_to_remove:
48        del os.environ[k]
49    # We also ignore the settings in the default pip configuration file
50    # See http://bugs.python.org/issue20053 for details
51    os.environ['PIP_CONFIG_FILE'] = os.devnull
52
53
54def bootstrap(root=None, upgrade=False, user=False,
55              altinstall=False, default_pip=True,
56              verbosity=0):
57    """
58    Bootstrap pip into the current Python installation (or the given root
59    directory).
60
61    Note that calling this function will alter both sys.path and os.environ.
62    """
63    if altinstall and default_pip:
64        raise ValueError("Cannot use altinstall and default_pip together")
65
66    _disable_pip_configuration_settings()
67
68    # By default, installing pip and setuptools installs all of the
69    # following scripts (X.Y == running Python version):
70    #
71    #   pip, pipX, pipX.Y, easy_install, easy_install-X.Y
72    #
73    # pip 1.5+ allows ensurepip to request that some of those be left out
74    if altinstall:
75        # omit pip, pipX and easy_install
76        os.environ["ENSUREPIP_OPTIONS"] = "altinstall"
77    elif not default_pip:
78        # omit pip and easy_install
79        os.environ["ENSUREPIP_OPTIONS"] = "install"
80
81    tmpdir = tempfile.mkdtemp()
82    try:
83        # Put our bundled wheels into a temporary directory and construct the
84        # additional paths that need added to sys.path
85        additional_paths = []
86        for project, version in _PROJECTS:
87            wheel_name = "{}-{}-py2.py3-none-any.whl".format(project, version)
88            whl = pkgutil.get_data(
89                "ensurepip",
90                "_bundled/{}".format(wheel_name),
91            )
92            with open(os.path.join(tmpdir, wheel_name), "wb") as fp:
93                fp.write(whl)
94
95            additional_paths.append(os.path.join(tmpdir, wheel_name))
96
97        # Construct the arguments to be passed to the pip command
98        args = ["install", "--no-index", "--find-links", tmpdir]
99        if root:
100            args += ["--root", root]
101        if upgrade:
102            args += ["--upgrade"]
103        if user:
104            args += ["--user"]
105        if verbosity:
106            args += ["-" + "v" * verbosity]
107
108        _run_pip(args + [p[0] for p in _PROJECTS], additional_paths)
109    finally:
110        shutil.rmtree(tmpdir, ignore_errors=True)
111
112
113def _uninstall_helper(verbosity=0):
114    """Helper to support a clean default uninstall process on Windows
115
116    Note that calling this function may alter os.environ.
117    """
118    # Nothing to do if pip was never installed, or has been removed
119    try:
120        import pip
121    except ImportError:
122        return
123
124    # If the pip version doesn't match the bundled one, leave it alone
125    if pip.__version__ != _PIP_VERSION:
126        msg = ("ensurepip will only uninstall a matching version "
127               "({!r} installed, {!r} bundled)")
128        print(msg.format(pip.__version__, _PIP_VERSION), file=sys.stderr)
129        return
130
131    _disable_pip_configuration_settings()
132
133    # Construct the arguments to be passed to the pip command
134    args = ["uninstall", "-y", "--disable-pip-version-check"]
135    if verbosity:
136        args += ["-" + "v" * verbosity]
137
138    _run_pip(args + [p[0] for p in reversed(_PROJECTS)])
139
140
141def _main(argv=None):
142    import argparse
143    parser = argparse.ArgumentParser(prog="python -m ensurepip")
144    parser.add_argument(
145        "--version",
146        action="version",
147        version="pip {}".format(version()),
148        help="Show the version of pip that is bundled with this Python.",
149    )
150    parser.add_argument(
151        "-v", "--verbose",
152        action="count",
153        default=0,
154        dest="verbosity",
155        help=("Give more output. Option is additive, and can be used up to 3 "
156              "times."),
157    )
158    parser.add_argument(
159        "-U", "--upgrade",
160        action="store_true",
161        default=False,
162        help="Upgrade pip and dependencies, even if already installed.",
163    )
164    parser.add_argument(
165        "--user",
166        action="store_true",
167        default=False,
168        help="Install using the user scheme.",
169    )
170    parser.add_argument(
171        "--root",
172        default=None,
173        help="Install everything relative to this alternate root directory.",
174    )
175    parser.add_argument(
176        "--altinstall",
177        action="store_true",
178        default=False,
179        help=("Make an alternate install, installing only the X.Y versioned"
180              "scripts (Default: pipX, pipX.Y, easy_install-X.Y)"),
181    )
182    parser.add_argument(
183        "--default-pip",
184        action="store_true",
185        default=True,
186        dest="default_pip",
187        help=argparse.SUPPRESS,
188    )
189    parser.add_argument(
190        "--no-default-pip",
191        action="store_false",
192        dest="default_pip",
193        help=("Make a non default install, installing only the X and X.Y "
194              "versioned scripts."),
195    )
196
197    args = parser.parse_args(argv)
198
199    bootstrap(
200        root=args.root,
201        upgrade=args.upgrade,
202        user=args.user,
203        verbosity=args.verbosity,
204        altinstall=args.altinstall,
205        default_pip=args.default_pip,
206    )
207