diff --git a/files/installer.py b/files/installer.py index ba740ad..d2133b9 100644 --- a/files/installer.py +++ b/files/installer.py @@ -5,9 +5,11 @@ import dataclasses import json import os +import pathlib import re import shutil import subprocess +import tempfile import typing as t import urllib.request @@ -49,7 +51,6 @@ class Pip: _OPTIONS = ( '--disable-pip-version-check', - '--no-cache-dir', ) _DEFAULT_PACKAGES = dict( @@ -105,6 +106,15 @@ def show_version(self) -> None: """Show the pip version.""" subprocess.run(self._pip_command + ['--version'] + list(self._OPTIONS), check=True) + def wheel(self, args: t.List[str], constraints: pathlib.Path) -> None: + """Build Python wheels with the given constraints file, storing them in the pip cache.""" + env = os.environ.copy() + env.update(PIP_CONSTRAINT=str(constraints)) + + with tempfile.TemporaryDirectory() as temp_dir: + with self._install_options_context() as options: + subprocess.run(self._pip_command + ['wheel'] + options + list(self._OPTIONS) + args, check=True, env=env, cwd=temp_dir) + def install(self, args: t.List[str]) -> None: """Install Python packages.""" with self._install_options_context() as options: @@ -121,6 +131,11 @@ def check(self) -> None: """Check installed Python packages.""" subprocess.run(self._pip_command + ['check'] + list(self._OPTIONS), check=True) + @staticmethod + def purge_cache() -> None: + """Purge the pip cache.""" + shutil.rmtree(os.path.expanduser('~/.cache/pip')) # The `pip cache purge` command leaves behind directories. + @contextlib.contextmanager def _install_options_context(self) -> t.List[str]: """Create a pip install context for the specified Python interpreter and return options needed for the installation.""" diff --git a/files/setup.py b/files/setup.py index 02a7ff5..34c3ec5 100644 --- a/files/setup.py +++ b/files/setup.py @@ -56,6 +56,8 @@ def setup_python(python: Python) -> None: display.section(f'Completed setup of Python {python.version}') + pip.purge_cache() + if __name__ == '__main__': main()