mach: switch to uv for managing python venv (#34504)

This patch switches servo to use `uv` for both installing a pinned
Python version as well as installing the dependency packages using
`uv`'s pip compatible interface. It also introduces a new 'composite'
GitHub action to setup python in the different CI workflows.

There is no support for externally managed python installations and
virtual environments. These could be added in the future.

Fixes #34095

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
This commit is contained in:
Mukilan Thiyagarajan 2024-12-09 20:22:06 +05:30 committed by GitHub
parent a0743f60b3
commit 4103421ba5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 100 additions and 80 deletions

View file

@ -4,7 +4,6 @@
import hashlib
import os
import platform
import site
import subprocess
import sys
@ -93,11 +92,13 @@ def _get_virtualenv_script_dir():
def _get_virtualenv_lib_dir():
if os.name == "nt" and os.sep != "/":
return os.path.join("Lib", "site-packages")
return os.path.join(
"lib",
f"python{sys.version_info[0]}.{sys.version_info[1]}",
"site-packages"
)
with open(".python-version", "r") as python_version_file:
python_version = python_version_file.read().strip()
return os.path.join(
"lib",
f"python{python_version}",
"site-packages"
)
def _process_exec(args):
@ -131,11 +132,8 @@ def install_virtual_env_requirements(project_path: str, python: str, virtualenv_
requirements_hash = requirements_hasher.hexdigest()
if marker_hash != requirements_hash:
print(" * Upgrading pip...")
_process_exec([python, "-m", "pip", "install", "--upgrade", "pip"])
print(" * Installing Python requirements...")
_process_exec([python, "-m", "pip", "install", "-I",
_process_exec(["uv", "pip", "install",
"-r", requirements_paths[0],
"-r", requirements_paths[1],
"-r", requirements_paths[2]])
@ -144,14 +142,14 @@ def install_virtual_env_requirements(project_path: str, python: str, virtualenv_
def _activate_virtualenv(topdir):
virtualenv_path = os.path.join(topdir, "python", "_venv%d.%d" % (sys.version_info[0], sys.version_info[1]))
virtualenv_path = os.path.join(topdir, ".venv")
python = sys.executable
if os.environ.get("VIRTUAL_ENV") != virtualenv_path:
venv_script_path = os.path.join(virtualenv_path, _get_virtualenv_script_dir())
if not os.path.exists(virtualenv_path):
print(" * Setting up virtual environment...")
_process_exec([python, "-m", "venv", "--system-site-packages", virtualenv_path])
_process_exec(["uv", "venv"])
# This general approach is taken from virtualenv's `activate_this.py`.
os.environ["PATH"] = os.pathsep.join([venv_script_path, *os.environ.get("PATH", "").split(os.pathsep)])
@ -171,6 +169,11 @@ def _activate_virtualenv(topdir):
install_virtual_env_requirements(topdir, python, virtualenv_path)
# Turn off warnings about deprecated syntax in our indirect dependencies.
# TODO: Find a better approach for doing this.
import warnings
warnings.filterwarnings('ignore', category=SyntaxWarning, module=r'.*.venv')
def _ensure_case_insensitive_if_windows():
# The folder is called 'python'. By deliberately checking for it with the wrong case, we determine if the file
@ -221,13 +224,6 @@ def bootstrap(topdir):
print('Current path:', topdir)
sys.exit(1)
# Ensure we are running Python 3.10+. We put this check here so we generate a
# user-friendly error message rather than a cryptic stack trace on module import.
if sys.version_info < (3, 10):
print('Python3 (>=3.10) is required to run mach.')
print('You are running Python', platform.python_version())
sys.exit(1)
_activate_virtualenv(topdir)
def populate_context(context, key=None):