Bug 1752927: Avoid distutils deprecation warning on every Mach call r=ahal

Python 3.10 prints a warning when it sees `distutils` used, so let's
avoid using `distutils` in the "common Mach code" that runs on every
Mach call.

Note that this change will also fix the `SetuptoolsDeprecationWarning`
that shipped on `setuptools>=58.3.0`, since our usage of `distutils` was
calling a `setup.py install` under the hood.

Differential Revision: https://phabricator.services.mozilla.com/D137499
This commit is contained in:
Mitchell Hentges 2022-02-04 21:49:15 +00:00
parent 951485daa3
commit b3b0d2b63d
5 changed files with 37 additions and 38 deletions

10
mach
View file

@ -77,16 +77,6 @@ def main(args):
""").strip())
sys.exit(1)
try:
import distutils
except ModuleNotFoundError:
print(dedent("""
Mach needs the Python "distutils" module, but it's not available on your
machine. This error is most common on Debian Linux (or derivatives), and can be
fixed by installing a package named something like `python3-distutils`.
""").strip())
sys.exit(1)
# XCode python sets __PYVENV_LAUNCHER__, which overrides the executable
# used when a python subprocess is created. This is an issue when we want
# to run using our virtualenv python executables.

View file

@ -17,7 +17,7 @@ import shutil
import subprocess
import sys
from collections import OrderedDict
from distutils import dist
import sysconfig
from pathlib import Path
import tempfile
from contextlib import contextmanager
@ -743,15 +743,24 @@ class PythonVirtualenv:
@functools.lru_cache(maxsize=None)
def site_packages_dir(self):
# macOS uses a different default sysconfig scheme based on whether it's using the
# system Python or running in a virtualenv.
# Manually define the scheme (following the implementation in
# "sysconfig._get_default_scheme()") so that we're always following the
# code path for a virtualenv directory structure.
if os.name == "posix":
scheme = "posix_prefix"
else:
scheme = os.name
sysconfig_paths = sysconfig.get_paths(scheme)
data_path = Path(sysconfig_paths["data"])
purelib_path = Path(sysconfig_paths["purelib"])
relative_purelib_path = purelib_path.relative_to(data_path)
normalized_venv_root = os.path.normpath(self.prefix)
distribution = dist.Distribution({"script_args": "--no-user-cfg"})
installer = distribution.get_command_obj("install")
installer.prefix = normalized_venv_root
installer.finalize_options()
# Path to virtualenv's "site-packages" directory
path = installer.install_purelib
path = os.path.join(normalized_venv_root, relative_purelib_path)
local_folder = os.path.join(normalized_venv_root, "local")
# Hack around https://github.com/pypa/virtualenv/issues/2208
if path.startswith(local_folder):
@ -789,11 +798,11 @@ class PythonVirtualenv:
return self.pip_install(["--constraint", constraints_path] + pip_args)
def pip_install(self, pip_install_args, **kwargs):
# distutils will use the architecture of the running Python instance when building
# packages. However, it's possible for the Xcode Python to be a universal binary
# (x86_64 and arm64) without the associated macOS SDK supporting arm64, thereby
# causing a build failure. To avoid this, we explicitly influence the build to
# only target a single architecture - our current architecture.
# setuptools will use the architecture of the running Python instance when
# building packages. However, it's possible for the Xcode Python to be a universal
# binary (x86_64 and arm64) without the associated macOS SDK supporting arm64,
# thereby causing a build failure. To avoid this, we explicitly influence the
# build to only target a single architecture - our current architecture.
kwargs.setdefault("env", os.environ.copy()).setdefault(
"ARCHFLAGS", "-arch {}".format(platform.machine())
)
@ -1080,8 +1089,8 @@ def _deprioritize_venv_packages(virtualenv):
# Additionally, when removing the existing "site-packages" folder's entry, we have
# to do it in a case-insensitive way because, on Windows:
# * Python adds it as <venv>/lib/site-packages
# * While distutils tells us it's <venv>/Lib/site-packages
# * (note: on-disk, it's capitalized, so distutils is slightly more accurate).
# * While sysconfig tells us it's <venv>/Lib/site-packages
# * (note: on-disk, it's capitalized, so sysconfig is slightly more accurate).
for line in (
"import sys; sys.path = [p for p in sys.path if "
f"p.lower() != {repr(site_packages_dir)}.lower()]",

View file

@ -12,7 +12,7 @@ import sys
from pathlib import Path
from distutils.version import LooseVersion
from packaging.version import Version
from mozboot import rust
from mozboot.util import (
get_mach_virtualenv_binary,
@ -143,10 +143,10 @@ ac_add_options --enable-application=js
# Upgrade Mercurial older than this.
# This should match the OLDEST_NON_LEGACY_VERSION in
# version-control-tools/hgext/configwizard/__init__.py.
MODERN_MERCURIAL_VERSION = LooseVersion("4.9")
MODERN_MERCURIAL_VERSION = Version("4.9")
# Upgrade rust older than this.
MODERN_RUST_VERSION = LooseVersion(MINIMUM_RUST_VERSION)
MODERN_RUST_VERSION = Version(MINIMUM_RUST_VERSION)
class BaseBootstrapper(object):
@ -619,7 +619,7 @@ class BaseBootstrapper(object):
"""Execute the given path, returning the version.
Invokes the path argument with the --version switch
and returns a LooseVersion representing the output
and returns a Version representing the output
if successful. If not, returns None.
An optional name argument gives the expected program
@ -653,7 +653,7 @@ class BaseBootstrapper(object):
print("ERROR! Unable to identify %s version." % name)
return None
return LooseVersion(match.group(1))
return Version(match.group(1))
def _parse_version(self, path: Path, name=None, env=None):
return self._parse_version_impl(path, name, env, "--version")
@ -817,7 +817,7 @@ class BaseBootstrapper(object):
if "mobile_android" in self.application:
# Let's add the most common targets.
if rust_version < LooseVersion("1.33"):
if rust_version < Version("1.33"):
arm_target = "armv7-linux-androideabi"
else:
arm_target = "thumbv7neon-linux-androideabi"

