aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/mach_bootstrap.py76
-rw-r--r--python/servo/build_commands.py4
-rw-r--r--python/servo/command_base.py5
3 files changed, 38 insertions, 47 deletions
diff --git a/python/mach_bootstrap.py b/python/mach_bootstrap.py
index c8085315219..53f7adb3fc4 100644
--- a/python/mach_bootstrap.py
+++ b/python/mach_bootstrap.py
@@ -4,8 +4,9 @@
import os
import platform
-import sys
+import site
import shutil
+import sys
from subprocess import Popen
from tempfile import TemporaryFile
@@ -80,27 +81,26 @@ CATEGORIES = {
}
}
-# Possible names of executables
-# NOTE: Windows Python doesn't provide versioned executables, so we must use
-# the plain names. On MSYS, we still use Windows Python.
-PYTHON_NAMES = ["python-2.7", "python2.7", "python2", "python"]
-
-
-def _get_exec_path(names, is_valid_path=lambda _path: True):
- for name in names:
- path = shutil.which(name)
- if path and is_valid_path(path):
- return path
- return None
-
+# venv calls its scripts folder "bin" on non-Windows and "Scripts" on Windows.
def _get_virtualenv_script_dir():
- # Virtualenv calls its scripts folder "bin" on linux/OSX/MSYS64 but "Scripts" on Windows
if os.name == "nt" and os.sep != "/":
return "Scripts"
return "bin"
+# venv names its lib folder something like "lib/python3.11/site-packages" on
+# non-Windows and "Lib\site-packages" on Window.
+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"
+ )
+
+
def _process_exec(args):
with TemporaryFile() as out:
with TemporaryFile() as err:
@@ -130,32 +130,29 @@ def _process_exec(args):
def _activate_virtualenv(topdir):
- virtualenv_path = os.path.join(topdir, "python", "_virtualenv%d.%d" % (sys.version_info[0], sys.version_info[1]))
- python = sys.executable # If there was no python, mach wouldn't have run at all!
- if not python:
- sys.exit('Failed to find python executable for starting virtualenv.')
-
- script_dir = _get_virtualenv_script_dir()
- activate_path = os.path.join(virtualenv_path, script_dir, "activate_this.py")
- need_pip_upgrade = False
- if not (os.path.exists(virtualenv_path) and os.path.exists(activate_path)):
- import importlib
- try:
- importlib.import_module('virtualenv')
- except ModuleNotFoundError:
- sys.exit("Python virtualenv is not installed. Please install it prior to running mach.")
+ virtualenv_path = os.path.join(topdir, "python", "_venv%d.%d" % (sys.version_info[0], sys.version_info[1]))
+ python = sys.executable
- _process_exec([python, "-m", "virtualenv", "-p", python, "--system-site-packages", virtualenv_path])
+ 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):
+ _process_exec([python, "-m", "venv", "--system-site-packages", virtualenv_path])
- # We want to upgrade pip when virtualenv created for the first time
- need_pip_upgrade = True
+ # 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)])
+ os.environ["VIRTUAL_ENV"] = virtualenv_path
- exec(compile(open(activate_path).read(), activate_path, 'exec'), dict(__file__=activate_path))
+ prev_length = len(sys.path)
+ lib_path = os.path.realpath(os.path.join(virtualenv_path, _get_virtualenv_lib_dir()))
+ site.addsitedir(lib_path)
+ sys.path[:] = sys.path[prev_length:] + sys.path[0:prev_length]
- python = _get_exec_path(PYTHON_NAMES,
- is_valid_path=lambda path: path.startswith(virtualenv_path))
- if not python:
- sys.exit("Python executable in virtualenv failed to activate.")
+ sys.real_prefix = sys.prefix
+ sys.prefix = virtualenv_path
+
+ # Use the python in our venv for subprocesses, not the python we were originally run with.
+ # Otherwise pip may still try to write to the wrong site-packages directory.
+ python = os.path.join(venv_script_path, "python")
# TODO: Right now, we iteratively install all the requirements by invoking
# `pip install` each time. If it were the case that there were conflicting
@@ -168,11 +165,6 @@ def _activate_virtualenv(topdir):
os.path.join(WPT_RUNNER_PATH, "requirements.txt",),
]
- if need_pip_upgrade:
- # Upgrade pip when virtualenv is created to fix the issue
- # https://github.com/servo/servo/issues/11074
- _process_exec([python, "-m", "pip", "install", "-I", "-U", "pip"])
-
for req_rel_path in requirements_paths:
req_path = os.path.join(topdir, req_rel_path)
marker_file = req_rel_path.replace(os.path.sep, '-')
diff --git a/python/servo/build_commands.py b/python/servo/build_commands.py
index cd977dfe91d..fae27e25b9e 100644
--- a/python/servo/build_commands.py
+++ b/python/servo/build_commands.py
@@ -252,7 +252,7 @@ class MachCommands(CommandBase):
subprocess.call(["perl", "-i", "-pe", expr, target_path])
@Command('clean',
- description='Clean the target/ and python/_virtualenv[version]/ directories',
+ description='Clean the target/ and python/_venv[version]/ directories',
category='build')
@CommandArgument('--manifest-path',
default=None,
@@ -265,7 +265,7 @@ class MachCommands(CommandBase):
def clean(self, manifest_path=None, params=[], verbose=False):
self.ensure_bootstrapped()
- virtualenv_fname = '_virtualenv%d.%d' % (sys.version_info[0], sys.version_info[1])
+ virtualenv_fname = '_venv%d.%d' % (sys.version_info[0], sys.version_info[1])
virtualenv_path = path.join(self.get_top_dir(), 'python', virtualenv_fname)
if path.exists(virtualenv_path):
print('Removing virtualenv directory: %s' % virtualenv_path)
diff --git a/python/servo/command_base.py b/python/servo/command_base.py
index daf9b68dd8e..af44102b313 100644
--- a/python/servo/command_base.py
+++ b/python/servo/command_base.py
@@ -36,7 +36,6 @@ from xml.etree.ElementTree import XML
import toml
-from mach_bootstrap import _get_exec_path
from mach.decorators import CommandArgument, CommandArgumentGroup
from mach.registrar import Registrar
@@ -618,8 +617,8 @@ class CommandBase(object):
host_suffix = "x86_64"
host = os_type + "-" + host_suffix
- host_cc = env.get('HOST_CC') or _get_exec_path(["clang"]) or _get_exec_path(["gcc"])
- host_cxx = env.get('HOST_CXX') or _get_exec_path(["clang++"]) or _get_exec_path(["g++"])
+ host_cc = env.get('HOST_CC') or shutil.which(["clang"]) or util.whichget_exec_path(["gcc"])
+ host_cxx = env.get('HOST_CXX') or util.whichget_exec_path(["clang++"]) or util.whichget_exec_path(["g++"])
llvm_toolchain = path.join(env['ANDROID_NDK'], "toolchains", "llvm", "prebuilt", host)
gcc_toolchain = path.join(env['ANDROID_NDK'], "toolchains",