浏览代码

mkvenv: add better error message for broken or missing ensurepip

Debian debundles ensurepip for python; NetBSD debundles pyexpat but
ensurepip needs pyexpat. Try our best to offer a helpful error message
instead of just failing catastrophically.

Signed-off-by: John Snow <jsnow@redhat.com>
Message-Id: <20230511035435.734312-5-jsnow@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
John Snow 2 年之前
父节点
当前提交
a9dbde71da
共有 1 个文件被更改,包括 37 次插入0 次删除
  1. 37 0
      python/scripts/mkvenv.py

+ 37 - 0
python/scripts/mkvenv.py

@@ -34,6 +34,7 @@
 # later. See the COPYING file in the top-level directory.
 # later. See the COPYING file in the top-level directory.
 
 
 import argparse
 import argparse
+from importlib.util import find_spec
 import logging
 import logging
 import os
 import os
 from pathlib import Path
 from pathlib import Path
@@ -76,6 +77,10 @@ class QemuEnvBuilder(venv.EnvBuilder):
 
 
     def __init__(self, *args: Any, **kwargs: Any) -> None:
     def __init__(self, *args: Any, **kwargs: Any) -> None:
         logger.debug("QemuEnvBuilder.__init__(...)")
         logger.debug("QemuEnvBuilder.__init__(...)")
+
+        if kwargs.get("with_pip", False):
+            check_ensurepip()
+
         super().__init__(*args, **kwargs)
         super().__init__(*args, **kwargs)
 
 
         # Make the context available post-creation:
         # Make the context available post-creation:
@@ -98,6 +103,38 @@ def get_value(self, field: str) -> str:
         return ret
         return ret
 
 
 
 
+def check_ensurepip() -> None:
+    """
+    Check that we have ensurepip.
+
+    Raise a fatal exception with a helpful hint if it isn't available.
+    """
+    if not find_spec("ensurepip"):
+        msg = (
+            "Python's ensurepip module is not found.\n"
+            "It's normally part of the Python standard library, "
+            "maybe your distribution packages it separately?\n"
+            "Either install ensurepip, or alleviate the need for it in the "
+            "first place by installing pip and setuptools for "
+            f"'{sys.executable}'.\n"
+            "(Hint: Debian puts ensurepip in its python3-venv package.)"
+        )
+        raise Ouch(msg)
+
+    # ensurepip uses pyexpat, which can also go missing on us:
+    if not find_spec("pyexpat"):
+        msg = (
+            "Python's pyexpat module is not found.\n"
+            "It's normally part of the Python standard library, "
+            "maybe your distribution packages it separately?\n"
+            "Either install pyexpat, or alleviate the need for it in the "
+            "first place by installing pip and setuptools for "
+            f"'{sys.executable}'.\n\n"
+            "(Hint: NetBSD's pkgsrc debundles this to e.g. 'py310-expat'.)"
+        )
+        raise Ouch(msg)
+
+
 def make_venv(  # pylint: disable=too-many-arguments
 def make_venv(  # pylint: disable=too-many-arguments
     env_dir: Union[str, Path],
     env_dir: Union[str, Path],
     system_site_packages: bool = False,
     system_site_packages: bool = False,