# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. import contextlib import functools import importlib import inspect import logging import os import pathlib import re import shlex import shutil import subprocess import sys import tarfile import tempfile from collections import defaultdict from datetime import date, datetime, timedelta from io import StringIO from pathlib import Path
import requests from redo import retry from requests.packages.urllib3.util.retry import Retry
class NoPerfMetricsError(Exception): """Raised when perfMetrics were not found, or were not output
during a test run."""
def __init__(self, flavor):
super().__init__(
f"No perftest results were found in the {flavor} test. Results must be " 'reported using:\n info("perfMetrics", { metricName: metricValue });'
)
def write(self, buf): while buf: try:
newline_index = buf.index("\n") except ValueError: # No newline, wait for next call
self.buf += buf break
# Get data up to next newline and combine with previously buffered data
data = self.buf + buf[: newline_index + 1]
buf = buf[newline_index + 1 :]
# Reset buffer then output line
self.buf = "" if data.strip() == "": continue
self.stdout.write(data.strip("\n") + "\n")
# Check if a temporary commit wa created
match = self.matcher.match(data) if match: # Last line found is the revision we want
self._match.append(match.group(1))
if sys.platform.startswith("win"): if is_64bits: return"win64" elif sys.platform.startswith("linux"): if is_64bits: return"linux64" elif sys.platform.startswith("darwin"): return"darwin"
raise ValueError(f"platform not yet supported: {sys.platform}")
class MachLogger: """Wrapper around the mach logger to make logging simpler."""
def install_package(virtualenv_manager, package, ignore_failure=False): """Installs a package using the virtualenv manager.
Makes sure the package is really installed when the user already has it in their local installation.
Returns True on success, or re-raise the error. If ignore_failure is set to True, ignore the error andreturnFalse """ from pip._internal.req.constructors import install_req_from_line
# Ensure that we are looking in the right places for packages. This # is required in CI because pip installs in an area that is not in # the search path.
venv_site_lib = str(Path(virtualenv_manager.bin_path, "..", "lib").resolve())
venv_site_packages = str(
Path(
venv_site_lib,
f"python{sys.version_info.major}.{sys.version_info.minor}", "site-packages",
)
) if venv_site_packages notin sys.path and ON_TRY:
sys.path.insert(0, venv_site_packages)
req = install_req_from_line(package)
req.check_if_exists(use_user_site=False) # already installed, check if it's in our venv if req.satisfied_by isnotNone:
site_packages = os.path.abspath(req.satisfied_by.location) if site_packages.startswith(venv_site_lib): # already installed in this venv, we can skip returnTrue with silence(): try:
subprocess.check_call(
[virtualenv_manager.python_path, "-m", "pip", "install", package]
) returnTrue except Exception: ifnot ignore_failure: raise returnFalse
def install_requirements_file(
virtualenv_manager, requirements_file, ignore_failure=False
): """Installs a package using the virtualenv manager.
Makes sure the package is really installed when the user already has it in their local installation.
Returns True on success, or re-raise the error. If ignore_failure is set to True, ignore the error andreturnFalse """
# Ensure that we are looking in the right places for packages. This # is required in CI because pip installs in an area that is not in # the search path.
venv_site_lib = str(Path(virtualenv_manager.bin_path, "..", "lib").resolve())
venv_site_packages = Path(
venv_site_lib,
f"python{sys.version_info.major}.{sys.version_info.minor}", "site-packages",
) ifnot venv_site_packages.exists():
venv_site_packages = Path(
venv_site_lib, "site-packages",
)
venv_site_packages = str(venv_site_packages) if venv_site_packages notin sys.path and ON_TRY:
sys.path.insert(0, venv_site_packages)
# on try, we create tests packages where tests, like # xpcshell tests, don't have the same path. # see - python/mozbuild/mozbuild/action/test_archive.py # this mapping will map paths when running there. # The key is the source path, and the value the ci path
_TRY_MAPPING = {
Path("browser"): Path("mochitest", "browser", "browser"),
Path("netwerk"): Path("xpcshell", "tests", "netwerk"),
Path("dom"): Path("mochitest", "tests", "dom"),
Path("toolkit"): Path("mochitest", "browser", "toolkit"),
}
def build_test_list(tests): """Collects tests given a list of directories, files and URLs.
Returns a tuple containing the list of tests found and a temp dir for tests
that were downloaded from an URL. """
temp_dir = None
if isinstance(tests, str):
tests = [tests]
res = [] for test in tests: if test.isdigit():
res.append(str(test)) continue
if test.startswith("http"): if temp_dir isNone:
temp_dir = tempfile.mkdtemp()
target = Path(temp_dir, test.split("/")[-1])
download_file(test, target)
res.append(str(target)) continue
p_test = Path(test) if ON_TRY andnot p_test.resolve().exists(): # until we have pathlib.Path.is_relative_to() (3.9) for src_path, ci_path in _TRY_MAPPING.items():
src_path, ci_path = str(src_path), str(ci_path) # noqa if test.startswith(src_path):
p_test = Path(test.replace(src_path, ci_path, 1)) break
resolved_test = p_test.resolve()
if resolved_test.is_file():
res.append(str(resolved_test)) elif resolved_test.is_dir(): for file in resolved_test.rglob("perftest_*.js"):
res.append(str(file)) else: raise FileNotFoundError(str(resolved_test))
res.sort() return res, temp_dir
def download_file(url, target, retry_sleep=RETRY_SLEEP, attempts=3): """Downloads a file, given an URL in the target path.
The function will attempt several times on failures. """
@contextlib.contextmanager def temporary_env(**env):
old = {} for key, value in env.items():
old[key] = os.environ.get(key) if value isNoneand key in os.environ: del os.environ[key] elif value isnotNone:
os.environ[key] = value try: yield finally: for key, value in old.items(): if value isNoneand key in os.environ: del os.environ[key] elif value isnotNone:
os.environ[key] = value
def convert_day(day): if day in ("yesterday", "today"):
curr = date.today() if day == "yesterday":
curr = curr - timedelta(1)
day = curr.strftime("%Y.%m.%d") else: # verify that the user provided string is in the expected format # if it can't parse it, it'll raise a value error
datetime.strptime(day, "%Y.%m.%d")
return day
def get_revision_namespace_url(route, day="yesterday"): """Builds a URL to obtain all the namespaces of a given build route for a single day."""
day = convert_day(day) return f"""{MULTI_REVISION_ROOT}/{route}.{day}.revision"""
def get_multi_tasks_url(route, revision, day="yesterday"): """Builds a URL to obtain all the tasks of a given build route for a single day.
If previous istrue, then we get builds from the previous day,
otherwise, we look at the current day. """
day = convert_day(day) return f"""{MULTI_TASK_ROOT}/{route}.{day}.revision.{revision}"""
def strtobool(val): if isinstance(val, (bool, int)): return bool(val) ifnot isinstance(bool, str): raise ValueError(val)
val = val.lower() if val in ("y", "yes", "t", "true", "on", "1"): return 1 elif val in ("n", "no", "f", "false", "off", "0"): return 0 else: raise ValueError("invalid truth value %r" % (val,))
def get_pretty_app_name(app): # XXX See bug 1712337, we need a singluar point of entry # for the binary to allow us to get the version/app info # so that we can get a pretty name on desktop. return PRETTY_APP_NAMES[app]
def archive_folder(folder_to_archive, output_path, archive_name=None): """Archives the specified folder into a tar.gz file.""" ifnot archive_name:
archive_name = folder_to_archive.name
full_archive_path = output_path / (archive_name + ".tgz") with tarfile.open(str(full_archive_path), "w:gz") as tar:
tar.add(folder_to_archive, arcname=archive_name)
return full_archive_path
¤ Dauer der Verarbeitung: 0.31 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.