blob: 5ceda516a2db5a6c64c12e087f6e197b5aa2fe1d [file] [log] [blame]
Nick Coghland0cf0632013-11-11 22:11:55 +10001import os
2import os.path
3import pkgutil
4import sys
5import tempfile
6
7# TODO: Remove the --pre flag when a pip 1.5 final copy is available
8
9
10__all__ = ["version", "bootstrap"]
11
12
Donald Stufft8b36dac2013-12-20 19:03:18 -050013_SETUPTOOLS_VERSION = "2.0.1"
Nick Coghland0cf0632013-11-11 22:11:55 +100014
Donald Stufft8b36dac2013-12-20 19:03:18 -050015_PIP_VERSION = "1.5rc2"
Nick Coghland0cf0632013-11-11 22:11:55 +100016
17_PROJECTS = [
18 ("setuptools", _SETUPTOOLS_VERSION),
19 ("pip", _PIP_VERSION),
20]
21
22
Nick Coghlanfdf3a622013-11-30 17:15:09 +100023def _run_pip(args, additional_paths=None):
Nick Coghland0cf0632013-11-11 22:11:55 +100024 # Add our bundled software to the sys.path so we can import it
Nick Coghlanfdf3a622013-11-30 17:15:09 +100025 if additional_paths is not None:
26 sys.path = additional_paths + sys.path
Nick Coghland0cf0632013-11-11 22:11:55 +100027
28 # Install the bundled software
29 import pip
30 pip.main(args)
31
32
33def version():
34 """
35 Returns a string specifying the bundled version of pip.
36 """
37 return _PIP_VERSION
38
39
40def bootstrap(*, root=None, upgrade=False, user=False,
41 altinstall=False, default_pip=False,
42 verbosity=0):
43 """
44 Bootstrap pip into the current Python installation (or the given root
45 directory).
Nick Coghlan6256fcb2013-12-23 16:16:07 +100046
47 Note that calling this function will alter both sys.path and os.environ.
Nick Coghland0cf0632013-11-11 22:11:55 +100048 """
49 if altinstall and default_pip:
50 raise ValueError("Cannot use altinstall and default_pip together")
51
Nick Coghlan6256fcb2013-12-23 16:16:07 +100052 # We deliberately ignore all pip environment variables
53 # See http://bugs.python.org/issue19734 for details
54 keys_to_remove = [k for k in os.environ if k.startswith("PIP_")]
55 for k in keys_to_remove:
56 del os.environ[k]
57
Nick Coghland0cf0632013-11-11 22:11:55 +100058 # By default, installing pip and setuptools installs all of the
59 # following scripts (X.Y == running Python version):
60 #
61 # pip, pipX, pipX.Y, easy_install, easy_install-X.Y
62 #
63 # pip 1.5+ allows ensurepip to request that some of those be left out
64 if altinstall:
65 # omit pip, pipX and easy_install
66 os.environ["ENSUREPIP_OPTIONS"] = "altinstall"
67 elif not default_pip:
68 # omit pip and easy_install
69 os.environ["ENSUREPIP_OPTIONS"] = "install"
70
71 with tempfile.TemporaryDirectory() as tmpdir:
72 # Put our bundled wheels into a temporary directory and construct the
73 # additional paths that need added to sys.path
74 additional_paths = []
75 for project, version in _PROJECTS:
76 wheel_name = "{}-{}-py2.py3-none-any.whl".format(project, version)
77 whl = pkgutil.get_data(
78 "ensurepip",
79 "_bundled/{}".format(wheel_name),
80 )
81 with open(os.path.join(tmpdir, wheel_name), "wb") as fp:
82 fp.write(whl)
83
84 additional_paths.append(os.path.join(tmpdir, wheel_name))
85
86 # Construct the arguments to be passed to the pip command
87 args = [
88 "install", "--no-index", "--find-links", tmpdir,
89 # Temporary until pip 1.5 is final
90 "--pre",
91 ]
92 if root:
93 args += ["--root", root]
94 if upgrade:
95 args += ["--upgrade"]
96 if user:
97 args += ["--user"]
98 if verbosity:
99 args += ["-" + "v" * verbosity]
100
101 _run_pip(args + [p[0] for p in _PROJECTS], additional_paths)
Nick Coghlanfdf3a622013-11-30 17:15:09 +1000102
103def _uninstall(*, verbosity=0):
104 """Helper to support a clean default uninstall process on Windows"""
105 # Nothing to do if pip was never installed, or has been removed
106 try:
107 import pip
108 except ImportError:
109 return
110
111 # If the pip version doesn't match the bundled one, leave it alone
112 if pip.__version__ != _PIP_VERSION:
113 msg = ("ensurepip will only uninstall a matching pip "
114 "({!r} installed, {!r} bundled)")
115 raise RuntimeError(msg.format(pip.__version__, _PIP_VERSION))
116
117 # Construct the arguments to be passed to the pip command
118 args = ["uninstall", "-y"]
119 if verbosity:
120 args += ["-" + "v" * verbosity]
121
122 _run_pip(args + [p[0] for p in reversed(_PROJECTS)])