View file

@ -14,7 +14,7 @@ import subprocess
import time
from typing import Optional
from pathlib import Path
from distutils.version import LooseVersion
from packaging.version import Version
from mach.util import (
get_state_dir,
UserError,
@ -128,7 +128,7 @@ Proceed at your own peril.
# Version 2.24 changes the "core.commitGraph" setting to be "True" by default.
MINIMUM_RECOMMENDED_GIT_VERSION = LooseVersion("2.24")
MINIMUM_RECOMMENDED_GIT_VERSION = Version("2.24")
OLD_GIT_WARNING = """
You are running an older version of git ("{old_version}").
We recommend upgrading to at least version "{minimum_recommended_version}" to improve
@ -616,7 +616,7 @@ def configure_git(
)
if not match:
raise Exception("Could not find git version")
git_version = LooseVersion(match.group(1))
git_version = Version(match.group(1))
if git_version < MINIMUM_RECOMMENDED_GIT_VERSION:
print(
@ -626,7 +626,7 @@ def configure_git(
)
)
if git_version >= LooseVersion("2.17"):
if git_version >= Version("2.17"):
# "core.untrackedCache" has a bug before 2.17
subprocess.check_call(
[git_str, "config", "core.untrackedCache", "true"], cwd=str(top_src_dir)

View file

@ -16,7 +16,7 @@ except ImportError:
from urllib.request import urlopen
from pathlib import Path
from distutils.version import StrictVersion
from packaging.version import Version
from mozboot.base import BaseBootstrapper
from mozfile import which
@ -200,9 +200,9 @@ class OSXBootstrapper(OSXAndroidBootstrapper, BaseBootstrapper):
def __init__(self, version, **kwargs):
BaseBootstrapper.__init__(self, **kwargs)
self.os_version = StrictVersion(version)
self.os_version = Version(version)
if self.os_version < StrictVersion("10.6"):
if self.os_version < Version("10.6"):
raise Exception("OS X 10.6 or above is required.")
self.minor_version = version.split(".")[1]