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