From: Stefano Rivera <stefanor@debian.org>
Date: Sat, 7 Oct 2017 09:38:58 +0200
Subject: Debian: Let ensurepip use the system wheels

Not the ones from the python source.

Origin: Debian cpython packaging
Last-Update: 2017-05-21
---
 lib-python/3/ensurepip/__init__.py | 90 ++++++++++++++++++++++++--------------
 1 file changed, 57 insertions(+), 33 deletions(-)

diff --git a/lib-python/3/ensurepip/__init__.py b/lib-python/3/ensurepip/__init__.py
index c628828..1c8c7c1 100644
--- a/lib-python/3/ensurepip/__init__.py
+++ b/lib-python/3/ensurepip/__init__.py
@@ -1,4 +1,5 @@
 import collections
+import glob
 import os
 import os.path
 import subprocess
@@ -10,12 +11,9 @@ from importlib import resources
 
 
 __all__ = ["version", "bootstrap"]
-_PACKAGE_NAMES = ('setuptools', 'pip')
-_SETUPTOOLS_VERSION = "65.5.0"
-_PIP_VERSION = "23.0.1"
 _PROJECTS = [
-    ("setuptools", _SETUPTOOLS_VERSION, "py3"),
-    ("pip", _PIP_VERSION, "py3"),
+    "setuptools",
+    "pip",
 ]
 
 # Packages bundled in ensurepip._bundled have wheel_name set.
@@ -108,7 +106,18 @@ def version():
     """
     Returns a string specifying the bundled version of pip.
     """
-    return _get_packages()['pip'].version
+    wheel_names = glob.glob('/usr/share/python-wheels/pip-*[.-]py3-*.whl')
+    if not wheel_names:
+        return None
+    wheel_names.sort(key=_wheel_version, reverse=True)
+    return os.path.basename(wheel_names[0]).split('-')[1]
+
+
+def _wheel_version(name):
+    """Return a tuple of a .whl's version, for sorting"""
+    name = os.path.basename(name)
+    package, version, tags = name.split('-', 2)
+    return [int(part) for part in version.split('.') if part.isdigit()]
 
 
 def _disable_pip_configuration_settings():
@@ -167,27 +176,44 @@ def _bootstrap(*, root=None, upgrade=False, user=False,
         # omit pip and easy_install
         os.environ["ENSUREPIP_OPTIONS"] = "install"
 
+    # Debian: The bundled wheels are useless to us because we must use ones
+    # crafted from source code in the archive.  As we build the virtual
+    # environment, copy the wheels from the system location into the virtual
+    # environment, and place those wheels on sys.path.
+    def copy_wheels(wheels, destdir, paths):
+        for project in wheels:
+            wheel_names = glob.glob(
+                '/usr/share/python-wheels/{}-*[.-]py3-*.whl'.format(project))
+            if len(wheel_names) == 0:
+                raise RuntimeError('missing dependency wheel %s' % project)
+            wheel_names.sort(key=_wheel_version, reverse=True)
+            wheel_name = os.path.basename(wheel_names[0])
+            path = os.path.join('/usr/share/python-wheels', wheel_name)
+            with open(path, 'rb') as fp:
+                whl = fp.read()
+            dest = os.path.join(destdir, wheel_name)
+            with open(dest, 'wb') as fp:
+                fp.write(whl)
+            paths.append(dest)
+
     with tempfile.TemporaryDirectory() as tmpdir:
+        # This directory is a "well known directory" which Debian has patched
+        # pip to look in when attempting to locate wheels to use to satisfy
+        # the dependencies that pip normally bundles but Debian has debundled.
+        # This is critically important and if this directory changes then both
+        # python-pip and python-virtualenv needs updated to match.
+        venv_wheel_dir = os.path.join(sys.prefix, 'share', 'python-wheels')
+        os.makedirs(venv_wheel_dir, exist_ok=True)
+        dependencies = [
+            os.path.basename(whl).split('-')[0]
+            for whl in glob.glob('/usr/share/python-wheels/*.whl')
+            ]
+        copy_wheels(dependencies, venv_wheel_dir, sys.path)
+
         # Put our bundled wheels into a temporary directory and construct the
         # additional paths that need added to sys.path
         additional_paths = []
-        for name, package in _get_packages().items():
-            if package.wheel_name:
-                # Use bundled wheel package
-                from ensurepip import _bundled
-                wheel_name = package.wheel_name
-                whl = resources.read_binary(_bundled, wheel_name)
-            else:
-                # Use the wheel package directory
-                with open(package.wheel_path, "rb") as fp:
-                    whl = fp.read()
-                wheel_name = os.path.basename(package.wheel_path)
-
-            filename = os.path.join(tmpdir, wheel_name)
-            with open(filename, "wb") as fp:
-                fp.write(whl)
-
-            additional_paths.append(filename)
+        copy_wheels(_PROJECTS, tmpdir, additional_paths)
 
         # Construct the arguments to be passed to the pip command
         args = ["install", "--no-cache-dir", "--no-index", "--find-links", tmpdir]
@@ -200,7 +226,7 @@ def _bootstrap(*, root=None, upgrade=False, user=False,
         if verbosity:
             args += ["-" + "v" * verbosity]
 
-        return _run_pip([*args, *_PACKAGE_NAMES], additional_paths)
+        return _run_pip(args + _PROJECTS, additional_paths)
 
 def _uninstall_helper(*, verbosity=0):
     """Helper to support a clean default uninstall process on Windows
@@ -213,14 +239,12 @@ def _uninstall_helper(*, verbosity=0):
     except ImportError:
         return
 
-    # If the installed pip version doesn't match the available one,
-    # leave it alone
-    available_version = version()
-    if pip.__version__ != available_version:
-        print(f"ensurepip will only uninstall a matching version "
-              f"({pip.__version__!r} installed, "
-              f"{available_version!r} available)",
-              file=sys.stderr)
+    # If the pip version doesn't match the bundled one, leave it alone
+    # Disabled for Debian, always using the version from the python3-pip package.
+    if False:  # pip.__version__ != _PIP_VERSION:
+        msg = ("ensurepip will only uninstall a matching version "
+               "({!r} installed, {!r} bundled)")
+        print(msg.format(pip.__version__, _PIP_VERSION), file=sys.stderr)
         return
 
     _disable_pip_configuration_settings()
@@ -230,7 +254,7 @@ def _uninstall_helper(*, verbosity=0):
     if verbosity:
         args += ["-" + "v" * verbosity]
 
-    return _run_pip([*args, *reversed(_PACKAGE_NAMES)])
+    return _run_pip(args + list(reversed(_PROJECTS)))
 
 
 def _main(argv=None):
