mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1759084: Print reason for site being out-of-date r=ahal
There are cases in CI where sites are being considered out-of-date, despite the situation being unexpected - for example, the "site out-of-date even though already activated" issue described in this patch's associated bug. Return a `reason` string from `_is_venv_up_to_date()`, and print it in cases where a virtualenv being out-of-date is erroneous. Differential Revision: https://phabricator.services.mozilla.com/D140855
This commit is contained in:
parent
25ca8bd87b
commit
a822813370
@ -49,6 +49,12 @@ class InstallPipRequirementsException(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SiteUpToDateResult:
|
||||||
|
def __init__(self, is_up_to_date, reason=None):
|
||||||
|
self.is_up_to_date = is_up_to_date
|
||||||
|
self.reason = reason
|
||||||
|
|
||||||
|
|
||||||
class SitePackagesSource(enum.Enum):
|
class SitePackagesSource(enum.Enum):
|
||||||
NONE = "none"
|
NONE = "none"
|
||||||
SYSTEM = "system"
|
SYSTEM = "system"
|
||||||
@ -338,7 +344,7 @@ class MachSiteManager:
|
|||||||
|
|
||||||
def _up_to_date(self):
|
def _up_to_date(self):
|
||||||
if self._site_packages_source == SitePackagesSource.NONE:
|
if self._site_packages_source == SitePackagesSource.NONE:
|
||||||
return True
|
return SiteUpToDateResult(True)
|
||||||
elif self._site_packages_source == SitePackagesSource.SYSTEM:
|
elif self._site_packages_source == SitePackagesSource.SYSTEM:
|
||||||
pthfile_lines = [
|
pthfile_lines = [
|
||||||
*self._requirements.pths_as_absolute(self._topsrcdir),
|
*self._requirements.pths_as_absolute(self._topsrcdir),
|
||||||
@ -347,7 +353,7 @@ class MachSiteManager:
|
|||||||
_assert_pip_check(
|
_assert_pip_check(
|
||||||
self._topsrcdir, pthfile_lines, "mach", self._requirements
|
self._topsrcdir, pthfile_lines, "mach", self._requirements
|
||||||
)
|
)
|
||||||
return True
|
return SiteUpToDateResult(True)
|
||||||
elif self._site_packages_source == SitePackagesSource.VENV:
|
elif self._site_packages_source == SitePackagesSource.VENV:
|
||||||
environment = self._virtualenv()
|
environment = self._virtualenv()
|
||||||
return _is_venv_up_to_date(
|
return _is_venv_up_to_date(
|
||||||
@ -359,15 +365,15 @@ class MachSiteManager:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def ensure(self, *, force=False):
|
def ensure(self, *, force=False):
|
||||||
up_to_date = self._up_to_date()
|
result = self._up_to_date()
|
||||||
if force or not up_to_date:
|
if force or not result.is_up_to_date:
|
||||||
if Path(sys.prefix) == Path(self._metadata.prefix):
|
if Path(sys.prefix) == Path(self._metadata.prefix):
|
||||||
# If the Mach virtualenv is already activated, then the changes caused
|
# If the Mach virtualenv is already activated, then the changes caused
|
||||||
# by rebuilding the virtualenv won't take effect until the next time
|
# by rebuilding the virtualenv won't take effect until the next time
|
||||||
# Mach is used, which can lead to confusing one-off errors.
|
# Mach is used, which can lead to confusing one-off errors.
|
||||||
# Instead, request that the user resolve the out-of-date situation,
|
# Instead, request that the user resolve the out-of-date situation,
|
||||||
# *then* come back and run the intended command.
|
# *then* come back and run the intended command.
|
||||||
raise VirtualenvOutOfDateException()
|
raise VirtualenvOutOfDateException(result.reason)
|
||||||
self._build()
|
self._build()
|
||||||
|
|
||||||
def attempt_populate_optional_packages(self):
|
def attempt_populate_optional_packages(self):
|
||||||
@ -560,9 +566,11 @@ class CommandSiteManager:
|
|||||||
If using a virtualenv Python binary directly, it's useful to call this function
|
If using a virtualenv Python binary directly, it's useful to call this function
|
||||||
first to ensure that the virtualenv doesn't have obsolete references or packages.
|
first to ensure that the virtualenv doesn't have obsolete references or packages.
|
||||||
"""
|
"""
|
||||||
if not self._up_to_date():
|
result = self._up_to_date()
|
||||||
|
if not result.is_up_to_date:
|
||||||
active_site = MozSiteMetadata.from_runtime()
|
active_site = MozSiteMetadata.from_runtime()
|
||||||
if active_site.site_name == self._site_name:
|
if active_site.site_name == self._site_name:
|
||||||
|
print(result.reason, file=sys.stderr)
|
||||||
raise Exception(
|
raise Exception(
|
||||||
f'The "{self._site_name}" site is out-of-date, even though it has '
|
f'The "{self._site_name}" site is out-of-date, even though it has '
|
||||||
f"already been activated. Was it modified while this Mach process "
|
f"already been activated. Was it modified while this Mach process "
|
||||||
@ -1201,8 +1209,12 @@ def _is_venv_up_to_date(
|
|||||||
expected_metadata,
|
expected_metadata,
|
||||||
):
|
):
|
||||||
if not os.path.exists(target_venv.prefix):
|
if not os.path.exists(target_venv.prefix):
|
||||||
return False
|
return SiteUpToDateResult(False, f'"{target_venv.prefix}" does not exist')
|
||||||
|
|
||||||
|
# Modifications to any of the following files mean the virtualenv should be
|
||||||
|
# rebuilt:
|
||||||
|
# * The `virtualenv` package
|
||||||
|
# * Any of our requirements manifest files
|
||||||
virtualenv_package = os.path.join(
|
virtualenv_package = os.path.join(
|
||||||
topsrcdir,
|
topsrcdir,
|
||||||
"third_party",
|
"third_party",
|
||||||
@ -1212,41 +1224,50 @@ def _is_venv_up_to_date(
|
|||||||
"version.py",
|
"version.py",
|
||||||
)
|
)
|
||||||
deps = [virtualenv_package] + requirements.requirements_paths
|
deps = [virtualenv_package] + requirements.requirements_paths
|
||||||
|
|
||||||
# Modifications to any of the following files mean the virtualenv should be
|
|
||||||
# rebuilt:
|
|
||||||
# * This file
|
|
||||||
# * The `virtualenv` package
|
|
||||||
# * Any of our requirements manifest files
|
|
||||||
metadata_mtime = os.path.getmtime(
|
metadata_mtime = os.path.getmtime(
|
||||||
os.path.join(target_venv.prefix, METADATA_FILENAME)
|
os.path.join(target_venv.prefix, METADATA_FILENAME)
|
||||||
)
|
)
|
||||||
dep_mtime = max(os.path.getmtime(p) for p in deps)
|
for dep_file in deps:
|
||||||
if dep_mtime > metadata_mtime:
|
if os.path.getmtime(dep_file) > metadata_mtime:
|
||||||
return False
|
return SiteUpToDateResult(
|
||||||
|
False, f'"{dep_file}" has changed since the virtualenv was created'
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
existing_metadata = MozSiteMetadata.from_path(target_venv.prefix)
|
existing_metadata = MozSiteMetadata.from_path(target_venv.prefix)
|
||||||
except MozSiteMetadataOutOfDateError:
|
except MozSiteMetadataOutOfDateError as e:
|
||||||
# The metadata is missing required fields, so must be out-of-date.
|
# The metadata is missing required fields, so must be out-of-date.
|
||||||
return False
|
return SiteUpToDateResult(False, str(e))
|
||||||
|
|
||||||
if existing_metadata != expected_metadata:
|
if existing_metadata != expected_metadata:
|
||||||
# The metadata doesn't exist or some fields have different values.
|
# The metadata doesn't exist or some fields have different values.
|
||||||
return False
|
return SiteUpToDateResult(
|
||||||
|
False,
|
||||||
|
f"The existing metadata on-disk ({vars(existing_metadata)}) does not match "
|
||||||
|
f"the expected metadata ({vars(expected_metadata)}",
|
||||||
|
)
|
||||||
|
|
||||||
platlib_site_packages_dir = target_venv.resolve_sysconfig_packages_path("platlib")
|
platlib_site_packages_dir = target_venv.resolve_sysconfig_packages_path("platlib")
|
||||||
|
pthfile_path = os.path.join(platlib_site_packages_dir, PTH_FILENAME)
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(platlib_site_packages_dir, PTH_FILENAME)) as file:
|
with open(pthfile_path) as file:
|
||||||
current_pthfile_contents = file.read().strip()
|
current_pthfile_contents = file.read().strip()
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
return False
|
return SiteUpToDateResult(False, f'No pthfile found at "{pthfile_path}"')
|
||||||
|
|
||||||
expected_pthfile_contents = "\n".join(expected_pthfile_lines)
|
expected_pthfile_contents = "\n".join(expected_pthfile_lines)
|
||||||
if current_pthfile_contents != expected_pthfile_contents:
|
if current_pthfile_contents != expected_pthfile_contents:
|
||||||
return False
|
return SiteUpToDateResult(
|
||||||
|
False,
|
||||||
|
f'The pthfile at "{pthfile_path}" does not match the expected value.\n'
|
||||||
|
f"# --- on-disk pthfile: ---\n"
|
||||||
|
f"{current_pthfile_contents}\n"
|
||||||
|
f"# --- expected pthfile contents ---\n"
|
||||||
|
f"{expected_pthfile_contents}\n"
|
||||||
|
f"# ---",
|
||||||
|
)
|
||||||
|
|
||||||
return True
|
return SiteUpToDateResult(True)
|
||||||
|
|
||||||
|
|
||||||
def activate_virtualenv(virtualenv: PythonVirtualenv):
|
def activate_virtualenv(virtualenv: PythonVirtualenv):
|
||||||
|
Loading…
Reference in New Issue
Block a user