Skip to content

Commit f309776

Browse files
committed
bpo-31046: Fix ensurepip script shebangs with --root
When using `python -m ensurepip` with the `--root` option for staged installations, the generated pip script contained an incorrect shebang that pointed into the staging directory. This made the installation unusable once the staging directory was removed. This commit fixes the issue by using the internal pip `--executable` option to force the shebang to point to the correct, final interpreter path. It also corrects related pathing issues: - Removes the check that incorrectly disallowed using --root and --prefix together. - Defaults the installation prefix to `/` when --root is used alone, ensuring installation occurs at the base of the staging directory. References: #17634 (comment) Signed-off-by: Matěj Cepl <mcepl@cepl.eu>
1 parent 0f3ed4c commit f309776

1 file changed

Lines changed: 27 additions & 8 deletions

File tree

Lib/ensurepip/__init__.py

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,6 @@ def _bootstrap(*, root=None, upgrade=False, user=False,
140140
"to install pip."
141141
) from None
142142

143-
if root is not None and prefix is not None:
144-
raise ValueError("Cannot use 'root' and 'prefix' together")
145143
if altinstall and default_pip:
146144
raise ValueError("Cannot use altinstall and default_pip together")
147145

@@ -172,19 +170,40 @@ def _bootstrap(*, root=None, upgrade=False, user=False,
172170

173171
# Construct the arguments to be passed to the pip command
174172
args = ["install", "--no-cache-dir", "--no-index", "--find-links", tmpdir]
175-
if root:
176-
args += ["--root", root]
177-
if prefix:
178-
args += ["--prefix", prefix]
179173
if upgrade:
180174
args += ["--upgrade"]
181-
if user:
182-
args += ["--user"]
183175
if verbosity:
184176
args += ["-" + "v" * verbosity]
185177
if sys.implementation.cache_tag is None:
186178
args += ["--no-compile"]
187179

180+
        if user:
181+
            # --user is mutually exclusive with --root/--prefix,
182+
            # pip will enforce this.
183+
            args += ["--user"]
184+
        else:
185+
            # Handle installation paths.
186+
            # If --root is given but not --prefix, we default to a prefix of "/"
187+
            # so that the install happens at the root of the --root directory.
188+
            # Otherwise, pip would use the configured sys.prefix, e.g.
189+
            # /usr/local, and install into ${root}/usr/local/.
190+
            effective_prefix = prefix
191+
            if root and not prefix:
192+
                effective_prefix = "/"
193+
194+
            if root:
195+
                args += ["--root", root]
196+
197+
            if effective_prefix:
198+
                args += ["--prefix", effective_prefix]
199+
200+
                # Force the script shebang to point to the correct, final
201+
                # executable path. This is necessary when --root is used.
202+
                executable_path = (
203+
                    Path(effective_prefix) / "bin" / Path(sys.executable).name
204+
                )
205+
                args += ["--executable", os.fsdecode(executable_path)]
206+
188207
return _run_pip([*args, "pip"], [os.fsdecode(tmp_wheel_path)])
189208

190209

0 commit comments

Comments
 (0)