Add pip as a custom package via python -m ensurepip

pip is unusual among the custom packages because it ships inside CPython
itself, so it doesn't need a URL or archive. The handler bootstraps it
from the standard-library wheel via 'python3 -m ensurepip --upgrade' and
then self-upgrades to the latest version. Detection uses
'python3 -m pip --version' instead of a filesystem path.
This commit is contained in:
Claude
2026-05-18 13:54:46 +00:00
parent a4d1dfb9fb
commit a05df917f7
2 changed files with 51 additions and 5 deletions
+50 -5
View File
@@ -676,8 +676,24 @@ def _default_install_path(pkg: CustomPackage) -> Optional[Path]:
return _DEFAULT_INSTALL_PATHS.get(pkg.name.lower())
def _pip_installed() -> bool:
if not has_cmd("python3"):
return False
return subprocess.run(
["python3", "-m", "pip", "--version"],
capture_output=True, check=False,
).returncode == 0
def is_custom_pkg_installed(pkg: CustomPackage) -> tuple[bool, Optional[Path]]:
"""Return (is_installed, check_path)."""
"""Return (is_installed, check_path).
For most custom packages the check is a filesystem path. ``pip`` is the
exception: it ships inside a Python distribution rather than at a known
path, so it's detected by running ``python3 -m pip --version``.
"""
if pkg.name.lower() == "pip":
return _pip_installed(), None
raw = Path(pkg.install_path) if pkg.install_path else _default_install_path(pkg)
if raw is None:
return False, None
@@ -788,6 +804,33 @@ def _install_pyenv() -> None:
print(" pyenv installed to ~/.pyenv")
def _install_pip() -> None:
"""Install pip via Python's bundled ``ensurepip`` module, then self-upgrade.
Unlike the other custom packages, pip ships inside CPython itself and is
bootstrapped from the wheel in the standard library rather than downloaded.
"""
if not has_cmd("python3"):
err("python3 is not installed — cannot install pip")
return
print(" Bootstrapping pip via 'python3 -m ensurepip --upgrade' ...")
bootstrap = run(
["python3", "-m", "ensurepip", "--upgrade"],
as_sudo=True, check=False,
)
if bootstrap.returncode != 0:
err("python3 -m ensurepip failed (system Python may need a distro 'python3-pip' package)")
return
print(" Upgrading pip to the latest version ...")
upgrade = run(
["python3", "-m", "pip", "install", "--upgrade", "pip"],
as_sudo=True, check=False,
)
if upgrade.returncode != 0:
warn("pip self-upgrade failed (likely PEP 668 externally-managed); "
"ensurepip-provided pip remains")
def _install_nvm() -> None:
data = _fetch_json("https://api.github.com/repos/nvm-sh/nvm/releases/latest")
if data is None:
@@ -1088,14 +1131,13 @@ def _resolve_latest(pkg: CustomPackage) -> None:
def install_custom_packages(to_install: list[CustomPackage]) -> None:
print("\n=== Custom Packages ===")
for pkg in to_install:
name_lower = pkg.name.lower()
_, check_path = is_custom_pkg_installed(pkg)
print(f"\n Installing {pkg.display_name} ..."
+ (f" (install path: {check_path})" if check_path else ""))
if check_path is None:
if check_path is None and name_lower != "pip":
warn(f"{pkg.name}: no known install path — script will not detect future installs")
name_lower = pkg.name.lower()
# Handlers that manage their own download/install
if name_lower == "nvm":
_install_nvm()
@@ -1103,6 +1145,9 @@ def install_custom_packages(to_install: list[CustomPackage]) -> None:
if name_lower == "pyenv":
_install_pyenv()
continue
if name_lower == "pip":
_install_pip()
continue
if name_lower == "neovim":
with tempfile.TemporaryDirectory() as tmp_str:
_install_neovim(pkg, Path(tmp_str))
@@ -1221,7 +1266,7 @@ def print_check_summary(sys_c: dict, flat_c: dict, cust_c: dict, only: Optional[
ok = cust_c["already_installed"]
print("\nCustom packages:")
for pkg, path in ok:
print(f" [OK] {pkg.display_name} ({path})")
print(f" [OK] {pkg.display_name}" + (f" ({path})" if path else ""))
for pkg in to:
_, path = is_custom_pkg_installed(pkg)
print(f" [INSTALL] {pkg.display_name}" + (f" → {path}" if path else ""))
+1
View File
@@ -110,4 +110,5 @@ CUSTOM_PACKAGES: list[dict] = [
},
{"name": "nvm"},
{"name": "pyenv"},
{"name": "pip"},
]