mirror of
https://github.com/servo/servo.git
synced 2025-10-02 01:29:15 +01:00
mach: add type annotation in function for 'python/servo' folder (#38592)
This part of function strictly typed in python by adding ANN rule in ruff, similiar to #38531. Testing: `./mach test-tidy` Fixes: Not related to any issues --------- Signed-off-by: Jerens Lensun <jerensslensun@gmail.com>
This commit is contained in:
parent
494493ceb7
commit
a4fdbe8be3
18 changed files with 167 additions and 146 deletions
|
@ -31,7 +31,6 @@ ignore = [
|
||||||
|
|
||||||
[tool.ruff.lint.per-file-ignores]
|
[tool.ruff.lint.per-file-ignores]
|
||||||
"!python/**/**.py" = ["ANN"]
|
"!python/**/**.py" = ["ANN"]
|
||||||
"python/servo/**.py" = ["ANN"]
|
|
||||||
"**/test.py" = ["ANN"]
|
"**/test.py" = ["ANN"]
|
||||||
"**/*_tests.py" = ["ANN"]
|
"**/*_tests.py" = ["ANN"]
|
||||||
"**/tests/**/*.py" = ["ANN"]
|
"**/tests/**/*.py" = ["ANN"]
|
||||||
|
|
|
@ -40,7 +40,7 @@ class MachCommands(CommandBase):
|
||||||
@CommandArgument("--force", "-f", action="store_true", help="Boostrap without confirmation")
|
@CommandArgument("--force", "-f", action="store_true", help="Boostrap without confirmation")
|
||||||
@CommandArgument("--skip-platform", action="store_true", help="Skip platform bootstrapping.")
|
@CommandArgument("--skip-platform", action="store_true", help="Skip platform bootstrapping.")
|
||||||
@CommandArgument("--skip-lints", action="store_true", help="Skip tool necessary for linting.")
|
@CommandArgument("--skip-lints", action="store_true", help="Skip tool necessary for linting.")
|
||||||
def bootstrap(self, force=False, skip_platform=False, skip_lints=False) -> int:
|
def bootstrap(self, force: bool = False, skip_platform: bool = False, skip_lints: bool = False) -> int:
|
||||||
# Note: This entry point isn't actually invoked by ./mach bootstrap.
|
# Note: This entry point isn't actually invoked by ./mach bootstrap.
|
||||||
# ./mach bootstrap calls mach_bootstrap.bootstrap_command_only so that
|
# ./mach bootstrap calls mach_bootstrap.bootstrap_command_only so that
|
||||||
# it can install dependencies without needing mach's dependencies
|
# it can install dependencies without needing mach's dependencies
|
||||||
|
@ -57,7 +57,7 @@ class MachCommands(CommandBase):
|
||||||
category="bootstrap",
|
category="bootstrap",
|
||||||
)
|
)
|
||||||
@CommandArgument("--force", "-f", action="store_true", help="Boostrap without confirmation")
|
@CommandArgument("--force", "-f", action="store_true", help="Boostrap without confirmation")
|
||||||
def bootstrap_gstreamer(self, force=False) -> int:
|
def bootstrap_gstreamer(self, force: bool = False) -> int:
|
||||||
try:
|
try:
|
||||||
servo.platform.get().bootstrap_gstreamer(force)
|
servo.platform.get().bootstrap_gstreamer(force)
|
||||||
except NotImplementedError as exception:
|
except NotImplementedError as exception:
|
||||||
|
@ -66,7 +66,7 @@ class MachCommands(CommandBase):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@Command("update-hsts-preload", description="Download the HSTS preload list", category="bootstrap")
|
@Command("update-hsts-preload", description="Download the HSTS preload list", category="bootstrap")
|
||||||
def bootstrap_hsts_preload(self, force=False) -> None:
|
def bootstrap_hsts_preload(self, force: bool = False) -> None:
|
||||||
preload_filename = "hsts_preload.fstmap"
|
preload_filename = "hsts_preload.fstmap"
|
||||||
preload_path = path.join(self.context.topdir, "resources")
|
preload_path = path.join(self.context.topdir, "resources")
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ class MachCommands(CommandBase):
|
||||||
description="Download the public domains list and update resources/public_domains.txt",
|
description="Download the public domains list and update resources/public_domains.txt",
|
||||||
category="bootstrap",
|
category="bootstrap",
|
||||||
)
|
)
|
||||||
def bootstrap_pub_suffix(self, force=False) -> None:
|
def bootstrap_pub_suffix(self, force: bool = False) -> None:
|
||||||
list_url = "https://publicsuffix.org/list/public_suffix_list.dat"
|
list_url = "https://publicsuffix.org/list/public_suffix_list.dat"
|
||||||
dst_filename = path.join(self.context.topdir, "resources", "public_domains.txt")
|
dst_filename = path.join(self.context.topdir, "resources", "public_domains.txt")
|
||||||
not_implemented_case = re.compile(r"^[^*]+\*")
|
not_implemented_case = re.compile(r"^[^*]+\*")
|
||||||
|
|
|
@ -18,7 +18,7 @@ import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from time import time
|
from time import time
|
||||||
from typing import Optional, List, Dict, Union
|
from typing import Optional, Union, Any
|
||||||
|
|
||||||
from mach.decorators import (
|
from mach.decorators import (
|
||||||
CommandArgument,
|
CommandArgument,
|
||||||
|
@ -54,7 +54,7 @@ SUPPORTED_TSAN_TARGETS = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def get_rustc_llvm_version() -> Optional[List[int]]:
|
def get_rustc_llvm_version() -> Optional[list[int]]:
|
||||||
"""Determine the LLVM version of `rustc` and return it as a List[major, minor, patch, ...]
|
"""Determine the LLVM version of `rustc` and return it as a List[major, minor, patch, ...]
|
||||||
|
|
||||||
In some cases we want to ensure that the LLVM version of rustc and clang match, e.g.
|
In some cases we want to ensure that the LLVM version of rustc and clang match, e.g.
|
||||||
|
@ -94,14 +94,14 @@ class MachCommands(CommandBase):
|
||||||
def build(
|
def build(
|
||||||
self,
|
self,
|
||||||
build_type: BuildType,
|
build_type: BuildType,
|
||||||
jobs=None,
|
jobs: str | None = None,
|
||||||
params=None,
|
params: list[str] | None = None,
|
||||||
no_package=False,
|
no_package: bool = False,
|
||||||
verbose=False,
|
verbose: bool = False,
|
||||||
very_verbose=False,
|
very_verbose: bool = False,
|
||||||
sanitizer: SanitizerKind = SanitizerKind.NONE,
|
sanitizer: SanitizerKind = SanitizerKind.NONE,
|
||||||
flavor=None,
|
flavor: str | None = None,
|
||||||
**kwargs,
|
**kwargs: Any,
|
||||||
) -> int:
|
) -> int:
|
||||||
opts = params or []
|
opts = params or []
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ class MachCommands(CommandBase):
|
||||||
@CommandArgument("--manifest-path", default=None, help="Path to the manifest to the package to clean")
|
@CommandArgument("--manifest-path", default=None, help="Path to the manifest to the package to clean")
|
||||||
@CommandArgument("--verbose", "-v", action="store_true", help="Print verbose output")
|
@CommandArgument("--verbose", "-v", action="store_true", help="Print verbose output")
|
||||||
@CommandArgument("params", nargs="...", help="Command-line arguments to be passed through to Cargo")
|
@CommandArgument("params", nargs="...", help="Command-line arguments to be passed through to Cargo")
|
||||||
def clean(self, manifest_path=None, params=[], verbose=False) -> None:
|
def clean(self, manifest_path: str | None = None, params: list[str] = [], verbose: bool = False) -> None:
|
||||||
self.ensure_bootstrapped()
|
self.ensure_bootstrapped()
|
||||||
|
|
||||||
virtualenv_path = path.join(self.get_top_dir(), ".venv")
|
virtualenv_path = path.join(self.get_top_dir(), ".venv")
|
||||||
|
@ -215,7 +215,7 @@ class MachCommands(CommandBase):
|
||||||
return check_call(["cargo", "clean"] + opts, env=self.build_env(), verbose=verbose)
|
return check_call(["cargo", "clean"] + opts, env=self.build_env(), verbose=verbose)
|
||||||
|
|
||||||
def build_sanitizer_env(
|
def build_sanitizer_env(
|
||||||
self, env: Dict, opts: List[str], kwargs, target_triple: str, sanitizer: SanitizerKind = SanitizerKind.NONE
|
self, env: dict, opts: list[str], kwargs: Any, target_triple: str, sanitizer: SanitizerKind = SanitizerKind.NONE
|
||||||
) -> None:
|
) -> None:
|
||||||
if sanitizer.is_none():
|
if sanitizer.is_none():
|
||||||
return
|
return
|
||||||
|
|
|
@ -19,6 +19,7 @@ import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tarfile
|
import tarfile
|
||||||
|
from tarfile import TarInfo
|
||||||
import urllib
|
import urllib
|
||||||
import zipfile
|
import zipfile
|
||||||
import urllib.error
|
import urllib.error
|
||||||
|
@ -28,7 +29,8 @@ from enum import Enum
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from os import path
|
from os import path
|
||||||
from subprocess import PIPE, CompletedProcess
|
from subprocess import PIPE, CompletedProcess
|
||||||
from typing import Any, Dict, List, Optional, Union, LiteralString, cast
|
from typing import Any, Optional, Union, LiteralString, cast
|
||||||
|
from collections.abc import Generator, Callable
|
||||||
from xml.etree.ElementTree import XML
|
from xml.etree.ElementTree import XML
|
||||||
|
|
||||||
import toml
|
import toml
|
||||||
|
@ -93,7 +95,7 @@ class BuildType:
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def cd(new_path: str):
|
def cd(new_path: str) -> Generator:
|
||||||
"""Context manager for changing the current working directory"""
|
"""Context manager for changing the current working directory"""
|
||||||
previous_path = os.getcwd()
|
previous_path = os.getcwd()
|
||||||
try:
|
try:
|
||||||
|
@ -104,7 +106,7 @@ def cd(new_path: str):
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def setlocale(name: str):
|
def setlocale(name: str) -> Generator:
|
||||||
"""Context manager for changing the current locale"""
|
"""Context manager for changing the current locale"""
|
||||||
saved_locale = locale.setlocale(locale.LC_ALL)
|
saved_locale = locale.setlocale(locale.LC_ALL)
|
||||||
try:
|
try:
|
||||||
|
@ -113,7 +115,7 @@ def setlocale(name: str):
|
||||||
locale.setlocale(locale.LC_ALL, saved_locale)
|
locale.setlocale(locale.LC_ALL, saved_locale)
|
||||||
|
|
||||||
|
|
||||||
def find_dep_path_newest(package, bin_path):
|
def find_dep_path_newest(package: str, bin_path: str) -> str | None:
|
||||||
deps_path = path.join(path.split(bin_path)[0], "build")
|
deps_path = path.join(path.split(bin_path)[0], "build")
|
||||||
candidates = []
|
candidates = []
|
||||||
with cd(deps_path):
|
with cd(deps_path):
|
||||||
|
@ -126,12 +128,12 @@ def find_dep_path_newest(package, bin_path):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def archive_deterministically(dir_to_archive, dest_archive, prepend_path=None) -> None:
|
def archive_deterministically(dir_to_archive: str, dest_archive: str, prepend_path: str | None = None) -> None:
|
||||||
"""Create a .tar.gz archive in a deterministic (reproducible) manner.
|
"""Create a .tar.gz archive in a deterministic (reproducible) manner.
|
||||||
|
|
||||||
See https://reproducible-builds.org/docs/archives/ for more details."""
|
See https://reproducible-builds.org/docs/archives/ for more details."""
|
||||||
|
|
||||||
def reset(tarinfo):
|
def reset(tarinfo: TarInfo) -> TarInfo:
|
||||||
"""Helper to reset owner/group and modification time for tar entries"""
|
"""Helper to reset owner/group and modification time for tar entries"""
|
||||||
tarinfo.uid = tarinfo.gid = 0
|
tarinfo.uid = tarinfo.gid = 0
|
||||||
tarinfo.uname = tarinfo.gname = "root"
|
tarinfo.uname = tarinfo.gname = "root"
|
||||||
|
@ -177,7 +179,7 @@ def archive_deterministically(dir_to_archive, dest_archive, prepend_path=None) -
|
||||||
os.rename(temp_file, dest_archive)
|
os.rename(temp_file, dest_archive)
|
||||||
|
|
||||||
|
|
||||||
def call(*args, **kwargs) -> int:
|
def call(*args: Any, **kwargs: Any) -> int:
|
||||||
"""Wrap `subprocess.call`, printing the command if verbose=True."""
|
"""Wrap `subprocess.call`, printing the command if verbose=True."""
|
||||||
verbose = kwargs.pop("verbose", False)
|
verbose = kwargs.pop("verbose", False)
|
||||||
if verbose:
|
if verbose:
|
||||||
|
@ -188,7 +190,7 @@ def call(*args, **kwargs) -> int:
|
||||||
return subprocess.call(*args, **kwargs)
|
return subprocess.call(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def check_output(*args, **kwargs) -> Union[str, bytes]:
|
def check_output(*args: Any, **kwargs: Any) -> Union[str, bytes]:
|
||||||
"""Wrap `subprocess.call`, printing the command if verbose=True."""
|
"""Wrap `subprocess.call`, printing the command if verbose=True."""
|
||||||
verbose = kwargs.pop("verbose", False)
|
verbose = kwargs.pop("verbose", False)
|
||||||
if verbose:
|
if verbose:
|
||||||
|
@ -199,7 +201,7 @@ def check_output(*args, **kwargs) -> Union[str, bytes]:
|
||||||
return subprocess.check_output(*args, **kwargs)
|
return subprocess.check_output(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def check_call(*args, **kwargs) -> None:
|
def check_call(*args: Any, **kwargs: Any) -> None:
|
||||||
"""Wrap `subprocess.check_call`, printing the command if verbose=True.
|
"""Wrap `subprocess.check_call`, printing the command if verbose=True.
|
||||||
|
|
||||||
Also fix any unicode-containing `env`, for subprocess"""
|
Also fix any unicode-containing `env`, for subprocess"""
|
||||||
|
@ -239,10 +241,10 @@ def is_linux() -> bool:
|
||||||
|
|
||||||
|
|
||||||
class BuildNotFound(Exception):
|
class BuildNotFound(Exception):
|
||||||
def __init__(self, message) -> None:
|
def __init__(self, message: str) -> None:
|
||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return self.message
|
return self.message
|
||||||
|
|
||||||
|
|
||||||
|
@ -253,7 +255,7 @@ class CommandBase(object):
|
||||||
|
|
||||||
target: BuildTarget
|
target: BuildTarget
|
||||||
|
|
||||||
def __init__(self, context) -> None:
|
def __init__(self, context: Any) -> None:
|
||||||
self.context = context
|
self.context = context
|
||||||
self.enable_media = False
|
self.enable_media = False
|
||||||
self.features = []
|
self.features = []
|
||||||
|
@ -321,7 +323,7 @@ class CommandBase(object):
|
||||||
|
|
||||||
_rust_toolchain = None
|
_rust_toolchain = None
|
||||||
|
|
||||||
def rust_toolchain(self):
|
def rust_toolchain(self) -> str:
|
||||||
if self._rust_toolchain:
|
if self._rust_toolchain:
|
||||||
return self._rust_toolchain
|
return self._rust_toolchain
|
||||||
|
|
||||||
|
@ -329,7 +331,7 @@ class CommandBase(object):
|
||||||
self._rust_toolchain = toml.load(toolchain_file)["toolchain"]["channel"]
|
self._rust_toolchain = toml.load(toolchain_file)["toolchain"]["channel"]
|
||||||
return self._rust_toolchain
|
return self._rust_toolchain
|
||||||
|
|
||||||
def get_top_dir(self):
|
def get_top_dir(self) -> str:
|
||||||
return self.context.topdir
|
return self.context.topdir
|
||||||
|
|
||||||
def get_binary_path(self, build_type: BuildType, sanitizer: SanitizerKind = SanitizerKind.NONE) -> str:
|
def get_binary_path(self, build_type: BuildType, sanitizer: SanitizerKind = SanitizerKind.NONE) -> str:
|
||||||
|
@ -356,7 +358,7 @@ class CommandBase(object):
|
||||||
if os.path.exists(mounted_volume):
|
if os.path.exists(mounted_volume):
|
||||||
self.detach_volume(mounted_volume)
|
self.detach_volume(mounted_volume)
|
||||||
|
|
||||||
def mount_dmg(self, dmg_path) -> None:
|
def mount_dmg(self, dmg_path: str) -> None:
|
||||||
print("Mounting dmg {}".format(dmg_path))
|
print("Mounting dmg {}".format(dmg_path))
|
||||||
try:
|
try:
|
||||||
subprocess.check_call(["hdiutil", "attach", dmg_path])
|
subprocess.check_call(["hdiutil", "attach", dmg_path])
|
||||||
|
@ -394,7 +396,7 @@ class CommandBase(object):
|
||||||
return path.join(destination_folder, "servo", "servo")
|
return path.join(destination_folder, "servo", "servo")
|
||||||
return path.join(destination_folder, "servo")
|
return path.join(destination_folder, "servo")
|
||||||
|
|
||||||
def get_nightly_binary_path(self, nightly_date) -> str | None:
|
def get_nightly_binary_path(self, nightly_date: str | None) -> str | None:
|
||||||
if nightly_date is None:
|
if nightly_date is None:
|
||||||
return
|
return
|
||||||
if not nightly_date:
|
if not nightly_date:
|
||||||
|
@ -462,7 +464,7 @@ class CommandBase(object):
|
||||||
|
|
||||||
return self.get_executable(destination_folder)
|
return self.get_executable(destination_folder)
|
||||||
|
|
||||||
def msvc_package_dir(self, package) -> str:
|
def msvc_package_dir(self, package: str) -> str:
|
||||||
return servo.platform.windows.get_dependency_dir(package)
|
return servo.platform.windows.get_dependency_dir(package)
|
||||||
|
|
||||||
def build_env(self) -> dict[str, str]:
|
def build_env(self) -> dict[str, str]:
|
||||||
|
@ -531,8 +533,11 @@ class CommandBase(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def common_command_arguments(
|
def common_command_arguments(
|
||||||
build_configuration=False, build_type=False, binary_selection=False, package_configuration=False
|
build_configuration: bool = False,
|
||||||
):
|
build_type: bool = False,
|
||||||
|
binary_selection: bool = False,
|
||||||
|
package_configuration: bool = False,
|
||||||
|
) -> Callable:
|
||||||
decorators = []
|
decorators = []
|
||||||
if build_type or binary_selection:
|
if build_type or binary_selection:
|
||||||
decorators += [
|
decorators += [
|
||||||
|
@ -654,8 +659,8 @@ class CommandBase(object):
|
||||||
CommandArgument("--nightly", "-n", default=None, help="Specify a YYYY-MM-DD nightly build to run"),
|
CommandArgument("--nightly", "-n", default=None, help="Specify a YYYY-MM-DD nightly build to run"),
|
||||||
]
|
]
|
||||||
|
|
||||||
def decorator_function(original_function):
|
def decorator_function(original_function: Callable) -> Callable:
|
||||||
def configuration_decorator(self, *args, **kwargs):
|
def configuration_decorator(self: CommandBase, *args: Any, **kwargs: Any) -> Callable:
|
||||||
if build_type or binary_selection:
|
if build_type or binary_selection:
|
||||||
# If `build_type` already exists in kwargs we are doing a recursive dispatch.
|
# If `build_type` already exists in kwargs we are doing a recursive dispatch.
|
||||||
if "build_type" not in kwargs:
|
if "build_type" not in kwargs:
|
||||||
|
@ -680,7 +685,10 @@ class CommandBase(object):
|
||||||
kwargs["servo_binary"] = (
|
kwargs["servo_binary"] = (
|
||||||
kwargs.get("bin")
|
kwargs.get("bin")
|
||||||
or self.get_nightly_binary_path(kwargs.get("nightly"))
|
or self.get_nightly_binary_path(kwargs.get("nightly"))
|
||||||
or self.get_binary_path(kwargs.get("build_type"), sanitizer=kwargs.get("sanitizer"))
|
or self.get_binary_path(
|
||||||
|
cast(BuildType, kwargs.get("build_type")),
|
||||||
|
sanitizer=cast(SanitizerKind, kwargs.get("sanitizer")),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
kwargs.pop("bin")
|
kwargs.pop("bin")
|
||||||
kwargs.pop("nightly")
|
kwargs.pop("nightly")
|
||||||
|
@ -699,8 +707,8 @@ class CommandBase(object):
|
||||||
return decorator_function
|
return decorator_function
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def allow_target_configuration(original_function):
|
def allow_target_configuration(original_function: Callable) -> Callable:
|
||||||
def target_configuration_decorator(self, *args, **kwargs):
|
def target_configuration_decorator(self: CommandBase, *args: Any, **kwargs: Any) -> Callable:
|
||||||
self.configure_build_target(kwargs, suppress_log=True)
|
self.configure_build_target(kwargs, suppress_log=True)
|
||||||
kwargs.pop("target", False)
|
kwargs.pop("target", False)
|
||||||
kwargs.pop("android", False)
|
kwargs.pop("android", False)
|
||||||
|
@ -741,7 +749,7 @@ class CommandBase(object):
|
||||||
else:
|
else:
|
||||||
return BuildType.custom(profile)
|
return BuildType.custom(profile)
|
||||||
|
|
||||||
def configure_build_target(self, kwargs: Dict[str, Any], suppress_log: bool = False) -> None:
|
def configure_build_target(self, kwargs: dict[str, Any], suppress_log: bool = False) -> None:
|
||||||
if hasattr(self.context, "target"):
|
if hasattr(self.context, "target"):
|
||||||
# This call is for a dispatched command and we've already configured
|
# This call is for a dispatched command and we've already configured
|
||||||
# the target, so just use it.
|
# the target, so just use it.
|
||||||
|
@ -778,7 +786,7 @@ class CommandBase(object):
|
||||||
if self.target.is_cross_build() and not suppress_log:
|
if self.target.is_cross_build() and not suppress_log:
|
||||||
print(f"Targeting '{self.target.triple()}' for cross-compilation")
|
print(f"Targeting '{self.target.triple()}' for cross-compilation")
|
||||||
|
|
||||||
def is_media_enabled(self, media_stack: Optional[str]):
|
def is_media_enabled(self, media_stack: Optional[str]) -> bool:
|
||||||
"""Determine whether media is enabled based on the value of the build target
|
"""Determine whether media is enabled based on the value of the build target
|
||||||
platform and the value of the '--media-stack' command-line argument.
|
platform and the value of the '--media-stack' command-line argument.
|
||||||
Returns true if media is enabled."""
|
Returns true if media is enabled."""
|
||||||
|
@ -803,16 +811,16 @@ class CommandBase(object):
|
||||||
def run_cargo_build_like_command(
|
def run_cargo_build_like_command(
|
||||||
self,
|
self,
|
||||||
command: str,
|
command: str,
|
||||||
cargo_args: List[str],
|
cargo_args: list[str],
|
||||||
env=None,
|
env: dict[str, Any] | None = None,
|
||||||
verbose=False,
|
verbose: bool = False,
|
||||||
debug_mozjs=False,
|
debug_mozjs: bool = False,
|
||||||
with_debug_assertions=False,
|
with_debug_assertions: bool = False,
|
||||||
with_frame_pointer=False,
|
with_frame_pointer: bool = False,
|
||||||
use_crown=False,
|
use_crown: bool = False,
|
||||||
capture_output=False,
|
capture_output: bool = False,
|
||||||
target_override: Optional[str] = None,
|
target_override: Optional[str] = None,
|
||||||
**_kwargs,
|
**_kwargs: Any,
|
||||||
) -> CompletedProcess[bytes] | int:
|
) -> CompletedProcess[bytes] | int:
|
||||||
env = cast(dict[str, str], env or self.build_env())
|
env = cast(dict[str, str], env or self.build_env())
|
||||||
|
|
||||||
|
@ -888,14 +896,14 @@ class CommandBase(object):
|
||||||
|
|
||||||
return call(["cargo", command] + args + cargo_args, env=env, verbose=verbose)
|
return call(["cargo", command] + args + cargo_args, env=env, verbose=verbose)
|
||||||
|
|
||||||
def android_adb_path(self, env) -> LiteralString:
|
def android_adb_path(self, env: dict[str, Any]) -> LiteralString:
|
||||||
if "ANDROID_SDK_ROOT" in env:
|
if "ANDROID_SDK_ROOT" in env:
|
||||||
sdk_adb = path.join(env["ANDROID_SDK_ROOT"], "platform-tools", "adb")
|
sdk_adb = path.join(env["ANDROID_SDK_ROOT"], "platform-tools", "adb")
|
||||||
if path.exists(sdk_adb):
|
if path.exists(sdk_adb):
|
||||||
return sdk_adb
|
return sdk_adb
|
||||||
return "adb"
|
return "adb"
|
||||||
|
|
||||||
def android_emulator_path(self, env) -> LiteralString:
|
def android_emulator_path(self, env: dict[str, Any]) -> LiteralString:
|
||||||
if "ANDROID_SDK_ROOT" in env:
|
if "ANDROID_SDK_ROOT" in env:
|
||||||
sdk_adb = path.join(env["ANDROID_SDK_ROOT"], "emulator", "emulator")
|
sdk_adb = path.join(env["ANDROID_SDK_ROOT"], "emulator", "emulator")
|
||||||
if path.exists(sdk_adb):
|
if path.exists(sdk_adb):
|
||||||
|
@ -919,7 +927,7 @@ class CommandBase(object):
|
||||||
if self.target.triple() not in installed_targets:
|
if self.target.triple() not in installed_targets:
|
||||||
check_call(["rustup", "target", "add", self.target.triple()], cwd=self.context.topdir)
|
check_call(["rustup", "target", "add", self.target.triple()], cwd=self.context.topdir)
|
||||||
|
|
||||||
def ensure_clobbered(self, target_dir=None) -> None:
|
def ensure_clobbered(self, target_dir: str | None = None) -> None:
|
||||||
if target_dir is None:
|
if target_dir is None:
|
||||||
target_dir = util.get_target_dir()
|
target_dir = util.get_target_dir()
|
||||||
auto = True if os.environ.get("AUTOCLOBBER", False) else False
|
auto = True if os.environ.get("AUTOCLOBBER", False) else False
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
from subprocess import CompletedProcess
|
from subprocess import CompletedProcess
|
||||||
import json
|
import json
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from mach.decorators import (
|
from mach.decorators import (
|
||||||
Command,
|
Command,
|
||||||
|
@ -27,7 +28,7 @@ class MachCommands(CommandBase):
|
||||||
"params", default=None, nargs="...", help="Command-line arguments to be passed through to cargo check"
|
"params", default=None, nargs="...", help="Command-line arguments to be passed through to cargo check"
|
||||||
)
|
)
|
||||||
@CommandBase.common_command_arguments(build_configuration=True, build_type=False)
|
@CommandBase.common_command_arguments(build_configuration=True, build_type=False)
|
||||||
def check(self, params, **kwargs) -> int:
|
def check(self, params: list[str], **kwargs: Any) -> int:
|
||||||
if not params:
|
if not params:
|
||||||
params = []
|
params = []
|
||||||
|
|
||||||
|
@ -42,7 +43,7 @@ class MachCommands(CommandBase):
|
||||||
|
|
||||||
@Command("rustc", description="Run the Rust compiler", category="devenv")
|
@Command("rustc", description="Run the Rust compiler", category="devenv")
|
||||||
@CommandArgument("params", default=None, nargs="...", help="Command-line arguments to be passed through to rustc")
|
@CommandArgument("params", default=None, nargs="...", help="Command-line arguments to be passed through to rustc")
|
||||||
def rustc(self, params) -> int:
|
def rustc(self, params: list[str]) -> int:
|
||||||
if params is None:
|
if params is None:
|
||||||
params = []
|
params = []
|
||||||
|
|
||||||
|
@ -54,7 +55,7 @@ class MachCommands(CommandBase):
|
||||||
"params", default=None, nargs="...", help="Command-line arguments to be passed through to cargo-fix"
|
"params", default=None, nargs="...", help="Command-line arguments to be passed through to cargo-fix"
|
||||||
)
|
)
|
||||||
@CommandBase.common_command_arguments(build_configuration=True, build_type=False)
|
@CommandBase.common_command_arguments(build_configuration=True, build_type=False)
|
||||||
def cargo_fix(self, params, **kwargs) -> int:
|
def cargo_fix(self, params: list[str], **kwargs: Any) -> int:
|
||||||
if not params:
|
if not params:
|
||||||
params = []
|
params = []
|
||||||
|
|
||||||
|
@ -73,7 +74,7 @@ class MachCommands(CommandBase):
|
||||||
help="Emit the clippy warnings in the Github Actions annotations format",
|
help="Emit the clippy warnings in the Github Actions annotations format",
|
||||||
)
|
)
|
||||||
@CommandBase.common_command_arguments(build_configuration=True, build_type=False)
|
@CommandBase.common_command_arguments(build_configuration=True, build_type=False)
|
||||||
def cargo_clippy(self, params, github_annotations=False, **kwargs) -> int:
|
def cargo_clippy(self, params: list[str], github_annotations: bool = False, **kwargs: Any) -> int:
|
||||||
if not params:
|
if not params:
|
||||||
params = []
|
params = []
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import os.path
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from typing import Set
|
from collections.abc import Set
|
||||||
|
|
||||||
# This file is called as a script from components/servo/build.rs, so
|
# This file is called as a script from components/servo/build.rs, so
|
||||||
# we need to explicitly modify the search path here.
|
# we need to explicitly modify the search path here.
|
||||||
|
|
|
@ -18,7 +18,7 @@ import random
|
||||||
test_summary = {test.Status.KILLED: 0, test.Status.SURVIVED: 0, test.Status.SKIPPED: 0, test.Status.UNEXPECTED: 0}
|
test_summary = {test.Status.KILLED: 0, test.Status.SURVIVED: 0, test.Status.SKIPPED: 0, test.Status.UNEXPECTED: 0}
|
||||||
|
|
||||||
|
|
||||||
def get_folders_list(path):
|
def get_folders_list(path: str) -> list[str]:
|
||||||
folder_list = []
|
folder_list = []
|
||||||
for filename in listdir(path):
|
for filename in listdir(path):
|
||||||
if isdir(join(path, filename)):
|
if isdir(join(path, filename)):
|
||||||
|
|
|
@ -11,14 +11,14 @@ import fileinput
|
||||||
import re
|
import re
|
||||||
from re import Match
|
from re import Match
|
||||||
import random
|
import random
|
||||||
from typing import Iterator
|
from collections.abc import Iterator
|
||||||
|
|
||||||
|
|
||||||
def is_comment(line: str) -> Match[str] | None:
|
def is_comment(line: str) -> Match[str] | None:
|
||||||
return re.search(r"\/\/.*", line)
|
return re.search(r"\/\/.*", line)
|
||||||
|
|
||||||
|
|
||||||
def init_variables(if_blocks):
|
def init_variables(if_blocks: list[int]) -> tuple[int, int, int, int, int]:
|
||||||
random_index = random.randint(0, len(if_blocks) - 1)
|
random_index = random.randint(0, len(if_blocks) - 1)
|
||||||
start_counter = 0
|
start_counter = 0
|
||||||
end_counter = 0
|
end_counter = 0
|
||||||
|
@ -27,7 +27,7 @@ def init_variables(if_blocks):
|
||||||
return random_index, start_counter, end_counter, lines_to_delete, line_to_mutate
|
return random_index, start_counter, end_counter, lines_to_delete, line_to_mutate
|
||||||
|
|
||||||
|
|
||||||
def deleteStatements(file_name, line_numbers) -> None:
|
def deleteStatements(file_name: str, line_numbers: list[int]) -> None:
|
||||||
for line in fileinput.input(file_name, inplace=True):
|
for line in fileinput.input(file_name, inplace=True):
|
||||||
if fileinput.lineno() not in line_numbers:
|
if fileinput.lineno() not in line_numbers:
|
||||||
print(line.rstrip())
|
print(line.rstrip())
|
||||||
|
@ -38,7 +38,7 @@ class Strategy:
|
||||||
self._strategy_name = ""
|
self._strategy_name = ""
|
||||||
self._replace_strategy = {}
|
self._replace_strategy = {}
|
||||||
|
|
||||||
def mutate(self, file_name):
|
def mutate(self, file_name: str) -> int:
|
||||||
line_numbers = []
|
line_numbers = []
|
||||||
for line in fileinput.input(file_name):
|
for line in fileinput.input(file_name):
|
||||||
if not is_comment(line) and re.search(self._replace_strategy["regex"], line):
|
if not is_comment(line) and re.search(self._replace_strategy["regex"], line):
|
||||||
|
@ -140,7 +140,7 @@ class DeleteIfBlock(Strategy):
|
||||||
self.if_block = r"^\s+if\s(.+)\s\{"
|
self.if_block = r"^\s+if\s(.+)\s\{"
|
||||||
self.else_block = r"\selse(.+)\{"
|
self.else_block = r"\selse(.+)\{"
|
||||||
|
|
||||||
def mutate(self, file_name):
|
def mutate(self, file_name: str) -> int:
|
||||||
code_lines = []
|
code_lines = []
|
||||||
if_blocks = []
|
if_blocks = []
|
||||||
for line in fileinput.input(file_name):
|
for line in fileinput.input(file_name):
|
||||||
|
@ -192,8 +192,8 @@ def get_strategies() -> Iterator[Strategy]:
|
||||||
|
|
||||||
|
|
||||||
class Mutator:
|
class Mutator:
|
||||||
def __init__(self, strategy) -> None:
|
def __init__(self, strategy: Strategy) -> None:
|
||||||
self._strategy = strategy
|
self._strategy = strategy
|
||||||
|
|
||||||
def mutate(self, file_name):
|
def mutate(self, file_name: str) -> int:
|
||||||
return self._strategy.mutate(file_name)
|
return self._strategy.mutate(file_name)
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import random
|
import random
|
||||||
import time
|
import time
|
||||||
from typing import List
|
from collections.abc import Generator
|
||||||
from github import Github
|
from github import Github
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
|
@ -68,14 +68,14 @@ PACKAGES = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def packages_for_platform(platform):
|
def packages_for_platform(platform: str) -> Generator[str]:
|
||||||
target_dir = get_target_dir()
|
target_dir = get_target_dir()
|
||||||
|
|
||||||
for package in PACKAGES[platform]:
|
for package in PACKAGES[platform]:
|
||||||
yield path.join(target_dir, package)
|
yield path.join(target_dir, package)
|
||||||
|
|
||||||
|
|
||||||
def listfiles(directory) -> list[str]:
|
def listfiles(directory: str) -> list[str]:
|
||||||
return [f for f in os.listdir(directory) if path.isfile(path.join(directory, f))]
|
return [f for f in os.listdir(directory) if path.isfile(path.join(directory, f))]
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ def copy_windows_dependencies(binary_path: str, destination: str) -> None:
|
||||||
shutil.copy(path.join(binary_path, f), destination)
|
shutil.copy(path.join(binary_path, f), destination)
|
||||||
|
|
||||||
|
|
||||||
def check_call_with_randomized_backoff(args: List[str], retries: int) -> int:
|
def check_call_with_randomized_backoff(args: list[str], retries: int) -> int:
|
||||||
"""
|
"""
|
||||||
Run the given command-line arguments via `subprocess.check_call()`. If the command
|
Run the given command-line arguments via `subprocess.check_call()`. If the command
|
||||||
fails sleep for a random number of seconds between 2 and 5 and then try to the command
|
fails sleep for a random number of seconds between 2 and 5 and then try to the command
|
||||||
|
@ -111,7 +111,9 @@ class PackageCommands(CommandBase):
|
||||||
@CommandArgument("--target", "-t", default=None, help="Package for given target platform")
|
@CommandArgument("--target", "-t", default=None, help="Package for given target platform")
|
||||||
@CommandBase.common_command_arguments(build_configuration=False, build_type=True, package_configuration=True)
|
@CommandBase.common_command_arguments(build_configuration=False, build_type=True, package_configuration=True)
|
||||||
@CommandBase.allow_target_configuration
|
@CommandBase.allow_target_configuration
|
||||||
def package(self, build_type: BuildType, flavor=None, sanitizer: SanitizerKind = SanitizerKind.NONE) -> int | None:
|
def package(
|
||||||
|
self, build_type: BuildType, flavor: str | None = None, sanitizer: SanitizerKind = SanitizerKind.NONE
|
||||||
|
) -> int | None:
|
||||||
env = self.build_env()
|
env = self.build_env()
|
||||||
binary_path = self.get_binary_path(build_type, sanitizer=sanitizer)
|
binary_path = self.get_binary_path(build_type, sanitizer=sanitizer)
|
||||||
dir_to_root = self.get_top_dir()
|
dir_to_root = self.get_top_dir()
|
||||||
|
@ -398,10 +400,10 @@ class PackageCommands(CommandBase):
|
||||||
def install(
|
def install(
|
||||||
self,
|
self,
|
||||||
build_type: BuildType,
|
build_type: BuildType,
|
||||||
emulator=False,
|
emulator: bool = False,
|
||||||
usb=False,
|
usb: bool = False,
|
||||||
sanitizer: SanitizerKind = SanitizerKind.NONE,
|
sanitizer: SanitizerKind = SanitizerKind.NONE,
|
||||||
flavor=None,
|
flavor: str | None = None,
|
||||||
) -> int:
|
) -> int:
|
||||||
env = self.build_env()
|
env = self.build_env()
|
||||||
try:
|
try:
|
||||||
|
@ -453,10 +455,10 @@ class PackageCommands(CommandBase):
|
||||||
@CommandArgument(
|
@CommandArgument(
|
||||||
"--github-release-id", default=None, type=int, help="The github release to upload the nightly builds."
|
"--github-release-id", default=None, type=int, help="The github release to upload the nightly builds."
|
||||||
)
|
)
|
||||||
def upload_nightly(self, platform, secret_from_environment, github_release_id) -> int:
|
def upload_nightly(self, platform: str, secret_from_environment: bool, github_release_id: int | None) -> int:
|
||||||
import boto3
|
import boto3
|
||||||
|
|
||||||
def get_s3_secret():
|
def get_s3_secret() -> tuple:
|
||||||
aws_access_key = None
|
aws_access_key = None
|
||||||
aws_secret_access_key = None
|
aws_secret_access_key = None
|
||||||
if secret_from_environment:
|
if secret_from_environment:
|
||||||
|
@ -465,13 +467,13 @@ class PackageCommands(CommandBase):
|
||||||
aws_secret_access_key = secret["aws_secret_access_key"]
|
aws_secret_access_key = secret["aws_secret_access_key"]
|
||||||
return (aws_access_key, aws_secret_access_key)
|
return (aws_access_key, aws_secret_access_key)
|
||||||
|
|
||||||
def nightly_filename(package, timestamp) -> str:
|
def nightly_filename(package: str, timestamp: datetime) -> str:
|
||||||
return "{}-{}".format(
|
return "{}-{}".format(
|
||||||
timestamp.isoformat() + "Z", # The `Z` denotes UTC
|
timestamp.isoformat() + "Z", # The `Z` denotes UTC
|
||||||
path.basename(package),
|
path.basename(package),
|
||||||
)
|
)
|
||||||
|
|
||||||
def upload_to_github_release(platform, package: str, package_hash: str) -> None:
|
def upload_to_github_release(platform: str, package: str, package_hash: str) -> None:
|
||||||
if not github_release_id:
|
if not github_release_id:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -488,7 +490,7 @@ class PackageCommands(CommandBase):
|
||||||
package_hash_fileobj, package_hash_fileobj.getbuffer().nbytes, name=f"{asset_name}.sha256"
|
package_hash_fileobj, package_hash_fileobj.getbuffer().nbytes, name=f"{asset_name}.sha256"
|
||||||
)
|
)
|
||||||
|
|
||||||
def upload_to_s3(platform, package: str, package_hash: str, timestamp: datetime) -> None:
|
def upload_to_s3(platform: str, package: str, package_hash: str, timestamp: datetime) -> None:
|
||||||
(aws_access_key, aws_secret_access_key) = get_s3_secret()
|
(aws_access_key, aws_secret_access_key) = get_s3_secret()
|
||||||
s3 = boto3.client("s3", aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_access_key)
|
s3 = boto3.client("s3", aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_access_key)
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ def host_triple() -> str:
|
||||||
return f"{cpu_type}-{os_type}"
|
return f"{cpu_type}-{os_type}"
|
||||||
|
|
||||||
|
|
||||||
def get():
|
def get(): # noqa
|
||||||
# pylint: disable=global-statement
|
# pylint: disable=global-statement
|
||||||
global __platform__
|
global __platform__
|
||||||
if __platform__:
|
if __platform__:
|
||||||
|
|
|
@ -20,7 +20,7 @@ from enum import Enum
|
||||||
|
|
||||||
from os import path
|
from os import path
|
||||||
from packaging.version import parse as parse_version
|
from packaging.version import parse as parse_version
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
import servo.platform
|
import servo.platform
|
||||||
import servo.util as util
|
import servo.util as util
|
||||||
|
@ -70,7 +70,7 @@ class BuildTarget(object):
|
||||||
def binary_name(self) -> str:
|
def binary_name(self) -> str:
|
||||||
return f"servo{servo.platform.get().executable_suffix()}"
|
return f"servo{servo.platform.get().executable_suffix()}"
|
||||||
|
|
||||||
def configure_build_environment(self, env: Dict[str, str], config: Dict[str, Any], topdir: pathlib.Path) -> None:
|
def configure_build_environment(self, env: dict[str, str], config: dict[str, Any], topdir: pathlib.Path) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def is_cross_build(self) -> bool:
|
def is_cross_build(self) -> bool:
|
||||||
|
@ -88,7 +88,7 @@ class CrossBuildTarget(BuildTarget):
|
||||||
class AndroidTarget(CrossBuildTarget):
|
class AndroidTarget(CrossBuildTarget):
|
||||||
DEFAULT_TRIPLE = "aarch64-linux-android"
|
DEFAULT_TRIPLE = "aarch64-linux-android"
|
||||||
|
|
||||||
def ndk_configuration(self) -> Dict[str, str]:
|
def ndk_configuration(self) -> dict[str, str]:
|
||||||
target = self.triple()
|
target = self.triple()
|
||||||
config = {}
|
config = {}
|
||||||
if target == "armv7-linux-androideabi":
|
if target == "armv7-linux-androideabi":
|
||||||
|
@ -125,7 +125,7 @@ class AndroidTarget(CrossBuildTarget):
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def configure_build_environment(self, env: Dict[str, str], config: Dict[str, Any], topdir: pathlib.Path) -> None:
|
def configure_build_environment(self, env: dict[str, str], config: dict[str, Any], topdir: pathlib.Path) -> None:
|
||||||
# Paths to Android build tools:
|
# Paths to Android build tools:
|
||||||
if config["android"]["sdk"]:
|
if config["android"]["sdk"]:
|
||||||
env["ANDROID_SDK_ROOT"] = config["android"]["sdk"]
|
env["ANDROID_SDK_ROOT"] = config["android"]["sdk"]
|
||||||
|
@ -296,7 +296,7 @@ class AndroidTarget(CrossBuildTarget):
|
||||||
class OpenHarmonyTarget(CrossBuildTarget):
|
class OpenHarmonyTarget(CrossBuildTarget):
|
||||||
DEFAULT_TRIPLE = "aarch64-unknown-linux-ohos"
|
DEFAULT_TRIPLE = "aarch64-unknown-linux-ohos"
|
||||||
|
|
||||||
def configure_build_environment(self, env: Dict[str, str], config: Dict[str, Any], topdir: pathlib.Path) -> None:
|
def configure_build_environment(self, env: dict[str, str], config: dict[str, Any], topdir: pathlib.Path) -> None:
|
||||||
# Paths to OpenHarmony SDK and build tools:
|
# Paths to OpenHarmony SDK and build tools:
|
||||||
# Note: `OHOS_SDK_NATIVE` is the CMake variable name the `hvigor` build-system
|
# Note: `OHOS_SDK_NATIVE` is the CMake variable name the `hvigor` build-system
|
||||||
# uses for the native directory of the SDK, so we use the same name to be consistent.
|
# uses for the native directory of the SDK, so we use the same name to be consistent.
|
||||||
|
|
|
@ -11,7 +11,7 @@ import distro
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import shutil
|
import shutil
|
||||||
from typing import Optional
|
from typing import Optional, Any
|
||||||
|
|
||||||
from .base import Base
|
from .base import Base
|
||||||
from .build_target import BuildTarget
|
from .build_target import BuildTarget
|
||||||
|
@ -164,7 +164,7 @@ GSTREAMER_URL = (
|
||||||
|
|
||||||
|
|
||||||
class Linux(Base):
|
class Linux(Base):
|
||||||
def __init__(self, *args, **kwargs) -> None:
|
def __init__(self, *args: str, **kwargs: Any) -> None:
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.is_linux = True
|
self.is_linux = True
|
||||||
self.distro = distro.name()
|
self.distro = distro.name()
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
from typing import Optional
|
from typing import Optional, Any
|
||||||
|
|
||||||
from .. import util
|
from .. import util
|
||||||
from .base import Base
|
from .base import Base
|
||||||
|
@ -24,7 +24,7 @@ GSTREAMER_ROOT = "/Library/Frameworks/GStreamer.framework/Versions/1.0"
|
||||||
|
|
||||||
|
|
||||||
class MacOS(Base):
|
class MacOS(Base):
|
||||||
def __init__(self, *args, **kwargs) -> None:
|
def __init__(self, *args: str, **kwargs: Any) -> None:
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.is_macos = True
|
self.is_macos = True
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ import os.path as path
|
||||||
import subprocess
|
import subprocess
|
||||||
from subprocess import CompletedProcess
|
from subprocess import CompletedProcess
|
||||||
from shutil import copy2
|
from shutil import copy2
|
||||||
from typing import List
|
from typing import Any
|
||||||
|
|
||||||
import mozdebug
|
import mozdebug
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ from servo.platform.build_target import is_android
|
||||||
ANDROID_APP_NAME = "org.servo.servoshell"
|
ANDROID_APP_NAME = "org.servo.servoshell"
|
||||||
|
|
||||||
|
|
||||||
def read_file(filename, if_exists=False) -> str | None:
|
def read_file(filename: str, if_exists: bool = False) -> str | None:
|
||||||
if if_exists and not path.exists(filename):
|
if if_exists and not path.exists(filename):
|
||||||
return None
|
return None
|
||||||
with open(filename) as f:
|
with open(filename) as f:
|
||||||
|
@ -44,7 +44,7 @@ def read_file(filename, if_exists=False) -> str | None:
|
||||||
|
|
||||||
|
|
||||||
# Copied from Python 3.3+'s shlex.quote()
|
# Copied from Python 3.3+'s shlex.quote()
|
||||||
def shell_quote(arg: str):
|
def shell_quote(arg: str) -> str:
|
||||||
# use single quotes, and put single quotes into double quotes
|
# use single quotes, and put single quotes into double quotes
|
||||||
# the string $'b is then quoted as '$'"'"'b'
|
# the string $'b is then quoted as '$'"'"'b'
|
||||||
return "'" + arg.replace("'", "'\"'\"'") + "'"
|
return "'" + arg.replace("'", "'\"'\"'") + "'"
|
||||||
|
@ -75,26 +75,26 @@ class PostBuildCommands(CommandBase):
|
||||||
def run(
|
def run(
|
||||||
self,
|
self,
|
||||||
servo_binary: str,
|
servo_binary: str,
|
||||||
params,
|
params: list[str],
|
||||||
debugger=False,
|
debugger: bool = False,
|
||||||
debugger_cmd=None,
|
debugger_cmd: str | None = None,
|
||||||
headless=False,
|
headless: bool = False,
|
||||||
software=False,
|
software: bool = False,
|
||||||
emulator=False,
|
emulator: bool = False,
|
||||||
usb=False,
|
usb: bool = False,
|
||||||
) -> int | None:
|
) -> int | None:
|
||||||
return self._run(servo_binary, params, debugger, debugger_cmd, headless, software, emulator, usb)
|
return self._run(servo_binary, params, debugger, debugger_cmd, headless, software, emulator, usb)
|
||||||
|
|
||||||
def _run(
|
def _run(
|
||||||
self,
|
self,
|
||||||
servo_binary: str,
|
servo_binary: str,
|
||||||
params,
|
params: list[str],
|
||||||
debugger=False,
|
debugger: bool = False,
|
||||||
debugger_cmd=None,
|
debugger_cmd: str | None = None,
|
||||||
headless=False,
|
headless: bool = False,
|
||||||
software=False,
|
software: bool = False,
|
||||||
emulator=False,
|
emulator: bool = False,
|
||||||
usb=False,
|
usb: bool = False,
|
||||||
) -> int | None:
|
) -> int | None:
|
||||||
env = self.build_env()
|
env = self.build_env()
|
||||||
env["RUST_BACKTRACE"] = "1"
|
env["RUST_BACKTRACE"] = "1"
|
||||||
|
@ -194,7 +194,7 @@ class PostBuildCommands(CommandBase):
|
||||||
|
|
||||||
@Command("android-emulator", description="Run the Android emulator", category="post-build")
|
@Command("android-emulator", description="Run the Android emulator", category="post-build")
|
||||||
@CommandArgument("args", nargs="...", help="Command-line arguments to be passed through to the emulator")
|
@CommandArgument("args", nargs="...", help="Command-line arguments to be passed through to the emulator")
|
||||||
def android_emulator(self, args=None) -> int:
|
def android_emulator(self, args: list[str] | None = None) -> int:
|
||||||
if not args:
|
if not args:
|
||||||
args = []
|
args = []
|
||||||
print("AVDs created by `./mach bootstrap-android` are servo-arm and servo-x86.")
|
print("AVDs created by `./mach bootstrap-android` are servo-arm and servo-x86.")
|
||||||
|
@ -204,7 +204,7 @@ class PostBuildCommands(CommandBase):
|
||||||
@Command("rr-record", description="Run Servo whilst recording execution with rr", category="post-build")
|
@Command("rr-record", description="Run Servo whilst recording execution with rr", category="post-build")
|
||||||
@CommandArgument("params", nargs="...", help="Command-line arguments to be passed through to Servo")
|
@CommandArgument("params", nargs="...", help="Command-line arguments to be passed through to Servo")
|
||||||
@CommandBase.common_command_arguments(binary_selection=True)
|
@CommandBase.common_command_arguments(binary_selection=True)
|
||||||
def rr_record(self, servo_binary: str, params=[]) -> None:
|
def rr_record(self, servo_binary: str, params: list[str] = []) -> None:
|
||||||
env = self.build_env()
|
env = self.build_env()
|
||||||
env["RUST_BACKTRACE"] = "1"
|
env["RUST_BACKTRACE"] = "1"
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ class PostBuildCommands(CommandBase):
|
||||||
@Command("doc", description="Generate documentation", category="post-build")
|
@Command("doc", description="Generate documentation", category="post-build")
|
||||||
@CommandArgument("params", nargs="...", help="Command-line arguments to be passed through to cargo doc")
|
@CommandArgument("params", nargs="...", help="Command-line arguments to be passed through to cargo doc")
|
||||||
@CommandBase.common_command_arguments(build_configuration=True, build_type=False)
|
@CommandBase.common_command_arguments(build_configuration=True, build_type=False)
|
||||||
def doc(self, params: List[str], **kwargs) -> CompletedProcess[bytes] | int | None:
|
def doc(self, params: list[str], **kwargs: Any) -> CompletedProcess[bytes] | int | None:
|
||||||
self.ensure_bootstrapped()
|
self.ensure_bootstrapped()
|
||||||
|
|
||||||
docs = path.join(servo.util.get_target_dir(), "doc")
|
docs = path.join(servo.util.get_target_dir(), "doc")
|
||||||
|
|
|
@ -118,7 +118,7 @@ class MachCommands(CommandBase):
|
||||||
DEFAULT_RENDER_MODE = "cpu"
|
DEFAULT_RENDER_MODE = "cpu"
|
||||||
HELP_RENDER_MODE = "Value can be 'cpu', 'gpu' or 'both' (default " + DEFAULT_RENDER_MODE + ")"
|
HELP_RENDER_MODE = "Value can be 'cpu', 'gpu' or 'both' (default " + DEFAULT_RENDER_MODE + ")"
|
||||||
|
|
||||||
def __init__(self, context) -> None:
|
def __init__(self, context: Any) -> None:
|
||||||
CommandBase.__init__(self, context)
|
CommandBase.__init__(self, context)
|
||||||
if not hasattr(self.context, "built_tests"):
|
if not hasattr(self.context, "built_tests"):
|
||||||
self.context.built_tests = False
|
self.context.built_tests = False
|
||||||
|
@ -127,7 +127,7 @@ class MachCommands(CommandBase):
|
||||||
@CommandArgument("--base", default=None, help="the base URL for testcases")
|
@CommandArgument("--base", default=None, help="the base URL for testcases")
|
||||||
@CommandArgument("--date", default=None, help="the datestamp for the data")
|
@CommandArgument("--date", default=None, help="the datestamp for the data")
|
||||||
@CommandArgument("--submit", "-a", default=False, action="store_true", help="submit the data to perfherder")
|
@CommandArgument("--submit", "-a", default=False, action="store_true", help="submit the data to perfherder")
|
||||||
def test_perf(self, base=None, date=None, submit=False) -> int:
|
def test_perf(self, base: str | None = None, date: str | None = None, submit: bool = False) -> int:
|
||||||
env = self.build_env()
|
env = self.build_env()
|
||||||
cmd = ["bash", "test_perf.sh"]
|
cmd = ["bash", "test_perf.sh"]
|
||||||
if base:
|
if base:
|
||||||
|
@ -147,7 +147,13 @@ class MachCommands(CommandBase):
|
||||||
)
|
)
|
||||||
@CommandBase.common_command_arguments(build_configuration=True, build_type=True)
|
@CommandBase.common_command_arguments(build_configuration=True, build_type=True)
|
||||||
def test_unit(
|
def test_unit(
|
||||||
self, build_type: BuildType, test_name=None, package=None, bench=False, nocapture=False, **kwargs
|
self,
|
||||||
|
build_type: BuildType,
|
||||||
|
test_name: list[str] | None = None,
|
||||||
|
package: str | None = None,
|
||||||
|
bench: bool = False,
|
||||||
|
nocapture: bool = False,
|
||||||
|
**kwargs: Any,
|
||||||
) -> int:
|
) -> int:
|
||||||
if test_name is None:
|
if test_name is None:
|
||||||
test_name = []
|
test_name = []
|
||||||
|
@ -265,7 +271,7 @@ class MachCommands(CommandBase):
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Emit tidy warnings in the Github Actions annotations format",
|
help="Emit tidy warnings in the Github Actions annotations format",
|
||||||
)
|
)
|
||||||
def test_tidy(self, all_files, no_progress, github_annotations) -> int:
|
def test_tidy(self, all_files: bool, no_progress: bool, github_annotations: bool) -> int:
|
||||||
tidy_failed = tidy.scan(not all_files, not no_progress, github_annotations)
|
tidy_failed = tidy.scan(not all_files, not no_progress, github_annotations)
|
||||||
|
|
||||||
print("\r ➤ Checking formatting of Rust files...")
|
print("\r ➤ Checking formatting of Rust files...")
|
||||||
|
@ -299,7 +305,7 @@ class MachCommands(CommandBase):
|
||||||
@CommandArgument(
|
@CommandArgument(
|
||||||
"tests", default=None, nargs="...", help="Specific WebIDL tests to run, relative to the tests directory"
|
"tests", default=None, nargs="...", help="Specific WebIDL tests to run, relative to the tests directory"
|
||||||
)
|
)
|
||||||
def test_scripts(self, verbose, very_verbose, all, tests) -> int:
|
def test_scripts(self, verbose: bool, very_verbose: bool, all: bool, tests: list[str]) -> int:
|
||||||
if very_verbose:
|
if very_verbose:
|
||||||
logging.getLogger().level = logging.DEBUG
|
logging.getLogger().level = logging.DEBUG
|
||||||
elif verbose:
|
elif verbose:
|
||||||
|
@ -357,7 +363,7 @@ class MachCommands(CommandBase):
|
||||||
@Command("test-devtools", description="Run tests for devtools.", category="testing")
|
@Command("test-devtools", description="Run tests for devtools.", category="testing")
|
||||||
@CommandArgument("test_names", nargs=argparse.REMAINDER, help="Only run tests that match these patterns")
|
@CommandArgument("test_names", nargs=argparse.REMAINDER, help="Only run tests that match these patterns")
|
||||||
@CommandBase.common_command_arguments(build_type=True)
|
@CommandBase.common_command_arguments(build_type=True)
|
||||||
def test_devtools(self, build_type: BuildType, test_names: list[str], **kwargs) -> int:
|
def test_devtools(self, build_type: BuildType, test_names: list[str], **kwargs: Any) -> int:
|
||||||
print("Running devtools tests...")
|
print("Running devtools tests...")
|
||||||
passed = servo.devtools_tests.run_tests(SCRIPT_PATH, build_type, test_names)
|
passed = servo.devtools_tests.run_tests(SCRIPT_PATH, build_type, test_names)
|
||||||
return 0 if passed else 1
|
return 0 if passed else 1
|
||||||
|
@ -369,7 +375,7 @@ class MachCommands(CommandBase):
|
||||||
parser=wpt.create_parser,
|
parser=wpt.create_parser,
|
||||||
)
|
)
|
||||||
@CommandBase.common_command_arguments(build_configuration=False, build_type=True)
|
@CommandBase.common_command_arguments(build_configuration=False, build_type=True)
|
||||||
def test_wpt_failure(self, build_type: BuildType, **kwargs) -> bool:
|
def test_wpt_failure(self, build_type: BuildType, **kwargs: Any) -> bool:
|
||||||
kwargs["pause_after_test"] = False
|
kwargs["pause_after_test"] = False
|
||||||
kwargs["include"] = ["infrastructure/failing-test.html"]
|
kwargs["include"] = ["infrastructure/failing-test.html"]
|
||||||
return not self._test_wpt(build_type=build_type, **kwargs)
|
return not self._test_wpt(build_type=build_type, **kwargs)
|
||||||
|
@ -378,11 +384,11 @@ class MachCommands(CommandBase):
|
||||||
"test-wpt", description="Run the regular web platform test suite", category="testing", parser=wpt.create_parser
|
"test-wpt", description="Run the regular web platform test suite", category="testing", parser=wpt.create_parser
|
||||||
)
|
)
|
||||||
@CommandBase.common_command_arguments(binary_selection=True)
|
@CommandBase.common_command_arguments(binary_selection=True)
|
||||||
def test_wpt(self, servo_binary: str, **kwargs):
|
def test_wpt(self, servo_binary: str, **kwargs: Any) -> int:
|
||||||
return self._test_wpt(servo_binary, **kwargs)
|
return self._test_wpt(servo_binary, **kwargs)
|
||||||
|
|
||||||
@CommandBase.allow_target_configuration
|
@CommandBase.allow_target_configuration
|
||||||
def _test_wpt(self, servo_binary: str, **kwargs) -> int:
|
def _test_wpt(self, servo_binary: str, **kwargs: Any) -> int:
|
||||||
# TODO(mrobinson): Why do we pass the wrong binary path in when running WPT on Android?
|
# TODO(mrobinson): Why do we pass the wrong binary path in when running WPT on Android?
|
||||||
return_value = wpt.run.run_tests(servo_binary, **kwargs)
|
return_value = wpt.run.run_tests(servo_binary, **kwargs)
|
||||||
return return_value if not kwargs["always_succeed"] else 0
|
return return_value if not kwargs["always_succeed"] else 0
|
||||||
|
@ -393,7 +399,7 @@ class MachCommands(CommandBase):
|
||||||
category="testing",
|
category="testing",
|
||||||
parser=wpt.manifestupdate.create_parser,
|
parser=wpt.manifestupdate.create_parser,
|
||||||
)
|
)
|
||||||
def update_manifest(self, **kwargs) -> int:
|
def update_manifest(self, **kwargs: Any) -> int:
|
||||||
return wpt.manifestupdate.update(check_clean=False)
|
return wpt.manifestupdate.update(check_clean=False)
|
||||||
|
|
||||||
@Command("fmt", description="Format Rust, Python, and TOML files", category="testing")
|
@Command("fmt", description="Format Rust, Python, and TOML files", category="testing")
|
||||||
|
@ -411,7 +417,7 @@ class MachCommands(CommandBase):
|
||||||
@Command(
|
@Command(
|
||||||
"update-wpt", description="Update the web platform tests", category="testing", parser=wpt.update.create_parser
|
"update-wpt", description="Update the web platform tests", category="testing", parser=wpt.update.create_parser
|
||||||
)
|
)
|
||||||
def update_wpt(self, **kwargs) -> int:
|
def update_wpt(self, **kwargs: Any) -> int:
|
||||||
patch = kwargs.get("patch", False)
|
patch = kwargs.get("patch", False)
|
||||||
if not patch and kwargs["sync"]:
|
if not patch and kwargs["sync"]:
|
||||||
print("Are you sure you don't want a patch?")
|
print("Are you sure you don't want a patch?")
|
||||||
|
@ -427,7 +433,7 @@ class MachCommands(CommandBase):
|
||||||
@CommandArgument("tests", default=["recommended"], nargs="...", help="Specific tests to run")
|
@CommandArgument("tests", default=["recommended"], nargs="...", help="Specific tests to run")
|
||||||
@CommandArgument("--bmf-output", default=None, help="Specify BMF JSON output file")
|
@CommandArgument("--bmf-output", default=None, help="Specify BMF JSON output file")
|
||||||
@CommandBase.common_command_arguments(binary_selection=True)
|
@CommandBase.common_command_arguments(binary_selection=True)
|
||||||
def test_dromaeo(self, tests, servo_binary: str, bmf_output: str | None = None) -> None:
|
def test_dromaeo(self, tests: list[str], servo_binary: str, bmf_output: str | None = None) -> None:
|
||||||
return self.dromaeo_test_runner(tests, servo_binary, bmf_output)
|
return self.dromaeo_test_runner(tests, servo_binary, bmf_output)
|
||||||
|
|
||||||
@Command("test-speedometer", description="Run servo's speedometer", category="testing")
|
@Command("test-speedometer", description="Run servo's speedometer", category="testing")
|
||||||
|
@ -455,7 +461,7 @@ class MachCommands(CommandBase):
|
||||||
@CommandArgument(
|
@CommandArgument(
|
||||||
"params", default=None, nargs="...", help=" filepaths of output files of two runs of dromaeo test "
|
"params", default=None, nargs="...", help=" filepaths of output files of two runs of dromaeo test "
|
||||||
)
|
)
|
||||||
def compare_dromaeo(self, params) -> None:
|
def compare_dromaeo(self, params: list[str]) -> None:
|
||||||
prev_op_filename = params[0]
|
prev_op_filename = params[0]
|
||||||
cur_op_filename = params[1]
|
cur_op_filename = params[1]
|
||||||
result = {"Test": [], "Prev_Time": [], "Cur_Time": [], "Difference(%)": []}
|
result = {"Test": [], "Prev_Time": [], "Cur_Time": [], "Difference(%)": []}
|
||||||
|
@ -552,7 +558,7 @@ class MachCommands(CommandBase):
|
||||||
|
|
||||||
return call([run_file, cmd, bin_path, base_dir])
|
return call([run_file, cmd, bin_path, base_dir])
|
||||||
|
|
||||||
def dromaeo_test_runner(self, tests, binary: str, bmf_output: str | None) -> None:
|
def dromaeo_test_runner(self, tests: list[str], binary: str, bmf_output: str | None) -> None:
|
||||||
base_dir = path.abspath(path.join("tests", "dromaeo"))
|
base_dir = path.abspath(path.join("tests", "dromaeo"))
|
||||||
dromaeo_dir = path.join(base_dir, "dromaeo")
|
dromaeo_dir = path.join(base_dir, "dromaeo")
|
||||||
run_file = path.join(base_dir, "run_dromaeo.py")
|
run_file = path.join(base_dir, "run_dromaeo.py")
|
||||||
|
@ -582,7 +588,7 @@ class MachCommands(CommandBase):
|
||||||
output = dict()
|
output = dict()
|
||||||
profile = "" if profile is None else profile + "/"
|
profile = "" if profile is None else profile + "/"
|
||||||
|
|
||||||
def parse_speedometer_result(result) -> None:
|
def parse_speedometer_result(result: dict[str, Any]) -> None:
|
||||||
if result["unit"] == "ms":
|
if result["unit"] == "ms":
|
||||||
output[profile + f"Speedometer/{result['name']}"] = {
|
output[profile + f"Speedometer/{result['name']}"] = {
|
||||||
"latency": { # speedometer has ms we need to convert to ns
|
"latency": { # speedometer has ms we need to convert to ns
|
||||||
|
@ -700,7 +706,7 @@ class MachCommands(CommandBase):
|
||||||
description="Update the net unit tests with cookie tests from http-state",
|
description="Update the net unit tests with cookie tests from http-state",
|
||||||
category="testing",
|
category="testing",
|
||||||
)
|
)
|
||||||
def update_net_cookies(self):
|
def update_net_cookies(self) -> int:
|
||||||
cache_dir = path.join(self.config["tools"]["cache-dir"], "tests")
|
cache_dir = path.join(self.config["tools"]["cache-dir"], "tests")
|
||||||
run_file = path.abspath(
|
run_file = path.abspath(
|
||||||
path.join(PROJECT_TOPLEVEL_PATH, "components", "net", "tests", "cookie_http_state_utils.py")
|
path.join(PROJECT_TOPLEVEL_PATH, "components", "net", "tests", "cookie_http_state_utils.py")
|
||||||
|
@ -713,7 +719,7 @@ class MachCommands(CommandBase):
|
||||||
"update-webgl", description="Update the WebGL conformance suite tests from Khronos repo", category="testing"
|
"update-webgl", description="Update the WebGL conformance suite tests from Khronos repo", category="testing"
|
||||||
)
|
)
|
||||||
@CommandArgument("--version", default="2.0.0", help="WebGL conformance suite version")
|
@CommandArgument("--version", default="2.0.0", help="WebGL conformance suite version")
|
||||||
def update_webgl(self, version=None):
|
def update_webgl(self, version: str | None = None) -> None:
|
||||||
base_dir = path.abspath(path.join(PROJECT_TOPLEVEL_PATH, "tests", "wpt", "mozilla", "tests", "webgl"))
|
base_dir = path.abspath(path.join(PROJECT_TOPLEVEL_PATH, "tests", "wpt", "mozilla", "tests", "webgl"))
|
||||||
run_file = path.join(base_dir, "tools", "import-conformance-tests.py")
|
run_file = path.join(base_dir, "tools", "import-conformance-tests.py")
|
||||||
dest_folder = path.join(base_dir, "conformance-%s" % version)
|
dest_folder = path.join(base_dir, "conformance-%s" % version)
|
||||||
|
@ -729,7 +735,7 @@ class MachCommands(CommandBase):
|
||||||
@Command("update-webgpu", description="Update the WebGPU conformance test suite", category="testing")
|
@Command("update-webgpu", description="Update the WebGPU conformance test suite", category="testing")
|
||||||
@CommandArgument("--repo", "-r", default="https://github.com/gpuweb/cts", help="Repo to vendor cts from")
|
@CommandArgument("--repo", "-r", default="https://github.com/gpuweb/cts", help="Repo to vendor cts from")
|
||||||
@CommandArgument("--checkout", "-c", default="main", help="Branch or commit of repo")
|
@CommandArgument("--checkout", "-c", default="main", help="Branch or commit of repo")
|
||||||
def cts(self, repo="https://github.com/gpuweb/cts", checkout="main"):
|
def cts(self, repo: str = "https://github.com/gpuweb/cts", checkout: str = "main") -> int:
|
||||||
tdir = path.join(self.context.topdir, "tests/wpt/webgpu/tests")
|
tdir = path.join(self.context.topdir, "tests/wpt/webgpu/tests")
|
||||||
clone_dir = path.join(tdir, "cts_clone")
|
clone_dir = path.join(tdir, "cts_clone")
|
||||||
# clone
|
# clone
|
||||||
|
@ -786,7 +792,7 @@ class MachCommands(CommandBase):
|
||||||
)
|
)
|
||||||
@CommandArgument("params", nargs="...", help="Command-line arguments to be passed through to Servo")
|
@CommandArgument("params", nargs="...", help="Command-line arguments to be passed through to Servo")
|
||||||
@CommandBase.common_command_arguments(binary_selection=True)
|
@CommandBase.common_command_arguments(binary_selection=True)
|
||||||
def smoketest(self, servo_binary: str, params, **kwargs) -> int | None:
|
def smoketest(self, servo_binary: str, params: list[str], **kwargs: Any) -> int | None:
|
||||||
# We pass `-f` here so that any thread panic will cause Servo to exit,
|
# We pass `-f` here so that any thread panic will cause Servo to exit,
|
||||||
# preventing a panic from hanging execution. This means that these kind
|
# preventing a panic from hanging execution. This means that these kind
|
||||||
# of panics won't cause timeouts on CI.
|
# of panics won't cause timeouts on CI.
|
||||||
|
|
|
@ -13,7 +13,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
from typing import ClassVar, List, Optional
|
from typing import ClassVar, Optional, Any
|
||||||
import unittest
|
import unittest
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ class JobConfig(object):
|
||||||
number_of_wpt_chunks: int = 20
|
number_of_wpt_chunks: int = 20
|
||||||
# These are the fields that must match in between two JobConfigs for them to be able to be
|
# These are the fields that must match in between two JobConfigs for them to be able to be
|
||||||
# merged. If you modify any of the fields above, make sure to update this line as well.
|
# merged. If you modify any of the fields above, make sure to update this line as well.
|
||||||
merge_compatibility_fields: ClassVar[List[str]] = ["workflow", "profile", "wpt_args", "build_args"]
|
merge_compatibility_fields: ClassVar[list[str]] = ["workflow", "profile", "wpt_args", "build_args"]
|
||||||
|
|
||||||
def merge(self, other: JobConfig) -> bool:
|
def merge(self, other: JobConfig) -> bool:
|
||||||
"""Try to merge another job with this job. Returns True if merging is successful
|
"""Try to merge another job with this job. Returns True if merging is successful
|
||||||
|
@ -177,7 +177,7 @@ def handle_modifier(config: Optional[JobConfig], s: str) -> Optional[JobConfig]:
|
||||||
|
|
||||||
|
|
||||||
class Encoder(json.JSONEncoder):
|
class Encoder(json.JSONEncoder):
|
||||||
def default(self, o):
|
def default(self, o: Any) -> Any:
|
||||||
if isinstance(o, (Config, JobConfig)):
|
if isinstance(o, (Config, JobConfig)):
|
||||||
return o.__dict__
|
return o.__dict__
|
||||||
return json.JSONEncoder.default(self, o)
|
return json.JSONEncoder.default(self, o)
|
||||||
|
@ -236,7 +236,7 @@ class Config(object):
|
||||||
return
|
return
|
||||||
self.matrix.append(job)
|
self.matrix.append(job)
|
||||||
|
|
||||||
def to_json(self, **kwargs) -> str:
|
def to_json(self, **kwargs: Any) -> str:
|
||||||
return json.dumps(self, cls=Encoder, **kwargs)
|
return json.dumps(self, cls=Encoder, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
# option. This file may not be copied, modified, or distributed
|
# option. This file may not be copied, modified, or distributed
|
||||||
# except according to those terms.
|
# except according to those terms.
|
||||||
|
|
||||||
|
from os import PathLike
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
@ -18,7 +19,8 @@ import urllib.error
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import zipfile
|
import zipfile
|
||||||
from zipfile import ZipInfo
|
from zipfile import ZipInfo
|
||||||
from typing import Dict, List, Union
|
from typing import Union, Any
|
||||||
|
from collections.abc import Callable
|
||||||
|
|
||||||
from io import BufferedIOBase, BytesIO
|
from io import BufferedIOBase, BytesIO
|
||||||
from socket import error as socket_error
|
from socket import error as socket_error
|
||||||
|
@ -27,13 +29,13 @@ SCRIPT_PATH = os.path.abspath(os.path.dirname(__file__))
|
||||||
SERVO_ROOT = os.path.abspath(os.path.join(SCRIPT_PATH, "..", ".."))
|
SERVO_ROOT = os.path.abspath(os.path.join(SCRIPT_PATH, "..", ".."))
|
||||||
|
|
||||||
|
|
||||||
def remove_readonly(func, path, _) -> None:
|
def remove_readonly(func: Callable[[str], None], path: str, _: Any) -> None:
|
||||||
"Clear the readonly bit and reattempt the removal"
|
"Clear the readonly bit and reattempt the removal"
|
||||||
os.chmod(path, stat.S_IWRITE)
|
os.chmod(path, stat.S_IWRITE)
|
||||||
func(path)
|
func(path)
|
||||||
|
|
||||||
|
|
||||||
def delete(path) -> None:
|
def delete(path: str) -> None:
|
||||||
if os.path.isdir(path) and not os.path.islink(path):
|
if os.path.isdir(path) and not os.path.islink(path):
|
||||||
shutil.rmtree(path, onerror=remove_readonly)
|
shutil.rmtree(path, onerror=remove_readonly)
|
||||||
else:
|
else:
|
||||||
|
@ -123,7 +125,7 @@ def download_file(description: str, url: str, destination_path: str) -> None:
|
||||||
# https://stackoverflow.com/questions/39296101/python-zipfile-removes-execute-permissions-from-binaries
|
# https://stackoverflow.com/questions/39296101/python-zipfile-removes-execute-permissions-from-binaries
|
||||||
# In particular, we want the executable bit for executable files.
|
# In particular, we want the executable bit for executable files.
|
||||||
class ZipFileWithUnixPermissions(zipfile.ZipFile):
|
class ZipFileWithUnixPermissions(zipfile.ZipFile):
|
||||||
def extract(self, member, path=None, pwd=None) -> str:
|
def extract(self, member: ZipInfo | str, path: PathLike[str] | str | None = None, pwd: bytes | None = None) -> str:
|
||||||
if not isinstance(member, zipfile.ZipInfo):
|
if not isinstance(member, zipfile.ZipInfo):
|
||||||
member = self.getinfo(member)
|
member = self.getinfo(member)
|
||||||
|
|
||||||
|
@ -137,7 +139,7 @@ class ZipFileWithUnixPermissions(zipfile.ZipFile):
|
||||||
return extracted
|
return extracted
|
||||||
|
|
||||||
# For Python 3.x
|
# For Python 3.x
|
||||||
def _extract_member(self, member: ZipInfo, targetpath, pwd) -> str:
|
def _extract_member(self, member: ZipInfo, targetpath: PathLike[str] | str, pwd: bytes | None) -> str:
|
||||||
if int(sys.version_info[0]) >= 3:
|
if int(sys.version_info[0]) >= 3:
|
||||||
if not isinstance(member, zipfile.ZipInfo):
|
if not isinstance(member, zipfile.ZipInfo):
|
||||||
member = self.getinfo(member)
|
member = self.getinfo(member)
|
||||||
|
@ -154,7 +156,7 @@ class ZipFileWithUnixPermissions(zipfile.ZipFile):
|
||||||
return super(ZipFileWithUnixPermissions, self)._extract_member(member, targetpath, pwd)
|
return super(ZipFileWithUnixPermissions, self)._extract_member(member, targetpath, pwd)
|
||||||
|
|
||||||
|
|
||||||
def extract(src, dst, movedir=None, remove=True) -> None:
|
def extract(src: str, dst: str, movedir: PathLike[str] | str | None = None, remove: bool = True) -> None:
|
||||||
assert src.endswith(".zip")
|
assert src.endswith(".zip")
|
||||||
ZipFileWithUnixPermissions(src).extractall(dst)
|
ZipFileWithUnixPermissions(src).extractall(dst)
|
||||||
|
|
||||||
|
@ -169,7 +171,7 @@ def extract(src, dst, movedir=None, remove=True) -> None:
|
||||||
os.remove(src)
|
os.remove(src)
|
||||||
|
|
||||||
|
|
||||||
def check_hash(filename, expected, algorithm) -> None:
|
def check_hash(filename: str, expected: str, algorithm: str) -> None:
|
||||||
hasher = hashlib.new(algorithm)
|
hasher = hashlib.new(algorithm)
|
||||||
with open(filename, "rb") as f:
|
with open(filename, "rb") as f:
|
||||||
while True:
|
while True:
|
||||||
|
@ -182,11 +184,11 @@ def check_hash(filename, expected, algorithm) -> None:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def get_default_cache_dir(topdir) -> str:
|
def get_default_cache_dir(topdir: str) -> str:
|
||||||
return os.environ.get("SERVO_CACHE_DIR", os.path.join(topdir, ".servo"))
|
return os.environ.get("SERVO_CACHE_DIR", os.path.join(topdir, ".servo"))
|
||||||
|
|
||||||
|
|
||||||
def append_paths_to_env(env: Dict[str, str], key: str, paths: Union[str, List[str]]) -> None:
|
def append_paths_to_env(env: dict[str, str], key: str, paths: Union[str, list[str]]) -> None:
|
||||||
if isinstance(paths, list):
|
if isinstance(paths, list):
|
||||||
paths = os.pathsep.join(paths)
|
paths = os.pathsep.join(paths)
|
||||||
|
|
||||||
|
@ -198,7 +200,7 @@ def append_paths_to_env(env: Dict[str, str], key: str, paths: Union[str, List[st
|
||||||
env[key] = new_value
|
env[key] = new_value
|
||||||
|
|
||||||
|
|
||||||
def prepend_paths_to_env(env: Dict[str, str], key: str, paths: Union[str, List[str]]) -> None:
|
def prepend_paths_to_env(env: dict[str, str], key: str, paths: Union[str, list[str]]) -> None:
|
||||||
if isinstance(paths, list):
|
if isinstance(paths, list):
|
||||||
paths = os.pathsep.join(paths)
|
paths = os.pathsep.join(paths)
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,15 @@
|
||||||
# option. This file may not be copied, modified, or distributed
|
# option. This file may not be copied, modified, or distributed
|
||||||
# except according to those terms.
|
# except according to those terms.
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import dataclasses
|
import dataclasses
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from typing import Generator, List, Optional
|
from typing import Optional
|
||||||
|
from collections.abc import Generator
|
||||||
|
|
||||||
COMPATIBLE_MSVC_VERSIONS = {
|
COMPATIBLE_MSVC_VERSIONS = {
|
||||||
"2019": "16.0",
|
"2019": "16.0",
|
||||||
|
@ -30,7 +33,7 @@ class VisualStudioInstallation:
|
||||||
installation_path: str
|
installation_path: str
|
||||||
vc_install_path: str
|
vc_install_path: str
|
||||||
|
|
||||||
def __lt__(self, other) -> bool:
|
def __lt__(self, other: VisualStudioInstallation) -> bool:
|
||||||
return self.version_number < other.version_number
|
return self.version_number < other.version_number
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,7 +111,7 @@ def find_compatible_msvc_with_environment_variables() -> Optional[VisualStudioIn
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def find_msvc_installations() -> List[VisualStudioInstallation]:
|
def find_msvc_installations() -> list[VisualStudioInstallation]:
|
||||||
# First try to find Visual Studio via `vswhere.exe` and in well-known paths.
|
# First try to find Visual Studio via `vswhere.exe` and in well-known paths.
|
||||||
installations = list(find_compatible_msvc_with_vswhere())
|
installations = list(find_compatible_msvc_with_vswhere())
|
||||||
installations.extend(find_compatible_msvc_with_path())
|
installations.extend(find_compatible_msvc_with_path())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue