Backed out changeset 53b1fa0faa6d (bug 1696251) for breaking the static-analysis integration. a=backout
This commit is contained in:
@@ -12,8 +12,10 @@ import os
|
||||
from mach.decorators import (
|
||||
Command,
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
)
|
||||
from mozbuild.base import (
|
||||
MachCommandBase,
|
||||
MachCommandConditions as conditions,
|
||||
BinaryNotFoundException,
|
||||
)
|
||||
@@ -25,6 +27,8 @@ def is_valgrind_build(cls):
|
||||
return "MOZ_VALGRIND" in defines and "MOZ_MEMORY" not in defines
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command(
|
||||
"valgrind-test",
|
||||
category="testing",
|
||||
@@ -40,7 +44,7 @@ def is_valgrind_build(cls):
|
||||
"--suppression multiple times to specify multiple suppression "
|
||||
"files.",
|
||||
)
|
||||
def valgrind_test(command_context, suppressions):
|
||||
def valgrind_test(self, command_context, suppressions):
|
||||
"""
|
||||
Run Valgrind tests.
|
||||
"""
|
||||
|
||||
@@ -19,9 +19,11 @@ import subprocess
|
||||
from mozbuild import shellutil
|
||||
from mozbuild.base import (
|
||||
MozbuildObject,
|
||||
MachCommandBase,
|
||||
BinaryNotFoundException,
|
||||
)
|
||||
from mach.decorators import (
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
|
||||
@@ -36,20 +38,22 @@ def stringify(obj):
|
||||
return json.dumps(obj, sort_keys=True, indent=2, separators=(",", ": "))
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command(
|
||||
"devtools-css-db",
|
||||
category="post-build",
|
||||
description="Rebuild the devtool's static css properties database.",
|
||||
)
|
||||
def generate_css_db(command_context):
|
||||
def generate_css_db(self, command_context):
|
||||
"""Generate the static css properties database for devtools and write it to file."""
|
||||
|
||||
print("Re-generating the css properties database...")
|
||||
db = get_properties_db_from_xpcshell(command_context)
|
||||
db = self.get_properties_db_from_xpcshell(command_context)
|
||||
if not db:
|
||||
return 1
|
||||
|
||||
output_template(
|
||||
self.output_template(
|
||||
command_context,
|
||||
{
|
||||
"preferences": stringify(db["preferences"]),
|
||||
@@ -58,8 +62,7 @@ def generate_css_db(command_context):
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def get_properties_db_from_xpcshell(command_context):
|
||||
def get_properties_db_from_xpcshell(self, command_context):
|
||||
"""Generate the static css properties db for devtools from an xpcshell script."""
|
||||
build = MozbuildObject.from_environment()
|
||||
|
||||
@@ -99,8 +102,7 @@ def get_properties_db_from_xpcshell(command_context):
|
||||
|
||||
return json.loads(contents)
|
||||
|
||||
|
||||
def output_template(command_context, substitutions):
|
||||
def output_template(self, command_context, substitutions):
|
||||
"""Output a the properties-db.js from a template."""
|
||||
js_template_path = resolve_path(
|
||||
command_context.topsrcdir,
|
||||
|
||||
@@ -9,9 +9,11 @@ import sys
|
||||
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
|
||||
from mozbuild.base import MachCommandBase
|
||||
from mozbuild.util import mkdir
|
||||
|
||||
|
||||
@@ -21,6 +23,8 @@ def get_test_parser():
|
||||
return runtests.get_parser
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class WebIDLProvider(MachCommandBase):
|
||||
@Command(
|
||||
"webidl-example",
|
||||
category="misc",
|
||||
@@ -29,22 +33,23 @@ def get_test_parser():
|
||||
@CommandArgument(
|
||||
"interface", nargs="+", help="Interface(s) whose examples to generate."
|
||||
)
|
||||
def webidl_example(command_context, interface):
|
||||
def webidl_example(self, command_context, interface):
|
||||
from mozwebidlcodegen import BuildSystemWebIDL
|
||||
|
||||
manager = command_context._spawn(BuildSystemWebIDL).manager
|
||||
for i in interface:
|
||||
manager.generate_example_files(i)
|
||||
|
||||
|
||||
@Command(
|
||||
"webidl-parser-test",
|
||||
category="testing",
|
||||
parser=get_test_parser,
|
||||
description="Run WebIDL tests (Interface Browser parser).",
|
||||
)
|
||||
def webidl_test(command_context, **kwargs):
|
||||
sys.path.insert(0, os.path.join(command_context.topsrcdir, "other-licenses", "ply"))
|
||||
def webidl_test(self, command_context, **kwargs):
|
||||
sys.path.insert(
|
||||
0, os.path.join(command_context.topsrcdir, "other-licenses", "ply")
|
||||
)
|
||||
|
||||
# Ensure the topobjdir exists. On a Taskcluster test run there won't be
|
||||
# an objdir yet.
|
||||
|
||||
@@ -16,12 +16,14 @@ import textwrap
|
||||
from mach.base import FailedCommandError, MachError
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
Command,
|
||||
SubCommand,
|
||||
)
|
||||
from mach.registrar import Registrar
|
||||
|
||||
from mozbuild.mozconfig import MozconfigLoader
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
# Command files like this are listed in build/mach_initialize.py in alphabetical
|
||||
# order, but we need to access commands earlier in the sorted order to grab
|
||||
@@ -55,11 +57,12 @@ def inherit_command_args(command, subcommand=None):
|
||||
return inherited
|
||||
|
||||
|
||||
def state_dir():
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
def state_dir(self):
|
||||
return os.environ.get("MOZBUILD_STATE_PATH", os.path.expanduser("~/.mozbuild"))
|
||||
|
||||
|
||||
def tools_dir():
|
||||
def tools_dir(self):
|
||||
if os.environ.get("MOZ_FETCHES_DIR"):
|
||||
# In automation, tools are provided by toolchain dependencies.
|
||||
return os.path.join(os.environ["HOME"], os.environ["MOZ_FETCHES_DIR"])
|
||||
@@ -68,77 +71,70 @@ def tools_dir():
|
||||
# to avoid colliding with the "main" compiler versions, which can
|
||||
# change separately (and the precompiled sixgill and compiler version
|
||||
# must match exactly).
|
||||
return os.path.join(state_dir(), "hazard-tools")
|
||||
return os.path.join(self.state_dir(), "hazard-tools")
|
||||
|
||||
def sixgill_dir(self):
|
||||
return os.path.join(self.tools_dir(), "sixgill")
|
||||
|
||||
def sixgill_dir():
|
||||
return os.path.join(tools_dir(), "sixgill")
|
||||
def gcc_dir(self):
|
||||
return os.path.join(self.tools_dir(), "gcc")
|
||||
|
||||
|
||||
def gcc_dir():
|
||||
return os.path.join(tools_dir(), "gcc")
|
||||
|
||||
|
||||
def script_dir(command_context):
|
||||
def script_dir(self, command_context):
|
||||
return os.path.join(command_context.topsrcdir, "js/src/devtools/rootAnalysis")
|
||||
|
||||
|
||||
def get_work_dir(command_context, application, given):
|
||||
def get_work_dir(self, command_context, application, given):
|
||||
if given is not None:
|
||||
return given
|
||||
return os.path.join(command_context.topsrcdir, "haz-" + application)
|
||||
|
||||
|
||||
def ensure_dir_exists(dir):
|
||||
def ensure_dir_exists(self, dir):
|
||||
os.makedirs(dir, exist_ok=True)
|
||||
return dir
|
||||
|
||||
|
||||
# Force the use of hazard-compatible installs of tools.
|
||||
def setup_env_for_tools(env):
|
||||
gccbin = os.path.join(gcc_dir(), "bin")
|
||||
def setup_env_for_tools(self, env):
|
||||
gccbin = os.path.join(self.gcc_dir(), "bin")
|
||||
env["CC"] = os.path.join(gccbin, "gcc")
|
||||
env["CXX"] = os.path.join(gccbin, "g++")
|
||||
env["PATH"] = "{sixgill_dir}/usr/bin:{gccbin}:{PATH}".format(
|
||||
sixgill_dir=sixgill_dir(), gccbin=gccbin, PATH=env["PATH"]
|
||||
sixgill_dir=self.sixgill_dir(), gccbin=gccbin, PATH=env["PATH"]
|
||||
)
|
||||
|
||||
|
||||
def setup_env_for_shell(env, shell):
|
||||
def setup_env_for_shell(self, env, shell):
|
||||
"""Add JS shell directory to dynamic lib search path"""
|
||||
for var in ("LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH"):
|
||||
env[var] = ":".join(p for p in (env.get(var), os.path.dirname(shell)) if p)
|
||||
|
||||
|
||||
@Command(
|
||||
"hazards",
|
||||
category="build",
|
||||
order="declaration",
|
||||
description="Commands for running the static analysis for GC rooting hazards",
|
||||
)
|
||||
def hazards(command_context):
|
||||
def hazards(self, command_context):
|
||||
"""Commands related to performing the GC rooting hazard analysis"""
|
||||
print("See `mach hazards --help` for a list of subcommands")
|
||||
|
||||
|
||||
@inherit_command_args("artifact", "toolchain")
|
||||
@SubCommand(
|
||||
"hazards",
|
||||
"bootstrap",
|
||||
description="Install prerequisites for the hazard analysis",
|
||||
)
|
||||
def bootstrap(command_context, **kwargs):
|
||||
def bootstrap(self, command_context, **kwargs):
|
||||
orig_dir = os.getcwd()
|
||||
os.chdir(ensure_dir_exists(tools_dir()))
|
||||
os.chdir(self.ensure_dir_exists(self.tools_dir()))
|
||||
try:
|
||||
kwargs["from_build"] = ("linux64-gcc-sixgill", "linux64-gcc-9")
|
||||
command_context._mach_context.commands.dispatch(
|
||||
"artifact", command_context._mach_context, subcommand="toolchain", **kwargs
|
||||
"artifact",
|
||||
command_context._mach_context,
|
||||
subcommand="toolchain",
|
||||
**kwargs
|
||||
)
|
||||
finally:
|
||||
os.chdir(orig_dir)
|
||||
|
||||
|
||||
@inherit_command_args("build")
|
||||
@SubCommand(
|
||||
"hazards", "build-shell", description="Build a shell for the hazard analysis"
|
||||
@@ -149,7 +145,7 @@ def bootstrap(command_context, **kwargs):
|
||||
metavar="FILENAME",
|
||||
help="Build with the given mozconfig.",
|
||||
)
|
||||
def build_shell(command_context, **kwargs):
|
||||
def build_shell(self, command_context, **kwargs):
|
||||
"""Build a JS shell to use to run the rooting hazard analysis."""
|
||||
# The JS shell requires some specific configuration settings to execute
|
||||
# the hazard analysis code, and configuration is done via mozconfig.
|
||||
@@ -177,7 +173,7 @@ def build_shell(command_context, **kwargs):
|
||||
# Transmit the mozconfig location to build subprocesses.
|
||||
os.environ["MOZCONFIG"] = mozconfig_path
|
||||
|
||||
setup_env_for_tools(os.environ)
|
||||
self.setup_env_for_tools(os.environ)
|
||||
|
||||
# Set a default objdir for the shell, for developer builds.
|
||||
os.environ.setdefault(
|
||||
@@ -188,18 +184,16 @@ def build_shell(command_context, **kwargs):
|
||||
"build", command_context._mach_context, **kwargs
|
||||
)
|
||||
|
||||
|
||||
def read_json_file(filename):
|
||||
def read_json_file(self, filename):
|
||||
with open(filename) as fh:
|
||||
return json.load(fh)
|
||||
|
||||
|
||||
def ensure_shell(command_context, objdir):
|
||||
def ensure_shell(self, command_context, objdir):
|
||||
if objdir is None:
|
||||
objdir = os.path.join(command_context.topsrcdir, "obj-haz-shell")
|
||||
|
||||
try:
|
||||
binaries = read_json_file(os.path.join(objdir, "binaries.json"))
|
||||
binaries = self.read_json_file(os.path.join(objdir, "binaries.json"))
|
||||
info = [b for b in binaries["programs"] if b["program"] == "js"][0]
|
||||
return os.path.join(objdir, info["install_target"], "js")
|
||||
except (OSError, KeyError):
|
||||
@@ -209,7 +203,6 @@ no shell found in %s -- must build the JS shell with `mach hazards build-shell`
|
||||
% objdir
|
||||
)
|
||||
|
||||
|
||||
@inherit_command_args("build")
|
||||
@SubCommand(
|
||||
"hazards",
|
||||
@@ -225,17 +218,19 @@ no shell found in %s -- must build the JS shell with `mach hazards build-shell`
|
||||
@CommandArgument(
|
||||
"--work-dir", default=None, help="Directory for output and working files."
|
||||
)
|
||||
def gather_hazard_data(command_context, **kwargs):
|
||||
def gather_hazard_data(self, command_context, **kwargs):
|
||||
"""Gather analysis information by compiling the tree"""
|
||||
application = kwargs["application"]
|
||||
objdir = kwargs["haz_objdir"]
|
||||
if objdir is None:
|
||||
objdir = os.environ.get("HAZ_OBJDIR")
|
||||
if objdir is None:
|
||||
objdir = os.path.join(command_context.topsrcdir, "obj-analyzed-" + application)
|
||||
objdir = os.path.join(
|
||||
command_context.topsrcdir, "obj-analyzed-" + application
|
||||
)
|
||||
|
||||
work_dir = get_work_dir(command_context, application, kwargs["work_dir"])
|
||||
ensure_dir_exists(work_dir)
|
||||
work_dir = self.get_work_dir(command_context, application, kwargs["work_dir"])
|
||||
self.ensure_dir_exists(work_dir)
|
||||
with open(os.path.join(work_dir, "defaults.py"), "wt") as fh:
|
||||
data = textwrap.dedent(
|
||||
"""\
|
||||
@@ -247,11 +242,11 @@ def gather_hazard_data(command_context, **kwargs):
|
||||
gcc_bin = "{gcc_dir}/bin"
|
||||
"""
|
||||
).format(
|
||||
script_dir=script_dir(command_context),
|
||||
script_dir=self.script_dir(command_context),
|
||||
objdir=objdir,
|
||||
srcdir=command_context.topsrcdir,
|
||||
sixgill_dir=sixgill_dir(),
|
||||
gcc_dir=gcc_dir(),
|
||||
sixgill_dir=self.sixgill_dir(),
|
||||
gcc_dir=self.gcc_dir(),
|
||||
)
|
||||
fh.write(data)
|
||||
|
||||
@@ -265,7 +260,7 @@ def gather_hazard_data(command_context, **kwargs):
|
||||
)
|
||||
args = [
|
||||
sys.executable,
|
||||
os.path.join(script_dir(command_context), "analyze.py"),
|
||||
os.path.join(self.script_dir(command_context), "analyze.py"),
|
||||
"dbs",
|
||||
"--upto",
|
||||
"dbs",
|
||||
@@ -275,7 +270,6 @@ def gather_hazard_data(command_context, **kwargs):
|
||||
|
||||
return command_context.run_process(args=args, cwd=work_dir, pass_thru=True)
|
||||
|
||||
|
||||
@inherit_command_args("build")
|
||||
@SubCommand("hazards", "compile", description=argparse.SUPPRESS)
|
||||
@CommandArgument(
|
||||
@@ -292,7 +286,7 @@ def gather_hazard_data(command_context, **kwargs):
|
||||
default=os.environ.get("HAZ_OBJDIR"),
|
||||
help="Write object files to this directory.",
|
||||
)
|
||||
def inner_compile(command_context, **kwargs):
|
||||
def inner_compile(self, command_context, **kwargs):
|
||||
"""Build a source tree and gather analysis information while running
|
||||
under the influence of the analysis collection server."""
|
||||
|
||||
@@ -329,12 +323,12 @@ def inner_compile(command_context, **kwargs):
|
||||
env["MOZCONFIG"] = os.path.join(command_context.topsrcdir, mozconfig_path)
|
||||
|
||||
# hazard mozconfigs need to find binaries in .mozbuild
|
||||
env["MOZBUILD_STATE_PATH"] = state_dir()
|
||||
env["MOZBUILD_STATE_PATH"] = self.state_dir()
|
||||
|
||||
# Suppress the gathering of sources, to save disk space and memory.
|
||||
env["XGILL_NO_SOURCE"] = "1"
|
||||
|
||||
setup_env_for_tools(env)
|
||||
self.setup_env_for_tools(env)
|
||||
|
||||
if "haz_objdir" in kwargs:
|
||||
env["MOZ_OBJDIR"] = kwargs.pop("haz_objdir")
|
||||
@@ -343,7 +337,6 @@ def inner_compile(command_context, **kwargs):
|
||||
"build", command_context._mach_context, **kwargs
|
||||
)
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"hazards", "analyze", description="Analyzed gathered data for rooting hazards"
|
||||
)
|
||||
@@ -365,12 +358,12 @@ def inner_compile(command_context, **kwargs):
|
||||
nargs=argparse.REMAINDER,
|
||||
help="Remaining non-optional arguments to analyze.py script",
|
||||
)
|
||||
def analyze(command_context, application, shell_objdir, work_dir, extra):
|
||||
def analyze(self, command_context, application, shell_objdir, work_dir, extra):
|
||||
"""Analyzed gathered data for rooting hazards"""
|
||||
|
||||
shell = ensure_shell(command_context, shell_objdir)
|
||||
shell = self.ensure_shell(command_context, shell_objdir)
|
||||
args = [
|
||||
os.path.join(script_dir(command_context), "analyze.py"),
|
||||
os.path.join(self.script_dir(command_context), "analyze.py"),
|
||||
"--js",
|
||||
shell,
|
||||
]
|
||||
@@ -382,13 +375,12 @@ def analyze(command_context, application, shell_objdir, work_dir, extra):
|
||||
"-v",
|
||||
]
|
||||
|
||||
setup_env_for_tools(os.environ)
|
||||
setup_env_for_shell(os.environ, shell)
|
||||
self.setup_env_for_tools(os.environ)
|
||||
self.setup_env_for_shell(os.environ, shell)
|
||||
|
||||
work_dir = get_work_dir(command_context, application, work_dir)
|
||||
work_dir = self.get_work_dir(command_context, application, work_dir)
|
||||
return command_context.run_process(args=args, cwd=work_dir, pass_thru=True)
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"hazards",
|
||||
"self-test",
|
||||
@@ -399,21 +391,21 @@ def analyze(command_context, application, shell_objdir, work_dir, extra):
|
||||
default=None,
|
||||
help="objdir containing the optimized JS shell for running the analysis.",
|
||||
)
|
||||
def self_test(command_context, shell_objdir):
|
||||
def self_test(self, command_context, shell_objdir):
|
||||
"""Analyzed gathered data for rooting hazards"""
|
||||
shell = ensure_shell(command_context, shell_objdir)
|
||||
shell = self.ensure_shell(command_context, shell_objdir)
|
||||
args = [
|
||||
os.path.join(script_dir(command_context), "run-test.py"),
|
||||
os.path.join(self.script_dir(command_context), "run-test.py"),
|
||||
"-v",
|
||||
"--js",
|
||||
shell,
|
||||
"--sixgill",
|
||||
os.path.join(tools_dir(), "sixgill"),
|
||||
os.path.join(self.tools_dir(), "sixgill"),
|
||||
"--gccdir",
|
||||
gcc_dir(),
|
||||
self.gcc_dir(),
|
||||
]
|
||||
|
||||
setup_env_for_tools(os.environ)
|
||||
setup_env_for_shell(os.environ, shell)
|
||||
self.setup_env_for_tools(os.environ)
|
||||
self.setup_env_for_shell(os.environ, shell)
|
||||
|
||||
return command_context.run_process(args=args, pass_thru=True)
|
||||
|
||||
@@ -10,11 +10,13 @@ import sys
|
||||
from argparse import Namespace
|
||||
|
||||
from mozbuild.base import (
|
||||
MachCommandBase,
|
||||
MachCommandConditions as conditions,
|
||||
MozbuildObject,
|
||||
)
|
||||
|
||||
from mach.decorators import (
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
|
||||
@@ -226,16 +228,17 @@ def get_parser():
|
||||
return parser
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command(
|
||||
"reftest",
|
||||
category="testing",
|
||||
description="Run reftests (layout and graphics correctness).",
|
||||
parser=get_parser,
|
||||
)
|
||||
def run_reftest(command_context, **kwargs):
|
||||
def run_reftest(self, command_context, **kwargs):
|
||||
kwargs["suite"] = "reftest"
|
||||
return _run_reftest(command_context, **kwargs)
|
||||
|
||||
return self._run_reftest(command_context, **kwargs)
|
||||
|
||||
@Command(
|
||||
"jstestbrowser",
|
||||
@@ -243,7 +246,7 @@ def run_reftest(command_context, **kwargs):
|
||||
description="Run js/src/tests in the browser.",
|
||||
parser=get_parser,
|
||||
)
|
||||
def run_jstestbrowser(command_context, **kwargs):
|
||||
def run_jstestbrowser(self, command_context, **kwargs):
|
||||
if "--enable-js-shell" not in command_context.mozconfig["configure_args"]:
|
||||
raise Exception(
|
||||
"jstestbrowser requires --enable-js-shell be specified in mozconfig."
|
||||
@@ -252,8 +255,7 @@ def run_jstestbrowser(command_context, **kwargs):
|
||||
"build", command_context._mach_context, what=["stage-jstests"]
|
||||
)
|
||||
kwargs["suite"] = "jstestbrowser"
|
||||
return _run_reftest(command_context, **kwargs)
|
||||
|
||||
return self._run_reftest(command_context, **kwargs)
|
||||
|
||||
@Command(
|
||||
"crashtest",
|
||||
@@ -261,12 +263,11 @@ def run_jstestbrowser(command_context, **kwargs):
|
||||
description="Run crashtests (Check if crashes on a page).",
|
||||
parser=get_parser,
|
||||
)
|
||||
def run_crashtest(command_context, **kwargs):
|
||||
def run_crashtest(self, command_context, **kwargs):
|
||||
kwargs["suite"] = "crashtest"
|
||||
return _run_reftest(command_context, **kwargs)
|
||||
return self._run_reftest(command_context, **kwargs)
|
||||
|
||||
|
||||
def _run_reftest(command_context, **kwargs):
|
||||
def _run_reftest(self, command_context, **kwargs):
|
||||
kwargs["topsrcdir"] = command_context.topsrcdir
|
||||
process_test_objects(kwargs)
|
||||
reftest = command_context._spawn(ReftestRunner)
|
||||
@@ -279,7 +280,9 @@ def _run_reftest(command_context, **kwargs):
|
||||
InstallIntent,
|
||||
)
|
||||
|
||||
install = InstallIntent.NO if kwargs.get("no_install") else InstallIntent.YES
|
||||
install = (
|
||||
InstallIntent.NO if kwargs.get("no_install") else InstallIntent.YES
|
||||
)
|
||||
verbose = False
|
||||
if (
|
||||
kwargs.get("log_mach_verbose")
|
||||
|
||||
@@ -10,8 +10,10 @@ from argparse import Namespace
|
||||
from functools import partial
|
||||
|
||||
from mach.decorators import (
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
logger = None
|
||||
@@ -105,13 +107,15 @@ def setup_argument_parser():
|
||||
return parser
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class ReftestCommands(MachCommandBase):
|
||||
@Command(
|
||||
"reftest",
|
||||
category="testing",
|
||||
description="Run the reftest harness.",
|
||||
parser=setup_argument_parser,
|
||||
)
|
||||
def reftest(command_context, **kwargs):
|
||||
def reftest(self, command_context, **kwargs):
|
||||
command_context._mach_context.activate_mozharness_venv()
|
||||
kwargs["suite"] = "reftest"
|
||||
return run_reftest(command_context._mach_context, **kwargs)
|
||||
|
||||
@@ -11,6 +11,7 @@ import os
|
||||
import mozpack.path as mozpath
|
||||
|
||||
from mozbuild.base import (
|
||||
MachCommandBase,
|
||||
MachCommandConditions as conditions,
|
||||
)
|
||||
|
||||
@@ -20,6 +21,7 @@ from mozbuild.shellutil import (
|
||||
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
Command,
|
||||
SubCommand,
|
||||
)
|
||||
@@ -47,16 +49,17 @@ def REMOVED(cls):
|
||||
return False
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command(
|
||||
"android",
|
||||
category="devenv",
|
||||
description="Run Android-specific commands.",
|
||||
conditions=[conditions.is_android],
|
||||
)
|
||||
def android(command_context):
|
||||
def android(self, command_context):
|
||||
pass
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"android",
|
||||
"assemble-app",
|
||||
@@ -64,8 +67,8 @@ def android(command_context):
|
||||
See http://firefox-source-docs.mozilla.org/build/buildsystem/toolchains.html#firefox-for-android-with-gradle""", # NOQA: E501
|
||||
)
|
||||
@CommandArgument("args", nargs=argparse.REMAINDER)
|
||||
def android_assemble_app(command_context, args):
|
||||
ret = gradle(
|
||||
def android_assemble_app(self, command_context, args):
|
||||
ret = self.gradle(
|
||||
command_context,
|
||||
command_context.substs["GRADLE_ANDROID_APP_TASKS"] + ["-x", "lint"] + args,
|
||||
verbose=True,
|
||||
@@ -73,7 +76,6 @@ def android_assemble_app(command_context, args):
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"android",
|
||||
"generate-sdk-bindings",
|
||||
@@ -82,20 +84,24 @@ def android_assemble_app(command_context, args):
|
||||
@CommandArgument(
|
||||
"inputs",
|
||||
nargs="+",
|
||||
help="config files, like [/path/to/ClassName-classes.txt]+",
|
||||
help="config files, " "like [/path/to/ClassName-classes.txt]+",
|
||||
)
|
||||
@CommandArgument("args", nargs=argparse.REMAINDER)
|
||||
def android_generate_sdk_bindings(command_context, inputs, args):
|
||||
def android_generate_sdk_bindings(self, command_context, inputs, args):
|
||||
import itertools
|
||||
|
||||
def stem(input):
|
||||
# Turn "/path/to/ClassName-classes.txt" into "ClassName".
|
||||
return os.path.basename(input).rsplit("-classes.txt", 1)[0]
|
||||
|
||||
bindings_inputs = list(itertools.chain(*((input, stem(input)) for input in inputs)))
|
||||
bindings_args = "-Pgenerate_sdk_bindings_args={}".format(";".join(bindings_inputs))
|
||||
bindings_inputs = list(
|
||||
itertools.chain(*((input, stem(input)) for input in inputs))
|
||||
)
|
||||
bindings_args = "-Pgenerate_sdk_bindings_args={}".format(
|
||||
";".join(bindings_inputs)
|
||||
)
|
||||
|
||||
ret = gradle(
|
||||
ret = self.gradle(
|
||||
command_context,
|
||||
command_context.substs["GRADLE_ANDROID_GENERATE_SDK_BINDINGS_TASKS"]
|
||||
+ [bindings_args]
|
||||
@@ -105,68 +111,64 @@ def android_generate_sdk_bindings(command_context, inputs, args):
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"android",
|
||||
"generate-generated-jni-wrappers",
|
||||
"""Generate GeckoView JNI wrappers used when building GeckoView.""",
|
||||
)
|
||||
@CommandArgument("args", nargs=argparse.REMAINDER)
|
||||
def android_generate_generated_jni_wrappers(command_context, args):
|
||||
ret = gradle(
|
||||
def android_generate_generated_jni_wrappers(self, command_context, args):
|
||||
ret = self.gradle(
|
||||
command_context,
|
||||
command_context.substs["GRADLE_ANDROID_GENERATE_GENERATED_JNI_WRAPPERS_TASKS"]
|
||||
command_context.substs[
|
||||
"GRADLE_ANDROID_GENERATE_GENERATED_JNI_WRAPPERS_TASKS"
|
||||
]
|
||||
+ args,
|
||||
verbose=True,
|
||||
)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"android",
|
||||
"api-lint",
|
||||
"""Run Android api-lint.
|
||||
REMOVED/DEPRECATED: Use 'mach lint --linter android-api-lint'.""",
|
||||
)
|
||||
def android_apilint_REMOVED(command_context):
|
||||
def android_apilint_REMOVED(self, command_context):
|
||||
print(LINT_DEPRECATION_MESSAGE)
|
||||
return 1
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"android",
|
||||
"test",
|
||||
"""Run Android test.
|
||||
REMOVED/DEPRECATED: Use 'mach lint --linter android-test'.""",
|
||||
)
|
||||
def android_test_REMOVED(command_context):
|
||||
def android_test_REMOVED(self, command_context):
|
||||
print(LINT_DEPRECATION_MESSAGE)
|
||||
return 1
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"android",
|
||||
"lint",
|
||||
"""Run Android lint.
|
||||
REMOVED/DEPRECATED: Use 'mach lint --linter android-lint'.""",
|
||||
)
|
||||
def android_lint_REMOVED(command_context):
|
||||
def android_lint_REMOVED(self, command_context):
|
||||
print(LINT_DEPRECATION_MESSAGE)
|
||||
return 1
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"android",
|
||||
"checkstyle",
|
||||
"""Run Android checkstyle.
|
||||
REMOVED/DEPRECATED: Use 'mach lint --linter android-checkstyle'.""",
|
||||
)
|
||||
def android_checkstyle_REMOVED(command_context):
|
||||
def android_checkstyle_REMOVED(self, command_context):
|
||||
print(LINT_DEPRECATION_MESSAGE)
|
||||
return 1
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"android",
|
||||
"gradle-dependencies",
|
||||
@@ -174,11 +176,11 @@ def android_checkstyle_REMOVED(command_context):
|
||||
See http://firefox-source-docs.mozilla.org/build/buildsystem/toolchains.html#firefox-for-android-with-gradle""", # NOQA: E501
|
||||
)
|
||||
@CommandArgument("args", nargs=argparse.REMAINDER)
|
||||
def android_gradle_dependencies(command_context, args):
|
||||
def android_gradle_dependencies(self, command_context, args):
|
||||
# We don't want to gate producing dependency archives on clean
|
||||
# lint or checkstyle, particularly because toolchain versions
|
||||
# can change the outputs for those processes.
|
||||
gradle(
|
||||
self.gradle(
|
||||
command_context,
|
||||
command_context.substs["GRADLE_ANDROID_DEPENDENCIES_TASKS"]
|
||||
+ ["--continue"]
|
||||
@@ -188,7 +190,6 @@ def android_gradle_dependencies(command_context, args):
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"android",
|
||||
"archive-geckoview",
|
||||
@@ -196,8 +197,8 @@ def android_gradle_dependencies(command_context, args):
|
||||
See http://firefox-source-docs.mozilla.org/build/buildsystem/toolchains.html#firefox-for-android-with-gradle""", # NOQA: E501
|
||||
)
|
||||
@CommandArgument("args", nargs=argparse.REMAINDER)
|
||||
def android_archive_geckoview(command_context, args):
|
||||
ret = gradle(
|
||||
def android_archive_geckoview(self, command_context, args):
|
||||
ret = self.gradle(
|
||||
command_context,
|
||||
command_context.substs["GRADLE_ANDROID_ARCHIVE_GECKOVIEW_TASKS"] + args,
|
||||
verbose=True,
|
||||
@@ -205,13 +206,13 @@ def android_archive_geckoview(command_context, args):
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
@SubCommand("android", "build-geckoview_example", """Build geckoview_example """)
|
||||
@CommandArgument("args", nargs=argparse.REMAINDER)
|
||||
def android_build_geckoview_example(command_context, args):
|
||||
gradle(
|
||||
def android_build_geckoview_example(self, command_context, args):
|
||||
self.gradle(
|
||||
command_context,
|
||||
command_context.substs["GRADLE_ANDROID_BUILD_GECKOVIEW_EXAMPLE_TASKS"] + args,
|
||||
command_context.substs["GRADLE_ANDROID_BUILD_GECKOVIEW_EXAMPLE_TASKS"]
|
||||
+ args,
|
||||
verbose=True,
|
||||
)
|
||||
|
||||
@@ -222,13 +223,15 @@ def android_build_geckoview_example(command_context, args):
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
@SubCommand("android", "install-geckoview_example", """Install geckoview_example """)
|
||||
@SubCommand(
|
||||
"android", "install-geckoview_example", """Install geckoview_example """
|
||||
)
|
||||
@CommandArgument("args", nargs=argparse.REMAINDER)
|
||||
def android_install_geckoview_example(command_context, args):
|
||||
gradle(
|
||||
def android_install_geckoview_example(self, command_context, args):
|
||||
self.gradle(
|
||||
command_context,
|
||||
command_context.substs["GRADLE_ANDROID_INSTALL_GECKOVIEW_EXAMPLE_TASKS"] + args,
|
||||
command_context.substs["GRADLE_ANDROID_INSTALL_GECKOVIEW_EXAMPLE_TASKS"]
|
||||
+ args,
|
||||
verbose=True,
|
||||
)
|
||||
|
||||
@@ -239,17 +242,19 @@ def android_install_geckoview_example(command_context, args):
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"android",
|
||||
"geckoview-docs",
|
||||
"""Create GeckoView javadoc and optionally upload to Github""",
|
||||
)
|
||||
@CommandArgument("--archive", action="store_true", help="Generate a javadoc archive.")
|
||||
@CommandArgument(
|
||||
"--archive", action="store_true", help="Generate a javadoc archive."
|
||||
)
|
||||
@CommandArgument(
|
||||
"--upload",
|
||||
metavar="USER/REPO",
|
||||
help="Upload geckoview documentation to Github, using the specified USER/REPO.",
|
||||
help="Upload geckoview documentation to Github, "
|
||||
"using the specified USER/REPO.",
|
||||
)
|
||||
@CommandArgument(
|
||||
"--upload-branch",
|
||||
@@ -270,6 +275,7 @@ def android_install_geckoview_example(command_context, args):
|
||||
help="Use the specified message for commits.",
|
||||
)
|
||||
def android_geckoview_docs(
|
||||
self,
|
||||
command_context,
|
||||
archive,
|
||||
upload,
|
||||
@@ -284,7 +290,7 @@ def android_geckoview_docs(
|
||||
else command_context.substs["GRADLE_ANDROID_GECKOVIEW_DOCS_TASKS"]
|
||||
)
|
||||
|
||||
ret = gradle(command_context, tasks, verbose=True)
|
||||
ret = self.gradle(command_context, tasks, verbose=True)
|
||||
if ret or not upload:
|
||||
return ret
|
||||
|
||||
@@ -360,7 +366,9 @@ def android_geckoview_docs(
|
||||
mozfile.extract_zip(src_tar, dst_path)
|
||||
|
||||
# Commit and push.
|
||||
command_context.run_process(["git", "add", "--all"], append_env=env, pass_thru=True)
|
||||
command_context.run_process(
|
||||
["git", "add", "--all"], append_env=env, pass_thru=True
|
||||
)
|
||||
if (
|
||||
command_context.run_process(
|
||||
["git", "diff", "--cached", "--quiet"],
|
||||
@@ -385,7 +393,6 @@ def android_geckoview_docs(
|
||||
mozfile.remove(keyfile)
|
||||
return 0
|
||||
|
||||
|
||||
@Command(
|
||||
"gradle",
|
||||
category="devenv",
|
||||
@@ -399,7 +406,7 @@ def android_geckoview_docs(
|
||||
help="Verbose output for what commands the build is running.",
|
||||
)
|
||||
@CommandArgument("args", nargs=argparse.REMAINDER)
|
||||
def gradle(command_context, args, verbose=False):
|
||||
def gradle(self, command_context, args, verbose=False):
|
||||
if not verbose:
|
||||
# Avoid logging the command
|
||||
command_context.log_manager.terminal_handler.setLevel(logging.CRITICAL)
|
||||
@@ -457,12 +464,13 @@ def gradle(command_context, args, verbose=False):
|
||||
cwd=mozpath.join(command_context.topsrcdir),
|
||||
)
|
||||
|
||||
|
||||
@Command("gradle-install", category="devenv", conditions=[REMOVED])
|
||||
def gradle_install_REMOVED(command_context):
|
||||
def gradle_install_REMOVED(self, command_context):
|
||||
pass
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class AndroidEmulatorCommands(MachCommandBase):
|
||||
@Command(
|
||||
"android-emulator",
|
||||
category="devenv",
|
||||
@@ -482,12 +490,15 @@ def gradle_install_REMOVED(command_context):
|
||||
'By default, "arm" will be used if the current build environment '
|
||||
'architecture is arm; otherwise "x86_64".',
|
||||
)
|
||||
@CommandArgument("--wait", action="store_true", help="Wait for emulator to be closed.")
|
||||
@CommandArgument(
|
||||
"--wait", action="store_true", help="Wait for emulator to be closed."
|
||||
)
|
||||
@CommandArgument("--gpu", help="Over-ride the emulator -gpu argument.")
|
||||
@CommandArgument(
|
||||
"--verbose", action="store_true", help="Log informative status messages."
|
||||
)
|
||||
def emulator(
|
||||
self,
|
||||
command_context,
|
||||
version,
|
||||
wait=False,
|
||||
|
||||
@@ -9,22 +9,26 @@ Mach commands are defined via Python decorators.
|
||||
All the relevant decorators are defined in the *mach.decorators* module.
|
||||
The important decorators are as follows:
|
||||
|
||||
:py:func:`CommandProvider <mach.decorators.CommandProvider>`
|
||||
A class decorator that denotes that a class contains mach
|
||||
commands. The decorator takes no arguments.
|
||||
|
||||
:py:func:`Command <mach.decorators.Command>`
|
||||
A function decorator that denotes that the function should be called when
|
||||
A method decorator that denotes that the method should be called when
|
||||
the specified command is requested. The decorator takes a command name
|
||||
as its first argument and a number of additional arguments to
|
||||
configure the behavior of the command. The decorated function must take a
|
||||
``command_context`` argument as its first.
|
||||
configure the behavior of the command. The decorated method must take a
|
||||
``command_context`` argument as its first (after ``self``).
|
||||
``command_context`` is a properly configured instance of a ``MozbuildObject``
|
||||
subclass, meaning it can be used for accessing things like the current config
|
||||
and running processes.
|
||||
|
||||
:py:func:`CommandArgument <mach.decorators.CommandArgument>`
|
||||
A function decorator that defines an argument to the command. Its
|
||||
A method decorator that defines an argument to the command. Its
|
||||
arguments are essentially proxied to ArgumentParser.add_argument()
|
||||
|
||||
:py:func:`SubCommand <mach.decorators.SubCommand>`
|
||||
A function decorator that denotes that the function should be a
|
||||
A method decorator that denotes that the method should be a
|
||||
sub-command to an existing ``@Command``. The decorator takes the
|
||||
parent command name as its first argument and the sub-command name
|
||||
as its second argument.
|
||||
@@ -32,6 +36,8 @@ The important decorators are as follows:
|
||||
``@CommandArgument`` can be used on ``@SubCommand`` instances just
|
||||
like they can on ``@Command`` instances.
|
||||
|
||||
Classes with the ``@CommandProvider`` decorator **must** subclass
|
||||
``MachCommandBase`` and have a compatible ``__init__`` method.
|
||||
|
||||
Here is a complete example:
|
||||
|
||||
@@ -39,13 +45,17 @@ Here is a complete example:
|
||||
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
@CommandProvider
|
||||
class MyClass(MachCommandBase):
|
||||
@Command('doit', help='Do ALL OF THE THINGS.')
|
||||
@CommandArgument('--force', '-f', action='store_true',
|
||||
help='Force doing it.')
|
||||
def doit(command_context, force=False):
|
||||
def doit(self, command_context, force=False):
|
||||
# Do stuff here.
|
||||
|
||||
When the module is loaded, the decorators tell mach about all handlers.
|
||||
@@ -69,7 +79,7 @@ define a series of conditions on the
|
||||
:py:func:`Command <mach.decorators.Command>` decorator.
|
||||
|
||||
A condition is simply a function that takes an instance of the
|
||||
:py:func:`mozbuild.base.MachCommandBase` class as an argument, and
|
||||
:py:func:`mach.decorators.CommandProvider` class as an argument, and
|
||||
returns ``True`` or ``False``. If any of the conditions defined on a
|
||||
command return ``False``, the command will not be runnable. The
|
||||
docstring of a condition function is used in error messages, to explain
|
||||
@@ -80,6 +90,7 @@ Here is an example:
|
||||
.. code-block:: python
|
||||
|
||||
from mach.decorators import (
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
|
||||
@@ -87,10 +98,19 @@ Here is an example:
|
||||
"""The build needs to be available."""
|
||||
return cls.build_path is not None
|
||||
|
||||
@CommandProvider
|
||||
class MyClass(MachCommandBase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MyClass, self).__init__(*args, **kwargs)
|
||||
self.build_path = ...
|
||||
|
||||
@Command('run_tests', conditions=[build_available])
|
||||
def run_tests(command_context):
|
||||
def run_tests(self, command_context):
|
||||
# Do stuff here.
|
||||
|
||||
It is important to make sure that any state needed by the condition is
|
||||
available to instances of the command provider.
|
||||
|
||||
By default all commands without any conditions applied will be runnable,
|
||||
but it is possible to change this behaviour by setting
|
||||
``require_conditions`` to ``True``:
|
||||
|
||||
@@ -116,6 +116,7 @@ For example:
|
||||
|
||||
from mach.decorators import (
|
||||
Command,
|
||||
CommandProvider,
|
||||
SettingsProvider,
|
||||
)
|
||||
from mozbuild.base import MachCommandBase
|
||||
@@ -128,10 +129,15 @@ For example:
|
||||
('foo.baz', 'int', 'desc', 0, {'choices': set([0,1,2])}),
|
||||
]
|
||||
|
||||
@CommandProvider
|
||||
class Commands(MachCommandBase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Commands, self).__init__(*args, **kwargs)
|
||||
self.settings = self._mach_context.settings
|
||||
|
||||
@Command('command', category='misc',
|
||||
description='Prints a setting')
|
||||
def command(command_context):
|
||||
settings = command_context._mach_context.settings
|
||||
print(settings.a.b)
|
||||
for option in settings.foo:
|
||||
print(settings.foo[option])
|
||||
def command(self):
|
||||
print(self.settings.a.b)
|
||||
for option in self.settings.foo:
|
||||
print(self.settings.foo[option])
|
||||
|
||||
@@ -19,15 +19,17 @@ Adding Metrics to a new Command
|
||||
If you would like to submit telemetry metrics from your mach ``@Command``, you should take two steps:
|
||||
|
||||
#. Parameterize your ``@Command`` annotation with ``metrics_path``.
|
||||
#. Use the ``command_context.metrics`` handle provided by ``MachCommandBase``
|
||||
#. Use the ``self.metrics`` handle provided by ``MachCommandBase``
|
||||
|
||||
For example::
|
||||
|
||||
METRICS_PATH = os.path.abspath(os.path.join(__file__, '..', '..', 'metrics.yaml'))
|
||||
|
||||
@CommandProvider
|
||||
class CustomCommand(MachCommandBase):
|
||||
@Command('custom-command', metrics_path=METRICS_PATH)
|
||||
def custom_command(command_context):
|
||||
command_context.metrics.custom.foo.set('bar')
|
||||
def custom_command(self):
|
||||
self.metrics.custom.foo.set('bar')
|
||||
|
||||
Updating Generated Metrics Docs
|
||||
===============================
|
||||
|
||||
@@ -13,7 +13,8 @@ from itertools import chain
|
||||
|
||||
import attr
|
||||
|
||||
from mach.decorators import Command, CommandArgument, SubCommand
|
||||
from mach.decorators import CommandProvider, Command, CommandArgument, SubCommand
|
||||
from mozbuild.base import MachCommandBase
|
||||
from mozbuild.util import memoize
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
@@ -36,19 +37,19 @@ def render_template(shell, context):
|
||||
return template % context
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class BuiltinCommands(MachCommandBase):
|
||||
@memoize
|
||||
def command_handlers(command_context):
|
||||
def command_handlers(self, command_context):
|
||||
"""A dictionary of command handlers keyed by command name."""
|
||||
return command_context._mach_context.commands.command_handlers
|
||||
|
||||
|
||||
@memoize
|
||||
def commands(command_context):
|
||||
def commands(self, command_context):
|
||||
"""A sorted list of all command names."""
|
||||
return sorted(command_handlers(command_context))
|
||||
return sorted(self.command_handlers(command_context))
|
||||
|
||||
|
||||
def _get_parser_options(parser):
|
||||
def _get_parser_options(self, parser):
|
||||
options = {}
|
||||
for action in parser._actions:
|
||||
# ignore positional args
|
||||
@@ -62,20 +63,18 @@ def _get_parser_options(parser):
|
||||
options[tuple(action.option_strings)] = action.help or ""
|
||||
return options
|
||||
|
||||
|
||||
@memoize
|
||||
def global_options(command_context):
|
||||
def global_options(self, command_context):
|
||||
"""Return a dict of global options.
|
||||
|
||||
Of the form `{("-o", "--option"): "description"}`.
|
||||
"""
|
||||
for group in command_context._mach_context.global_parser._action_groups:
|
||||
if group.title == "Global Arguments":
|
||||
return _get_parser_options(group)
|
||||
|
||||
return self._get_parser_options(group)
|
||||
|
||||
@memoize
|
||||
def _get_handler_options(handler):
|
||||
def _get_handler_options(self, handler):
|
||||
"""Return a dict of options for the given handler.
|
||||
|
||||
Of the form `{("-o", "--option"): "description"}`.
|
||||
@@ -89,14 +88,13 @@ def _get_handler_options(handler):
|
||||
options[tuple(option_strings)] = val.get("help", "")
|
||||
|
||||
if handler._parser:
|
||||
options.update(_get_parser_options(handler.parser))
|
||||
options.update(self._get_parser_options(handler.parser))
|
||||
|
||||
return options
|
||||
|
||||
|
||||
def _get_handler_info(handler):
|
||||
def _get_handler_info(self, handler):
|
||||
try:
|
||||
options = _get_handler_options(handler)
|
||||
options = self._get_handler_options(handler)
|
||||
except (Exception, SystemExit):
|
||||
# We don't want misbehaving commands to break tab completion,
|
||||
# ignore any exceptions.
|
||||
@@ -104,7 +102,7 @@ def _get_handler_info(handler):
|
||||
|
||||
subcommands = []
|
||||
for sub in sorted(handler.subcommand_handlers):
|
||||
subcommands.append(_get_handler_info(handler.subcommand_handlers[sub]))
|
||||
subcommands.append(self._get_handler_info(handler.subcommand_handlers[sub]))
|
||||
|
||||
return CommandInfo(
|
||||
name=handler.name,
|
||||
@@ -114,22 +112,21 @@ def _get_handler_info(handler):
|
||||
subcommand=handler.subcommand,
|
||||
)
|
||||
|
||||
|
||||
@memoize
|
||||
def commands_info(command_context):
|
||||
def commands_info(self, command_context):
|
||||
"""Return a list of CommandInfo objects for each command."""
|
||||
commands_info = []
|
||||
# Loop over self.commands() rather than self.command_handlers().items() for
|
||||
# alphabetical order.
|
||||
for c in commands(command_context):
|
||||
commands_info.append(_get_handler_info(command_handlers(command_context)[c]))
|
||||
for c in self.commands(command_context):
|
||||
commands_info.append(
|
||||
self._get_handler_info(self.command_handlers(command_context)[c])
|
||||
)
|
||||
return commands_info
|
||||
|
||||
|
||||
@Command("mach-commands", category="misc", description="List all mach commands.")
|
||||
def run_commands(command_context):
|
||||
print("\n".join(commands(command_context)))
|
||||
|
||||
def run_commands(self, command_context):
|
||||
print("\n".join(self.commands(command_context)))
|
||||
|
||||
@Command(
|
||||
"mach-debug-commands",
|
||||
@@ -143,10 +140,10 @@ def run_commands(command_context):
|
||||
nargs="?",
|
||||
help="Only display commands containing given substring.",
|
||||
)
|
||||
def run_debug_commands(command_context, match=None):
|
||||
def run_debug_commands(self, command_context, match=None):
|
||||
import inspect
|
||||
|
||||
for command, handler in command_handlers(command_context).items():
|
||||
for command, handler in self.command_handlers(command_context).items():
|
||||
if match and match not in command:
|
||||
continue
|
||||
|
||||
@@ -161,7 +158,6 @@ def run_debug_commands(command_context, match=None):
|
||||
print("Method: %s" % handler.method)
|
||||
print("")
|
||||
|
||||
|
||||
@Command(
|
||||
"mach-completion",
|
||||
category="misc",
|
||||
@@ -170,25 +166,25 @@ def run_debug_commands(command_context, match=None):
|
||||
@CommandArgument(
|
||||
"args", default=None, nargs=argparse.REMAINDER, help="Command to complete."
|
||||
)
|
||||
def run_completion(command_context, args):
|
||||
def run_completion(self, command_context, args):
|
||||
if not args:
|
||||
print("\n".join(commands(command_context)))
|
||||
print("\n".join(self.commands(command_context)))
|
||||
return
|
||||
|
||||
is_help = "help" in args
|
||||
command = None
|
||||
for i, arg in enumerate(args):
|
||||
if arg in commands(command_context):
|
||||
if arg in self.commands(command_context):
|
||||
command = arg
|
||||
args = args[i + 1 :]
|
||||
break
|
||||
|
||||
# If no command is typed yet, just offer the commands.
|
||||
if not command:
|
||||
print("\n".join(commands(command_context)))
|
||||
print("\n".join(self.commands(command_context)))
|
||||
return
|
||||
|
||||
handler = command_handlers(command_context)[command]
|
||||
handler = self.command_handlers(command_context)[command]
|
||||
# If a subcommand was typed, update the handler.
|
||||
for arg in args:
|
||||
if arg in handler.subcommand_handlers:
|
||||
@@ -201,11 +197,10 @@ def run_completion(command_context, args):
|
||||
return
|
||||
|
||||
targets.append("help")
|
||||
targets.extend(chain(*_get_handler_options(handler).keys()))
|
||||
targets.extend(chain(*self._get_handler_options(handler).keys()))
|
||||
print("\n".join(targets))
|
||||
|
||||
|
||||
def _zsh_describe(value, description=None):
|
||||
def _zsh_describe(self, value, description=None):
|
||||
value = '"' + value.replace(":", "\\:")
|
||||
if description:
|
||||
description = subprocess.list2cmdline(
|
||||
@@ -221,7 +216,6 @@ def _zsh_describe(value, description=None):
|
||||
|
||||
return value
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"mach-completion",
|
||||
"bash",
|
||||
@@ -234,16 +228,16 @@ def _zsh_describe(value, description=None):
|
||||
default=None,
|
||||
help="File path to save completion script.",
|
||||
)
|
||||
def completion_bash(command_context, outfile):
|
||||
def completion_bash(self, command_context, outfile):
|
||||
commands_subcommands = []
|
||||
case_options = []
|
||||
case_subcommands = []
|
||||
for i, cmd in enumerate(commands_info(command_context)):
|
||||
for i, cmd in enumerate(self.commands_info(command_context)):
|
||||
# Build case statement for options.
|
||||
options = []
|
||||
for opt_strs, description in cmd.options.items():
|
||||
for opt in opt_strs:
|
||||
options.append(_zsh_describe(opt, None).strip('"'))
|
||||
options.append(self._zsh_describe(opt, None).strip('"'))
|
||||
|
||||
if options:
|
||||
case_options.append(
|
||||
@@ -262,14 +256,18 @@ def completion_bash(command_context, outfile):
|
||||
options = []
|
||||
for opt_strs, description in sub.options.items():
|
||||
for opt in opt_strs:
|
||||
options.append(_zsh_describe(opt, None))
|
||||
options.append(self._zsh_describe(opt, None))
|
||||
|
||||
if options:
|
||||
case_options.append(
|
||||
"\n".join(
|
||||
[
|
||||
' ("{} {}")'.format(sub.name, sub.subcommand),
|
||||
' opts="${{opts}} {}"'.format(" ".join(options)),
|
||||
' ("{} {}")'.format(
|
||||
sub.name, sub.subcommand
|
||||
),
|
||||
' opts="${{opts}} {}"'.format(
|
||||
" ".join(options)
|
||||
),
|
||||
" ;;",
|
||||
"",
|
||||
]
|
||||
@@ -277,7 +275,9 @@ def completion_bash(command_context, outfile):
|
||||
)
|
||||
|
||||
# Build case statement for subcommands.
|
||||
subcommands = [_zsh_describe(s.subcommand, None) for s in cmd.subcommands]
|
||||
subcommands = [
|
||||
self._zsh_describe(s.subcommand, None) for s in cmd.subcommands
|
||||
]
|
||||
if subcommands:
|
||||
commands_subcommands.append(
|
||||
'[{}]=" {} "'.format(
|
||||
@@ -289,7 +289,9 @@ def completion_bash(command_context, outfile):
|
||||
"\n".join(
|
||||
[
|
||||
" ({})".format(cmd.name),
|
||||
' subs="${{subs}} {}"'.format(" ".join(subcommands)),
|
||||
' subs="${{subs}} {}"'.format(
|
||||
" ".join(subcommands)
|
||||
),
|
||||
" ;;",
|
||||
"",
|
||||
]
|
||||
@@ -297,12 +299,12 @@ def completion_bash(command_context, outfile):
|
||||
)
|
||||
|
||||
globalopts = [
|
||||
opt for opt_strs in global_options(command_context) for opt in opt_strs
|
||||
opt for opt_strs in self.global_options(command_context) for opt in opt_strs
|
||||
]
|
||||
context = {
|
||||
"case_options": "\n".join(case_options),
|
||||
"case_subcommands": "\n".join(case_subcommands),
|
||||
"commands": " ".join(commands(command_context)),
|
||||
"commands": " ".join(self.commands(command_context)),
|
||||
"commands_subcommands": " ".join(sorted(commands_subcommands)),
|
||||
"globalopts": " ".join(sorted(globalopts)),
|
||||
}
|
||||
@@ -310,7 +312,6 @@ def completion_bash(command_context, outfile):
|
||||
outfile = open(outfile, "w") if outfile else sys.stdout
|
||||
print(render_template("bash", context), file=outfile)
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"mach-completion",
|
||||
"zsh",
|
||||
@@ -323,19 +324,19 @@ def completion_bash(command_context, outfile):
|
||||
default=None,
|
||||
help="File path to save completion script.",
|
||||
)
|
||||
def completion_zsh(command_context, outfile):
|
||||
def completion_zsh(self, command_context, outfile):
|
||||
commands_descriptions = []
|
||||
commands_subcommands = []
|
||||
case_options = []
|
||||
case_subcommands = []
|
||||
for i, cmd in enumerate(commands_info(command_context)):
|
||||
commands_descriptions.append(_zsh_describe(cmd.name, cmd.description))
|
||||
for i, cmd in enumerate(self.commands_info(command_context)):
|
||||
commands_descriptions.append(self._zsh_describe(cmd.name, cmd.description))
|
||||
|
||||
# Build case statement for options.
|
||||
options = []
|
||||
for opt_strs, description in cmd.options.items():
|
||||
for opt in opt_strs:
|
||||
options.append(_zsh_describe(opt, description))
|
||||
options.append(self._zsh_describe(opt, description))
|
||||
|
||||
if options:
|
||||
case_options.append(
|
||||
@@ -354,7 +355,7 @@ def completion_zsh(command_context, outfile):
|
||||
options = []
|
||||
for opt_strs, description in sub.options.items():
|
||||
for opt in opt_strs:
|
||||
options.append(_zsh_describe(opt, description))
|
||||
options.append(self._zsh_describe(opt, description))
|
||||
|
||||
if options:
|
||||
case_options.append(
|
||||
@@ -370,7 +371,7 @@ def completion_zsh(command_context, outfile):
|
||||
|
||||
# Build case statement for subcommands.
|
||||
subcommands = [
|
||||
_zsh_describe(s.subcommand, s.description) for s in cmd.subcommands
|
||||
self._zsh_describe(s.subcommand, s.description) for s in cmd.subcommands
|
||||
]
|
||||
if subcommands:
|
||||
commands_subcommands.append(
|
||||
@@ -391,9 +392,9 @@ def completion_zsh(command_context, outfile):
|
||||
)
|
||||
|
||||
globalopts = []
|
||||
for opt_strings, description in global_options(command_context).items():
|
||||
for opt_strings, description in self.global_options(command_context).items():
|
||||
for opt in opt_strings:
|
||||
globalopts.append(_zsh_describe(opt, description))
|
||||
globalopts.append(self._zsh_describe(opt, description))
|
||||
|
||||
context = {
|
||||
"case_options": "\n".join(case_options),
|
||||
@@ -406,7 +407,6 @@ def completion_zsh(command_context, outfile):
|
||||
outfile = open(outfile, "w") if outfile else sys.stdout
|
||||
print(render_template("zsh", context), file=outfile)
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"mach-completion",
|
||||
"fish",
|
||||
@@ -419,7 +419,7 @@ def completion_zsh(command_context, outfile):
|
||||
default=None,
|
||||
help="File path to save completion script.",
|
||||
)
|
||||
def completion_fish(command_context, outfile):
|
||||
def completion_fish(self, command_context, outfile):
|
||||
def _append_opt_strs(comp, opt_strs):
|
||||
for opt in opt_strs:
|
||||
if opt.startswith("--"):
|
||||
@@ -429,7 +429,7 @@ def completion_fish(command_context, outfile):
|
||||
return comp
|
||||
|
||||
globalopts = []
|
||||
for opt_strs, description in global_options(command_context).items():
|
||||
for opt_strs, description in self.global_options(command_context).items():
|
||||
comp = (
|
||||
"complete -c mach -n '__fish_mach_complete_no_command' "
|
||||
"-d '{}'".format(description.replace("'", "\\'"))
|
||||
@@ -439,7 +439,7 @@ def completion_fish(command_context, outfile):
|
||||
|
||||
cmds = []
|
||||
cmds_opts = []
|
||||
for i, cmd in enumerate(commands_info(command_context)):
|
||||
for i, cmd in enumerate(self.commands_info(command_context)):
|
||||
cmds.append(
|
||||
"complete -c mach -f -n '__fish_mach_complete_no_command' "
|
||||
"-a {} -d '{}'".format(cmd.name, cmd.description.replace("'", "\\'"))
|
||||
@@ -451,7 +451,9 @@ def completion_fish(command_context, outfile):
|
||||
for opt_strs, description in cmd.options.items():
|
||||
comp = (
|
||||
"complete -c mach -A -n '__fish_mach_complete_command {} {}' "
|
||||
"-d '{}'".format(cmd.name, subcommands, description.replace("'", "\\'"))
|
||||
"-d '{}'".format(
|
||||
cmd.name, subcommands, description.replace("'", "\\'")
|
||||
)
|
||||
)
|
||||
comp = _append_opt_strs(comp, opt_strs)
|
||||
cmds_opts.append(comp)
|
||||
@@ -478,11 +480,11 @@ def completion_fish(command_context, outfile):
|
||||
)
|
||||
cmds_opts.append(comp)
|
||||
|
||||
if i < len(commands(command_context)) - 1:
|
||||
if i < len(self.commands(command_context)) - 1:
|
||||
cmds_opts.append("")
|
||||
|
||||
context = {
|
||||
"commands": " ".join(commands(command_context)),
|
||||
"commands": " ".join(self.commands(command_context)),
|
||||
"command_completions": "\n".join(cmds),
|
||||
"command_option_completions": "\n".join(cmds_opts),
|
||||
"global_option_completions": "\n".join(globalopts),
|
||||
|
||||
@@ -7,17 +7,22 @@ from __future__ import absolute_import, print_function, unicode_literals
|
||||
from textwrap import TextWrapper
|
||||
|
||||
from mach.config import TYPE_CLASSES
|
||||
from mach.decorators import CommandArgument, Command
|
||||
from mach.decorators import CommandArgument, CommandProvider, Command
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
|
||||
# Interact with settings for mach.
|
||||
@CommandProvider
|
||||
class Settings(MachCommandBase):
|
||||
"""Interact with settings for mach.
|
||||
|
||||
# Currently, we only provide functionality to view what settings are
|
||||
# available. In the future, this module will be used to modify settings, help
|
||||
# people create configs via a wizard, etc.
|
||||
Currently, we only provide functionality to view what settings are
|
||||
available. In the future, this module will be used to modify settings, help
|
||||
people create configs via a wizard, etc.
|
||||
"""
|
||||
|
||||
|
||||
@Command("settings", category="devenv", description="Show available config settings.")
|
||||
@Command(
|
||||
"settings", category="devenv", description="Show available config settings."
|
||||
)
|
||||
@CommandArgument(
|
||||
"-l",
|
||||
"--list",
|
||||
@@ -25,7 +30,7 @@ from mach.decorators import CommandArgument, Command
|
||||
action="store_true",
|
||||
help="Show settings in a concise list",
|
||||
)
|
||||
def run_settings(command_context, short=None):
|
||||
def run_settings(self, command_context, short=None):
|
||||
"""List available settings."""
|
||||
types = {v: k for k, v in TYPE_CLASSES.items()}
|
||||
wrapper = TextWrapper(initial_indent="# ", subsequent_indent="# ")
|
||||
@@ -33,7 +38,9 @@ def run_settings(command_context, short=None):
|
||||
if not short:
|
||||
print("%s[%s]" % ("" if i == 0 else "\n", section))
|
||||
|
||||
for option in sorted(command_context._mach_context.settings[section]._settings):
|
||||
for option in sorted(
|
||||
command_context._mach_context.settings[section]._settings
|
||||
):
|
||||
meta = command_context._mach_context.settings[section].get_meta(option)
|
||||
desc = meta["description"]
|
||||
|
||||
|
||||
@@ -31,12 +31,18 @@ class _MachCommand(object):
|
||||
# By default, subcommands will be sorted. If this is set to
|
||||
# 'declaration', they will be left in declaration order.
|
||||
"order",
|
||||
# This is the function or callable that will be called when
|
||||
# the command is invoked
|
||||
"func",
|
||||
# Describes how dispatch is performed.
|
||||
# The Python class providing the command. This is the class type not
|
||||
# an instance of the class. Mach will instantiate a new instance of
|
||||
# the class if the command is executed.
|
||||
"cls",
|
||||
# The path to the `metrics.yaml` file that describes data that telemetry will
|
||||
# gather for this command. This path is optional.
|
||||
"metrics_path",
|
||||
# The name of the method providing the command. In other words, this
|
||||
# is the str name of the attribute on the class type corresponding to
|
||||
# the name of the function.
|
||||
"method",
|
||||
# Dict of string to _MachCommand defining sub-commands for this
|
||||
# command.
|
||||
"subcommand_handlers",
|
||||
@@ -73,8 +79,9 @@ class _MachCommand(object):
|
||||
)
|
||||
self.ok_if_tests_disabled = ok_if_tests_disabled
|
||||
|
||||
self.func = None
|
||||
self.cls = None
|
||||
self.metrics_path = None
|
||||
self.method = None
|
||||
self.subcommand_handlers = {}
|
||||
self.decl_order = None
|
||||
|
||||
@@ -82,11 +89,7 @@ class _MachCommand(object):
|
||||
metrics = None
|
||||
if self.metrics_path:
|
||||
metrics = context.telemetry.metrics(self.metrics_path)
|
||||
|
||||
# This ensures the resulting class is defined inside `mach` so that logging
|
||||
# works as expected, and has a meaningful name
|
||||
subclass = type(self.name, (MachCommandBase,), {})
|
||||
return subclass(context, virtualenv_name=virtualenv_name, metrics=metrics)
|
||||
return self.cls(context, virtualenv_name=virtualenv_name, metrics=metrics)
|
||||
|
||||
@property
|
||||
def parser(self):
|
||||
@@ -99,7 +102,7 @@ class _MachCommand(object):
|
||||
|
||||
@property
|
||||
def docstring(self):
|
||||
return self.func.__doc__
|
||||
return self.cls.__dict__[self.method].__doc__
|
||||
|
||||
def __ior__(self, other):
|
||||
if not isinstance(other, _MachCommand):
|
||||
@@ -111,11 +114,37 @@ class _MachCommand(object):
|
||||
|
||||
return self
|
||||
|
||||
def register(self, func):
|
||||
"""Register the command in the Registrar with the function to be called on invocation."""
|
||||
if not self.subcommand:
|
||||
if not self.conditions and Registrar.require_conditions:
|
||||
return
|
||||
|
||||
def CommandProvider(cls):
|
||||
if not issubclass(cls, MachCommandBase):
|
||||
raise MachError(
|
||||
"Mach command provider class %s must be a subclass of "
|
||||
"mozbuild.base.MachComandBase" % cls.__name__
|
||||
)
|
||||
|
||||
seen_commands = set()
|
||||
|
||||
# We scan __dict__ because we only care about the classes' own attributes,
|
||||
# not inherited ones. If we did inherited attributes, we could potentially
|
||||
# define commands multiple times. We also sort keys so commands defined in
|
||||
# the same class are grouped in a sane order.
|
||||
command_methods = sorted(
|
||||
[
|
||||
(name, value._mach_command)
|
||||
for name, value in cls.__dict__.items()
|
||||
if hasattr(value, "_mach_command")
|
||||
]
|
||||
)
|
||||
|
||||
for method, command in command_methods:
|
||||
# Ignore subcommands for now: we handle them later.
|
||||
if command.subcommand:
|
||||
continue
|
||||
|
||||
seen_commands.add(command.name)
|
||||
|
||||
if not command.conditions and Registrar.require_conditions:
|
||||
continue
|
||||
|
||||
msg = (
|
||||
"Mach command '%s' implemented incorrectly. "
|
||||
@@ -123,32 +152,46 @@ class _MachCommand(object):
|
||||
+ "of functions. Found %s instead."
|
||||
)
|
||||
|
||||
if not isinstance(self.conditions, collections.abc.Iterable):
|
||||
msg = msg % (self.name, type(self.conditions))
|
||||
if not isinstance(command.conditions, collections.abc.Iterable):
|
||||
msg = msg % (command.name, type(command.conditions))
|
||||
raise MachError(msg)
|
||||
|
||||
for c in self.conditions:
|
||||
for c in command.conditions:
|
||||
if not hasattr(c, "__call__"):
|
||||
msg = msg % (self.name, type(c))
|
||||
msg = msg % (command.name, type(c))
|
||||
raise MachError(msg)
|
||||
|
||||
self.func = func
|
||||
command.cls = cls
|
||||
command.method = method
|
||||
|
||||
Registrar.register_command_handler(self)
|
||||
Registrar.register_command_handler(command)
|
||||
|
||||
else:
|
||||
if self.name not in Registrar.command_handlers:
|
||||
# Now do another pass to get sub-commands. We do this in two passes so
|
||||
# we can check the parent command existence without having to hold
|
||||
# state and reconcile after traversal.
|
||||
for method, command in command_methods:
|
||||
# It is a regular command.
|
||||
if not command.subcommand:
|
||||
continue
|
||||
|
||||
if command.name not in seen_commands:
|
||||
raise MachError(
|
||||
"Command referenced by sub-command does not exist: %s" % self.name
|
||||
"Command referenced by sub-command does not exist: %s" % command.name
|
||||
)
|
||||
|
||||
self.func = func
|
||||
parent = Registrar.command_handlers[self.name]
|
||||
if command.name not in Registrar.command_handlers:
|
||||
continue
|
||||
|
||||
if self.subcommand in parent.subcommand_handlers:
|
||||
raise MachError("sub-command already defined: %s" % self.subcommand)
|
||||
command.cls = cls
|
||||
command.method = method
|
||||
parent = Registrar.command_handlers[command.name]
|
||||
|
||||
parent.subcommand_handlers[self.subcommand] = self
|
||||
if command.subcommand in parent.subcommand_handlers:
|
||||
raise MachError("sub-command already defined: %s" % command.subcommand)
|
||||
|
||||
parent.subcommand_handlers[command.subcommand] = command
|
||||
|
||||
return cls
|
||||
|
||||
|
||||
class Command(object):
|
||||
@@ -182,7 +225,6 @@ class Command(object):
|
||||
func._mach_command = _MachCommand()
|
||||
|
||||
func._mach_command |= self._mach_command
|
||||
func._mach_command.register(func)
|
||||
|
||||
return func
|
||||
|
||||
@@ -223,7 +265,6 @@ class SubCommand(object):
|
||||
func._mach_command = _MachCommand()
|
||||
|
||||
func._mach_command |= self._mach_command
|
||||
func._mach_command.register(func)
|
||||
|
||||
return func
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ class MachRegistrar(object):
|
||||
return 1
|
||||
|
||||
self.command_depth += 1
|
||||
fn = handler.func
|
||||
fn = getattr(instance, handler.method)
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
|
||||
@@ -6,16 +6,19 @@ from __future__ import unicode_literals
|
||||
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class ConditionsProvider(MachCommandBase):
|
||||
@Command("cmd_foo", category="testing")
|
||||
def run_foo(command_context):
|
||||
def run_foo(self, command_context):
|
||||
pass
|
||||
|
||||
|
||||
@Command("cmd_bar", category="testing")
|
||||
@CommandArgument("--baz", action="store_true", help="Run with baz")
|
||||
def run_bar(command_context, baz=None):
|
||||
def run_bar(self, command_context, baz=None):
|
||||
pass
|
||||
|
||||
@@ -8,8 +8,10 @@ from functools import partial
|
||||
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
|
||||
def is_foo(cls):
|
||||
@@ -22,17 +24,22 @@ def is_bar(val, cls):
|
||||
return cls.bar == val
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
foo = True
|
||||
bar = False
|
||||
|
||||
@Command("cmd_foo", category="testing")
|
||||
@CommandArgument("--arg", default=None, help="Argument help.")
|
||||
def run_foo(command_context):
|
||||
def run_foo(self, command_context):
|
||||
pass
|
||||
|
||||
|
||||
@Command("cmd_bar", category="testing", conditions=[partial(is_bar, False)])
|
||||
def run_bar(command_context):
|
||||
def run_bar(self, command_context):
|
||||
pass
|
||||
|
||||
|
||||
@Command("cmd_foobar", category="testing", conditions=[is_foo, partial(is_bar, True)])
|
||||
def run_foobar(command_context):
|
||||
@Command(
|
||||
"cmd_foobar", category="testing", conditions=[is_foo, partial(is_bar, True)]
|
||||
)
|
||||
def run_foobar(self, command_context):
|
||||
pass
|
||||
|
||||
@@ -6,55 +6,50 @@ from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from mach.decorators import (
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
|
||||
def is_true(cls):
|
||||
return True
|
||||
|
||||
|
||||
def is_false(cls):
|
||||
return False
|
||||
|
||||
|
||||
@Command("cmd_condition_true", category="testing", conditions=[is_true])
|
||||
def run_condition_true(self, command_context):
|
||||
pass
|
||||
|
||||
|
||||
@Command("cmd_condition_false", category="testing", conditions=[is_false])
|
||||
def run_condition_false(self, command_context):
|
||||
pass
|
||||
|
||||
|
||||
@Command(
|
||||
"cmd_condition_true_and_false", category="testing", conditions=[is_true, is_false]
|
||||
)
|
||||
def run_condition_true_and_false(self, command_context):
|
||||
pass
|
||||
|
||||
|
||||
def is_ctx_foo(cls):
|
||||
def is_foo(cls):
|
||||
"""Foo must be true"""
|
||||
return cls._mach_context.foo
|
||||
return cls.foo
|
||||
|
||||
|
||||
def is_ctx_bar(cls):
|
||||
def is_bar(cls):
|
||||
"""Bar must be true"""
|
||||
return cls._mach_context.bar
|
||||
return cls.bar
|
||||
|
||||
|
||||
@Command("cmd_foo_ctx", category="testing", conditions=[is_ctx_foo])
|
||||
def run_foo_ctx(self, command_context):
|
||||
@CommandProvider
|
||||
class ConditionsProvider(MachCommandBase):
|
||||
foo = True
|
||||
bar = False
|
||||
|
||||
@Command("cmd_foo", category="testing", conditions=[is_foo])
|
||||
def run_foo(self, command_context):
|
||||
pass
|
||||
|
||||
@Command("cmd_bar", category="testing", conditions=[is_bar])
|
||||
def run_bar(self, command_context):
|
||||
pass
|
||||
|
||||
@Command("cmd_foobar", category="testing", conditions=[is_foo, is_bar])
|
||||
def run_foobar(self, command_context):
|
||||
pass
|
||||
|
||||
|
||||
@Command("cmd_bar_ctx", category="testing", conditions=[is_ctx_bar])
|
||||
def run_bar_ctx(self, command_context):
|
||||
@CommandProvider
|
||||
class ConditionsContextProvider(MachCommandBase):
|
||||
@Command("cmd_foo_ctx", category="testing", conditions=[is_foo])
|
||||
def run_foo(self, command_context):
|
||||
pass
|
||||
|
||||
|
||||
@Command("cmd_foobar_ctx", category="testing", conditions=[is_ctx_foo, is_ctx_bar])
|
||||
def run_foobar_ctx(self, command_context):
|
||||
@Command("cmd_bar_ctx", category="testing", conditions=[is_bar])
|
||||
def run_bar(self, command_context):
|
||||
pass
|
||||
|
||||
@Command("cmd_foobar_ctx", category="testing", conditions=[is_foo, is_bar])
|
||||
def run_foobar(self, command_context):
|
||||
pass
|
||||
|
||||
@@ -6,10 +6,14 @@ from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from mach.decorators import (
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class ConditionsProvider(MachCommandBase):
|
||||
@Command("cmd_foo", category="testing", conditions=["invalid"])
|
||||
def run_foo(command_context):
|
||||
def run_foo(self, command_context):
|
||||
pass
|
||||
|
||||
@@ -7,18 +7,21 @@ from __future__ import unicode_literals
|
||||
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
from mach.test.providers import throw2
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class TestCommandProvider(MachCommandBase):
|
||||
@Command("throw", category="testing")
|
||||
@CommandArgument("--message", "-m", default="General Error")
|
||||
def throw(command_context, message):
|
||||
def throw(self, command_context, message):
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
@Command("throw_deep", category="testing")
|
||||
@CommandArgument("--message", "-m", default="General Error")
|
||||
def throw_deep(command_context, message):
|
||||
def throw_deep(self, command_context, message):
|
||||
throw2.throw_deep(message)
|
||||
|
||||
@@ -49,7 +49,7 @@ class TestConditions(TestBase):
|
||||
def test_conditions_pass(self):
|
||||
"""Test that a command which passes its conditions is runnable."""
|
||||
|
||||
self.assertEquals((0, "", ""), self._run(["cmd_condition_true"]))
|
||||
self.assertEquals((0, "", ""), self._run(["cmd_foo"]))
|
||||
self.assertEquals((0, "", ""), self._run(["cmd_foo_ctx"], _populate_context))
|
||||
|
||||
def test_invalid_context_message(self):
|
||||
@@ -61,7 +61,7 @@ class TestConditions(TestBase):
|
||||
|
||||
fail_conditions = [is_bar]
|
||||
|
||||
for name in ("cmd_condition_false", "cmd_condition_true_and_false"):
|
||||
for name in ("cmd_bar", "cmd_foobar"):
|
||||
result, stdout, stderr = self._run([name])
|
||||
self.assertEquals(1, result)
|
||||
|
||||
@@ -90,9 +90,9 @@ class TestConditions(TestBase):
|
||||
"""Test that commands that are not runnable do not show up in help."""
|
||||
|
||||
result, stdout, stderr = self._run(["help"], _populate_context)
|
||||
self.assertIn("cmd_condition_true", stdout)
|
||||
self.assertNotIn("cmd_condition_false", stdout)
|
||||
self.assertNotIn("cmd_condition_true_and_false", stdout)
|
||||
self.assertIn("cmd_foo", stdout)
|
||||
self.assertNotIn("cmd_bar", stdout)
|
||||
self.assertNotIn("cmd_foobar", stdout)
|
||||
self.assertIn("cmd_foo_ctx", stdout)
|
||||
self.assertNotIn("cmd_bar_ctx", stdout)
|
||||
self.assertNotIn("cmd_foobar_ctx", stdout)
|
||||
|
||||
@@ -9,12 +9,13 @@ import os
|
||||
import pytest
|
||||
from unittest.mock import Mock
|
||||
|
||||
from mozbuild.base import MachCommandBase
|
||||
from mozunit import main
|
||||
|
||||
import mach.registrar
|
||||
import mach.decorators
|
||||
from mach.base import MachError
|
||||
from mach.decorators import CommandArgument, Command, SubCommand
|
||||
from mach.decorators import CommandArgument, CommandProvider, Command, SubCommand
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -32,9 +33,11 @@ def test_register_command_with_argument(registrar):
|
||||
context = Mock()
|
||||
context.cwd = "."
|
||||
|
||||
@CommandProvider
|
||||
class CommandFoo(MachCommandBase):
|
||||
@Command("cmd_foo", category="testing")
|
||||
@CommandArgument("--arg", default=None, help="Argument help.")
|
||||
def run_foo(command_context, arg):
|
||||
def run_foo(self, command_context, arg):
|
||||
inner_function(arg)
|
||||
|
||||
registrar.dispatch("cmd_foo", context, arg="argument")
|
||||
@@ -50,12 +53,14 @@ def test_register_command_with_metrics_path(registrar):
|
||||
metrics_mock = Mock()
|
||||
context.telemetry.metrics.return_value = metrics_mock
|
||||
|
||||
@CommandProvider
|
||||
class CommandFoo(MachCommandBase):
|
||||
@Command("cmd_foo", category="testing", metrics_path=metrics_path)
|
||||
def run_foo(command_context):
|
||||
def run_foo(self, command_context):
|
||||
assert command_context.metrics == metrics_mock
|
||||
|
||||
@SubCommand("cmd_foo", "sub_foo", metrics_path=metrics_path + "2")
|
||||
def run_subfoo(command_context):
|
||||
def run_subfoo(self, command_context):
|
||||
assert command_context.metrics == metrics_mock
|
||||
|
||||
registrar.dispatch("cmd_foo", context)
|
||||
@@ -73,10 +78,12 @@ def test_register_command_sets_up_class_at_runtime(registrar):
|
||||
context = Mock()
|
||||
context.cwd = "."
|
||||
|
||||
# We test that the virtualenv is set up properly dynamically on
|
||||
# the instance that actually runs the command.
|
||||
# Inside the following class, we test that the virtualenv is set up properly
|
||||
# dynamically on the instance that actually runs the command.
|
||||
@CommandProvider
|
||||
class CommandFoo(MachCommandBase):
|
||||
@Command("cmd_foo", category="testing", virtualenv_name="env_foo")
|
||||
def run_foo(command_context):
|
||||
def run_foo(self, command_context):
|
||||
assert (
|
||||
os.path.basename(command_context.virtualenv_manager.virtualenv_root)
|
||||
== "env_foo"
|
||||
@@ -84,7 +91,7 @@ def test_register_command_sets_up_class_at_runtime(registrar):
|
||||
inner_function("foo")
|
||||
|
||||
@Command("cmd_bar", category="testing", virtualenv_name="env_bar")
|
||||
def run_bar(command_context):
|
||||
def run_bar(self, command_context):
|
||||
assert (
|
||||
os.path.basename(command_context.virtualenv_manager.virtualenv_root)
|
||||
== "env_bar"
|
||||
@@ -100,16 +107,20 @@ def test_register_command_sets_up_class_at_runtime(registrar):
|
||||
def test_cannot_create_command_nonexisting_category(registrar):
|
||||
with pytest.raises(MachError):
|
||||
|
||||
@CommandProvider
|
||||
class CommandFoo(MachCommandBase):
|
||||
@Command("cmd_foo", category="bar")
|
||||
def run_foo(command_context):
|
||||
def run_foo(self, command_context):
|
||||
pass
|
||||
|
||||
|
||||
def test_subcommand_requires_parent_to_exist(registrar):
|
||||
with pytest.raises(MachError):
|
||||
|
||||
@CommandProvider
|
||||
class CommandFoo(MachCommandBase):
|
||||
@SubCommand("sub_foo", "foo")
|
||||
def run_foo(command_context):
|
||||
def run_foo(self, command_context):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@@ -20,13 +20,16 @@ from mozfile import which
|
||||
from manifestparser import TestManifest
|
||||
from manifestparser import filters as mpf
|
||||
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
from mach.decorators import CommandArgument, Command
|
||||
from mach.decorators import CommandArgument, CommandProvider, Command
|
||||
from mach.util import UserError
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command("python", category="devenv", description="Run Python.")
|
||||
@CommandArgument(
|
||||
"--no-virtualenv", action="store_true", help="Do not set up a virtualenv"
|
||||
@@ -50,6 +53,7 @@ here = os.path.abspath(os.path.dirname(__file__))
|
||||
)
|
||||
@CommandArgument("args", nargs=argparse.REMAINDER)
|
||||
def python(
|
||||
self,
|
||||
command_context,
|
||||
no_virtualenv,
|
||||
no_activate,
|
||||
@@ -110,7 +114,6 @@ def python(
|
||||
append_env=append_env,
|
||||
)
|
||||
|
||||
|
||||
@Command(
|
||||
"python-test",
|
||||
category="testing",
|
||||
@@ -161,21 +164,21 @@ def python(
|
||||
"passed as it is to pytest"
|
||||
),
|
||||
)
|
||||
def python_test(command_context, *args, **kwargs):
|
||||
def python_test(self, command_context, *args, **kwargs):
|
||||
try:
|
||||
tempdir = str(tempfile.mkdtemp(suffix="-python-test"))
|
||||
if six.PY2:
|
||||
os.environ[b"PYTHON_TEST_TMP"] = tempdir
|
||||
else:
|
||||
os.environ["PYTHON_TEST_TMP"] = tempdir
|
||||
return run_python_tests(command_context, *args, **kwargs)
|
||||
return self.run_python_tests(command_context, *args, **kwargs)
|
||||
finally:
|
||||
import mozfile
|
||||
|
||||
mozfile.remove(tempdir)
|
||||
|
||||
|
||||
def run_python_tests(
|
||||
self,
|
||||
command_context,
|
||||
tests=None,
|
||||
test_objects=None,
|
||||
@@ -276,7 +279,9 @@ def run_python_tests(
|
||||
|
||||
with ThreadPoolExecutor(max_workers=jobs) as executor:
|
||||
futures = [
|
||||
executor.submit(_run_python_test, command_context, test, jobs, verbose)
|
||||
executor.submit(
|
||||
self._run_python_test, command_context, test, jobs, verbose
|
||||
)
|
||||
for test in parallel
|
||||
]
|
||||
|
||||
@@ -292,7 +297,7 @@ def run_python_tests(
|
||||
|
||||
for test in sequential:
|
||||
return_code = on_test_finished(
|
||||
_run_python_test(command_context, test, jobs, verbose)
|
||||
self._run_python_test(command_context, test, jobs, verbose)
|
||||
)
|
||||
if return_code and exitfirst:
|
||||
break
|
||||
@@ -305,8 +310,7 @@ def run_python_tests(
|
||||
)
|
||||
return return_code
|
||||
|
||||
|
||||
def _run_python_test(command_context, test, jobs, verbose):
|
||||
def _run_python_test(self, command_context, test, jobs, verbose):
|
||||
from mozprocess import ProcessHandler
|
||||
|
||||
output = []
|
||||
@@ -325,7 +329,9 @@ def _run_python_test(command_context, test, jobs, verbose):
|
||||
def _line_handler(line):
|
||||
line = six.ensure_str(line)
|
||||
if not file_displayed_test:
|
||||
output = "Ran" in line or "collected" in line or line.startswith("TEST-")
|
||||
output = (
|
||||
"Ran" in line or "collected" in line or line.startswith("TEST-")
|
||||
)
|
||||
if output:
|
||||
file_displayed_test.append(True)
|
||||
|
||||
|
||||
@@ -7,10 +7,13 @@ from __future__ import absolute_import, print_function, unicode_literals
|
||||
import errno
|
||||
import sys
|
||||
|
||||
from mach.decorators import CommandArgument, Command
|
||||
from mach.decorators import CommandArgument, CommandProvider, Command
|
||||
from mozbuild.base import MachCommandBase
|
||||
from mozboot.bootstrap import APPLICATIONS
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class Bootstrap(MachCommandBase):
|
||||
@Command(
|
||||
"bootstrap",
|
||||
category="devenv",
|
||||
@@ -27,9 +30,11 @@ from mozboot.bootstrap import APPLICATIONS
|
||||
"--no-system-changes",
|
||||
dest="no_system_changes",
|
||||
action="store_true",
|
||||
help="Only execute actions that leave the system configuration alone.",
|
||||
help="Only execute actions that leave the system " "configuration alone.",
|
||||
)
|
||||
def bootstrap(command_context, application_choice=None, no_system_changes=False):
|
||||
def bootstrap(
|
||||
self, command_context, application_choice=None, no_system_changes=False
|
||||
):
|
||||
"""Bootstrap system and mach for optimal development experience."""
|
||||
from mozboot.bootstrap import Bootstrapper
|
||||
|
||||
@@ -42,6 +47,8 @@ def bootstrap(command_context, application_choice=None, no_system_changes=False)
|
||||
bootstrapper.bootstrap(command_context.settings)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class VersionControlCommands(MachCommandBase):
|
||||
@Command(
|
||||
"vcs-setup",
|
||||
category="devenv",
|
||||
@@ -53,7 +60,7 @@ def bootstrap(command_context, application_choice=None, no_system_changes=False)
|
||||
action="store_true",
|
||||
help="Only update recommended extensions, don't run the wizard.",
|
||||
)
|
||||
def vcs_setup(command_context, update_only=False):
|
||||
def vcs_setup(self, command_context, update_only=False):
|
||||
"""Ensure a Version Control System (Mercurial or Git) is optimally
|
||||
configured.
|
||||
|
||||
@@ -72,7 +79,9 @@ def vcs_setup(command_context, update_only=False):
|
||||
import mozversioncontrol
|
||||
from mozfile import which
|
||||
|
||||
repo = mozversioncontrol.get_repository_object(command_context._mach_context.topdir)
|
||||
repo = mozversioncontrol.get_repository_object(
|
||||
command_context._mach_context.topdir
|
||||
)
|
||||
tool = "hg"
|
||||
if repo.name == "git":
|
||||
tool = "git"
|
||||
@@ -105,4 +114,6 @@ def vcs_setup(command_context, update_only=False):
|
||||
command_context._mach_context.topdir,
|
||||
)
|
||||
else:
|
||||
bootstrap.configure_mercurial(vcs, command_context._mach_context.state_dir)
|
||||
bootstrap.configure_mercurial(
|
||||
vcs, command_context._mach_context.state_dir
|
||||
)
|
||||
|
||||
@@ -13,9 +13,9 @@ import six
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from mach.decorators import CommandArgument, Command, SubCommand
|
||||
from mach.decorators import CommandArgument, CommandProvider, Command, SubCommand
|
||||
from mozbuild.artifact_builds import JOB_CHOICES
|
||||
from mozbuild.base import MachCommandConditions as conditions
|
||||
from mozbuild.base import MachCommandBase, MachCommandConditions as conditions
|
||||
from mozbuild.util import ensureParentDir
|
||||
import mozversioncontrol
|
||||
|
||||
@@ -55,15 +55,16 @@ class ArtifactSubCommand(SubCommand):
|
||||
return after
|
||||
|
||||
|
||||
# Fetch and install binary artifacts from Mozilla automation.
|
||||
|
||||
@CommandProvider
|
||||
class PackageFrontend(MachCommandBase):
|
||||
"""Fetch and install binary artifacts from Mozilla automation."""
|
||||
|
||||
@Command(
|
||||
"artifact",
|
||||
category="post-build",
|
||||
description="Use pre-built artifacts to build Firefox.",
|
||||
)
|
||||
def artifact(command_context):
|
||||
def artifact(self, command_context):
|
||||
"""Download, cache, and install pre-built binary artifacts to build Firefox.
|
||||
|
||||
Use |mach build| as normal to freshen your installed binary libraries:
|
||||
@@ -77,8 +78,8 @@ def artifact(command_context):
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def _make_artifacts(
|
||||
self,
|
||||
command_context,
|
||||
tree=None,
|
||||
job=None,
|
||||
@@ -101,7 +102,9 @@ def _make_artifacts(
|
||||
git = command_context.substs["GIT"]
|
||||
|
||||
# If we're building Thunderbird, we should be checking for comm-central artifacts.
|
||||
topsrcdir = command_context.substs.get("commtopsrcdir", command_context.topsrcdir)
|
||||
topsrcdir = command_context.substs.get(
|
||||
"commtopsrcdir", command_context.topsrcdir
|
||||
)
|
||||
|
||||
if download_maven_zip:
|
||||
if download_tests:
|
||||
@@ -135,7 +138,6 @@ def _make_artifacts(
|
||||
)
|
||||
return artifacts
|
||||
|
||||
|
||||
@ArtifactSubCommand("artifact", "install", "Install a good pre-built artifact.")
|
||||
@CommandArgument(
|
||||
"source",
|
||||
@@ -154,7 +156,9 @@ def _make_artifacts(
|
||||
default=False,
|
||||
)
|
||||
@CommandArgument("--no-tests", action="store_true", help="Don't install tests.")
|
||||
@CommandArgument("--symbols", nargs="?", action=SymbolsAction, help="Download symbols.")
|
||||
@CommandArgument(
|
||||
"--symbols", nargs="?", action=SymbolsAction, help="Download symbols."
|
||||
)
|
||||
@CommandArgument("--host-bins", action="store_true", help="Download host binaries.")
|
||||
@CommandArgument("--distdir", help="Where to install artifacts to.")
|
||||
@CommandArgument(
|
||||
@@ -166,6 +170,7 @@ def _make_artifacts(
|
||||
"--maven-zip", action="store_true", help="Download Maven zip (Android-only)."
|
||||
)
|
||||
def artifact_install(
|
||||
self,
|
||||
command_context,
|
||||
source=None,
|
||||
skip_cache=False,
|
||||
@@ -180,7 +185,7 @@ def artifact_install(
|
||||
maven_zip=False,
|
||||
):
|
||||
command_context._set_log_level(verbose)
|
||||
artifacts = _make_artifacts(
|
||||
artifacts = self._make_artifacts(
|
||||
command_context,
|
||||
tree=tree,
|
||||
job=job,
|
||||
@@ -194,21 +199,21 @@ def artifact_install(
|
||||
|
||||
return artifacts.install_from(source, distdir or command_context.distdir)
|
||||
|
||||
|
||||
@ArtifactSubCommand(
|
||||
"artifact",
|
||||
"clear-cache",
|
||||
"Delete local artifacts and reset local artifact cache.",
|
||||
)
|
||||
def artifact_clear_cache(command_context, tree=None, job=None, verbose=False):
|
||||
def artifact_clear_cache(self, command_context, tree=None, job=None, verbose=False):
|
||||
command_context._set_log_level(verbose)
|
||||
artifacts = _make_artifacts(command_context, tree=tree, job=job)
|
||||
artifacts = self._make_artifacts(command_context, tree=tree, job=job)
|
||||
artifacts.clear_cache()
|
||||
return 0
|
||||
|
||||
|
||||
@SubCommand("artifact", "toolchain")
|
||||
@CommandArgument("--verbose", "-v", action="store_true", help="Print verbose output.")
|
||||
@CommandArgument(
|
||||
"--verbose", "-v", action="store_true", help="Print verbose output."
|
||||
)
|
||||
@CommandArgument(
|
||||
"--cache-dir",
|
||||
metavar="DIR",
|
||||
@@ -250,6 +255,7 @@ def artifact_clear_cache(command_context, tree=None, job=None, verbose=False):
|
||||
help="Store a manifest about the downloaded taskcluster artifacts",
|
||||
)
|
||||
def artifact_toolchain(
|
||||
self,
|
||||
command_context,
|
||||
verbose=False,
|
||||
cache_dir=None,
|
||||
@@ -288,7 +294,9 @@ def artifact_toolchain(
|
||||
command_context.log_manager.structured_filter
|
||||
)
|
||||
if not cache_dir:
|
||||
cache_dir = os.path.join(command_context._mach_context.state_dir, "toolchains")
|
||||
cache_dir = os.path.join(
|
||||
command_context._mach_context.state_dir, "toolchains"
|
||||
)
|
||||
|
||||
tooltool_host = os.environ.get("TOOLTOOL_HOST", "tooltool.mozilla-releng.net")
|
||||
taskcluster_proxy_url = os.environ.get("TASKCLUSTER_PROXY_URL")
|
||||
|
||||
@@ -9,14 +9,17 @@ import logging
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from mozbuild import build_commands
|
||||
from mozbuild.base import MachCommandBase
|
||||
from mozbuild.build_commands import Build
|
||||
|
||||
from mozfile import which
|
||||
from mach.decorators import CommandArgument, Command
|
||||
from mach.decorators import CommandArgument, CommandProvider, Command
|
||||
|
||||
import mozpack.path as mozpath
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command(
|
||||
"ide",
|
||||
category="devenv",
|
||||
@@ -25,7 +28,7 @@ import mozpack.path as mozpath
|
||||
)
|
||||
@CommandArgument("ide", choices=["eclipse", "visualstudio", "vscode"])
|
||||
@CommandArgument("args", nargs=argparse.REMAINDER)
|
||||
def run(command_context, ide, args):
|
||||
def run(self, command_context, ide, args):
|
||||
if ide == "eclipse":
|
||||
backend = "CppEclipse"
|
||||
elif ide == "visualstudio":
|
||||
@@ -50,7 +53,7 @@ def run(command_context, ide, args):
|
||||
|
||||
if ide == "vscode":
|
||||
# Check if platform has VSCode installed
|
||||
vscode_cmd = find_vscode_cmd(command_context)
|
||||
vscode_cmd = self.find_vscode_cmd(command_context)
|
||||
if vscode_cmd is None:
|
||||
choice = prompt_bool(
|
||||
"VSCode cannot be found, and may not be installed. Proceed?"
|
||||
@@ -58,13 +61,15 @@ def run(command_context, ide, args):
|
||||
if not choice:
|
||||
return 1
|
||||
|
||||
rc = build_commands.configure(command_context)
|
||||
# Create the Build environment to configure the tree
|
||||
builder = Build(command_context._mach_context, None)
|
||||
|
||||
rc = builder.configure(command_context)
|
||||
if rc != 0:
|
||||
return rc
|
||||
|
||||
# First install what we can through install manifests.
|
||||
rc = build_commands._run_make(
|
||||
rc = builder._run_make(
|
||||
directory=command_context.topobjdir,
|
||||
target="pre-export",
|
||||
line_handler=None,
|
||||
@@ -75,7 +80,7 @@ def run(command_context, ide, args):
|
||||
# Then build the rest of the build dependencies by running the full
|
||||
# export target, because we can't do anything better.
|
||||
for target in ("export", "pre-compile"):
|
||||
rc = build_commands._run_make(
|
||||
rc = builder._run_make(
|
||||
directory=command_context.topobjdir,
|
||||
target=target,
|
||||
line_handler=None,
|
||||
@@ -103,30 +108,29 @@ def run(command_context, ide, args):
|
||||
return 1
|
||||
|
||||
if ide == "eclipse":
|
||||
eclipse_workspace_dir = get_eclipse_workspace_path(command_context)
|
||||
eclipse_workspace_dir = self.get_eclipse_workspace_path(command_context)
|
||||
subprocess.check_call(["eclipse", "-data", eclipse_workspace_dir])
|
||||
elif ide == "visualstudio":
|
||||
visual_studio_workspace_dir = get_visualstudio_workspace_path(command_context)
|
||||
visual_studio_workspace_dir = self.get_visualstudio_workspace_path(
|
||||
command_context
|
||||
)
|
||||
subprocess.call(["explorer.exe", visual_studio_workspace_dir])
|
||||
elif ide == "vscode":
|
||||
return setup_vscode(command_context, vscode_cmd)
|
||||
return self.setup_vscode(command_context, vscode_cmd)
|
||||
|
||||
|
||||
def get_eclipse_workspace_path(command_context):
|
||||
def get_eclipse_workspace_path(self, command_context):
|
||||
from mozbuild.backend.cpp_eclipse import CppEclipseBackend
|
||||
|
||||
return CppEclipseBackend.get_workspace_path(
|
||||
command_context.topsrcdir, command_context.topobjdir
|
||||
)
|
||||
|
||||
|
||||
def get_visualstudio_workspace_path(command_context):
|
||||
def get_visualstudio_workspace_path(self, command_context):
|
||||
return os.path.normpath(
|
||||
os.path.join(command_context.topobjdir, "msvc", "mozilla.sln")
|
||||
)
|
||||
|
||||
|
||||
def find_vscode_cmd(command_context):
|
||||
def find_vscode_cmd(self, command_context):
|
||||
import shutil
|
||||
|
||||
# Try to look up the `code` binary on $PATH, and use it if present. This
|
||||
@@ -193,8 +197,7 @@ def find_vscode_cmd(command_context):
|
||||
# Path cannot be found
|
||||
return None
|
||||
|
||||
|
||||
def setup_vscode(command_context, vscode_cmd):
|
||||
def setup_vscode(self, command_context, vscode_cmd):
|
||||
vscode_settings = mozpath.join(
|
||||
command_context.topsrcdir, ".vscode", "settings.json"
|
||||
)
|
||||
@@ -219,7 +222,7 @@ def setup_vscode(command_context, vscode_cmd):
|
||||
{},
|
||||
"Unable to locate clangd in {}.".format(clang_tidy_bin),
|
||||
)
|
||||
rc = _get_clang_tools(command_context, clang_tools_path)
|
||||
rc = self._get_clang_tools(command_context, clang_tools_path)
|
||||
|
||||
if rc != 0:
|
||||
return rc
|
||||
@@ -335,8 +338,7 @@ def setup_vscode(command_context, vscode_cmd):
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def _get_clang_tools(command_context, clang_tools_path):
|
||||
def _get_clang_tools(self, command_context, clang_tools_path):
|
||||
|
||||
import shutil
|
||||
|
||||
|
||||
@@ -8,8 +8,9 @@ import argparse
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from mach.decorators import CommandArgument, Command
|
||||
from mach.decorators import CommandArgument, CommandProvider, Command
|
||||
|
||||
from mozbuild.base import MachCommandBase
|
||||
from mozbuild.util import MOZBUILD_METRICS_PATH
|
||||
from mozbuild.mozconfig import MozconfigLoader
|
||||
import mozpack.path as mozpath
|
||||
@@ -68,8 +69,9 @@ def _set_priority(priority, verbose):
|
||||
return True
|
||||
|
||||
|
||||
# Interface to build the tree.
|
||||
|
||||
@CommandProvider
|
||||
class Build(MachCommandBase):
|
||||
"""Interface to build the tree."""
|
||||
|
||||
@Command(
|
||||
"build",
|
||||
@@ -121,6 +123,7 @@ def _set_priority(priority, verbose):
|
||||
help="idle/less/normal/more/high. (Default less)",
|
||||
)
|
||||
def build(
|
||||
self,
|
||||
command_context,
|
||||
what=None,
|
||||
jobs=0,
|
||||
@@ -169,7 +172,9 @@ def build(
|
||||
|
||||
if doing_pgo:
|
||||
if what:
|
||||
raise Exception("Cannot specify targets (%s) in MOZ_PGO=1 builds" % what)
|
||||
raise Exception(
|
||||
"Cannot specify targets (%s) in MOZ_PGO=1 builds" % what
|
||||
)
|
||||
instr = command_context._spawn(BuildDriver)
|
||||
orig_topobjdir = instr._topobjdir
|
||||
instr._topobjdir = mozpath.join(instr._topobjdir, "instrumented")
|
||||
@@ -229,7 +234,6 @@ def build(
|
||||
append_env=append_env,
|
||||
)
|
||||
|
||||
|
||||
@Command(
|
||||
"configure",
|
||||
category="build",
|
||||
@@ -241,6 +245,7 @@ def build(
|
||||
"options", default=None, nargs=argparse.REMAINDER, help="Configure options"
|
||||
)
|
||||
def configure(
|
||||
self,
|
||||
command_context,
|
||||
options=None,
|
||||
buildstatus_messages=False,
|
||||
@@ -258,7 +263,6 @@ def configure(
|
||||
line_handler=line_handler,
|
||||
)
|
||||
|
||||
|
||||
@Command(
|
||||
"resource-usage",
|
||||
category="post-build",
|
||||
@@ -282,7 +286,9 @@ def configure(
|
||||
help="Web browser to automatically open. See webbrowser Python module.",
|
||||
)
|
||||
@CommandArgument("--url", help="URL of JSON document to display")
|
||||
def resource_usage(command_context, address=None, port=None, browser=None, url=None):
|
||||
def resource_usage(
|
||||
self, command_context, address=None, port=None, browser=None, url=None
|
||||
):
|
||||
import webbrowser
|
||||
from mozbuild.html_build_viewer import BuildViewerServer
|
||||
|
||||
@@ -313,14 +319,15 @@ def resource_usage(command_context, address=None, port=None, browser=None, url=N
|
||||
print("Hit CTRL+c to stop server.")
|
||||
server.run()
|
||||
|
||||
|
||||
@Command(
|
||||
"build-backend",
|
||||
category="build",
|
||||
description="Generate a backend used to build the tree.",
|
||||
virtualenv_name="build",
|
||||
)
|
||||
@CommandArgument("-d", "--diff", action="store_true", help="Show a diff of changes.")
|
||||
@CommandArgument(
|
||||
"-d", "--diff", action="store_true", help="Show a diff of changes."
|
||||
)
|
||||
# It would be nice to filter the choices below based on
|
||||
# conditions, but that is for another day.
|
||||
@CommandArgument(
|
||||
@@ -337,7 +344,9 @@ def resource_usage(command_context, address=None, port=None, browser=None, url=N
|
||||
action="store_true",
|
||||
help="Do everything except writing files out.",
|
||||
)
|
||||
def build_backend(command_context, backend, diff=False, verbose=False, dry_run=False):
|
||||
def build_backend(
|
||||
self, command_context, backend, diff=False, verbose=False, dry_run=False
|
||||
):
|
||||
python = command_context.virtualenv_manager.python_path
|
||||
config_status = os.path.join(command_context.topobjdir, "config.status")
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,13 +6,15 @@
|
||||
|
||||
from __future__ import absolute_import, print_function
|
||||
|
||||
from mach.decorators import CommandArgument, Command
|
||||
from mach.decorators import CommandArgument, CommandProvider, Command
|
||||
|
||||
from mozbuild.base import MachCommandBase
|
||||
from mozbuild.shellutil import split as shell_split, quote as shell_quote
|
||||
|
||||
|
||||
# Instropection commands.
|
||||
|
||||
@CommandProvider
|
||||
class Introspection(MachCommandBase):
|
||||
"""Instropection commands."""
|
||||
|
||||
@Command(
|
||||
"compileflags",
|
||||
@@ -22,7 +24,7 @@ from mozbuild.shellutil import split as shell_split, quote as shell_quote
|
||||
@CommandArgument(
|
||||
"what", default=None, help="Source file to display compilation flags for"
|
||||
)
|
||||
def compileflags(command_context, what):
|
||||
def compileflags(self, command_context, what):
|
||||
from mozbuild.util import resolve_target_to_make
|
||||
from mozbuild.compilation import util
|
||||
|
||||
@@ -38,7 +40,7 @@ def compileflags(command_context, what):
|
||||
if make_dir is None and make_target is None:
|
||||
return 1
|
||||
|
||||
build_vars = util.get_build_vars(make_dir, command_context)
|
||||
build_vars = util.get_build_vars(make_dir, self)
|
||||
|
||||
if what.endswith(".c"):
|
||||
cc = "CC"
|
||||
|
||||
@@ -9,8 +9,9 @@ import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
from mach.decorators import CommandArgument, Command, SubCommand
|
||||
from mach.decorators import CommandArgument, CommandProvider, Command, SubCommand
|
||||
|
||||
from mozbuild.base import MachCommandBase
|
||||
import mozpack.path as mozpath
|
||||
|
||||
TOPSRCDIR = os.path.abspath(os.path.join(__file__, "../../../../../"))
|
||||
@@ -20,6 +21,8 @@ class InvalidPathException(Exception):
|
||||
"""Represents an error due to an invalid path."""
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MozbuildFileCommands(MachCommandBase):
|
||||
@Command(
|
||||
"mozbuild-reference",
|
||||
category="build-dev",
|
||||
@@ -38,7 +41,7 @@ class InvalidPathException(Exception):
|
||||
action="store_true",
|
||||
help="Print symbol names only.",
|
||||
)
|
||||
def reference(command_context, symbol, name_only=False):
|
||||
def reference(self, command_context, symbol, name_only=False):
|
||||
# mozbuild.sphinx imports some Sphinx modules, so we need to be sure
|
||||
# the optional Sphinx package is installed.
|
||||
command_context.activate_virtualenv()
|
||||
@@ -90,24 +93,24 @@ def reference(command_context, symbol, name_only=False):
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
@Command(
|
||||
"file-info", category="build-dev", description="Query for metadata about files."
|
||||
)
|
||||
def file_info(command_context):
|
||||
def file_info(self, command_context):
|
||||
"""Show files metadata derived from moz.build files.
|
||||
|
||||
moz.build files contain "Files" sub-contexts for declaring metadata
|
||||
against file patterns. This command suite is used to query that data.
|
||||
"""
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"file-info",
|
||||
"bugzilla-component",
|
||||
"Show Bugzilla component info for files listed.",
|
||||
)
|
||||
@CommandArgument("-r", "--rev", help="Version control revision to look up info from")
|
||||
@CommandArgument(
|
||||
"-r", "--rev", help="Version control revision to look up info from"
|
||||
)
|
||||
@CommandArgument(
|
||||
"--format",
|
||||
choices={"json", "plain"},
|
||||
@@ -116,7 +119,7 @@ def file_info(command_context):
|
||||
dest="fmt",
|
||||
)
|
||||
@CommandArgument("paths", nargs="+", help="Paths whose data to query")
|
||||
def file_info_bugzilla(command_context, paths, rev=None, fmt=None):
|
||||
def file_info_bugzilla(self, command_context, paths, rev=None, fmt=None):
|
||||
"""Show Bugzilla component for a set of files.
|
||||
|
||||
Given a requested set of files (which can be specified using
|
||||
@@ -124,7 +127,7 @@ def file_info_bugzilla(command_context, paths, rev=None, fmt=None):
|
||||
"""
|
||||
components = defaultdict(set)
|
||||
try:
|
||||
for p, m in _get_files_info(command_context, paths, rev=rev).items():
|
||||
for p, m in self._get_files_info(command_context, paths, rev=rev).items():
|
||||
components[m.get("BUG_COMPONENT")].add(p)
|
||||
except InvalidPathException as e:
|
||||
print(e)
|
||||
@@ -158,11 +161,12 @@ def file_info_bugzilla(command_context, paths, rev=None, fmt=None):
|
||||
print("unhandled output format: %s" % fmt)
|
||||
return 1
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"file-info", "missing-bugzilla", "Show files missing Bugzilla component info"
|
||||
)
|
||||
@CommandArgument("-r", "--rev", help="Version control revision to look up info from")
|
||||
@CommandArgument(
|
||||
"-r", "--rev", help="Version control revision to look up info from"
|
||||
)
|
||||
@CommandArgument(
|
||||
"--format",
|
||||
choices={"json", "plain"},
|
||||
@@ -171,11 +175,11 @@ def file_info_bugzilla(command_context, paths, rev=None, fmt=None):
|
||||
help="Output format",
|
||||
)
|
||||
@CommandArgument("paths", nargs="+", help="Paths whose data to query")
|
||||
def file_info_missing_bugzilla(command_context, paths, rev=None, fmt=None):
|
||||
def file_info_missing_bugzilla(self, command_context, paths, rev=None, fmt=None):
|
||||
missing = set()
|
||||
|
||||
try:
|
||||
for p, m in _get_files_info(command_context, paths, rev=rev).items():
|
||||
for p, m in self._get_files_info(command_context, paths, rev=rev).items():
|
||||
if "BUG_COMPONENT" not in m:
|
||||
missing.add(p)
|
||||
except InvalidPathException as e:
|
||||
@@ -192,14 +196,13 @@ def file_info_missing_bugzilla(command_context, paths, rev=None, fmt=None):
|
||||
print("unhandled output format: %s" % fmt)
|
||||
return 1
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"file-info",
|
||||
"bugzilla-automation",
|
||||
"Perform Bugzilla metadata analysis as required for automation",
|
||||
)
|
||||
@CommandArgument("out_dir", help="Where to write files")
|
||||
def bugzilla_automation(command_context, out_dir):
|
||||
def bugzilla_automation(self, command_context, out_dir):
|
||||
"""Analyze and validate Bugzilla metadata as required by automation.
|
||||
|
||||
This will write out JSON and gzipped JSON files for Bugzilla metadata.
|
||||
@@ -215,7 +218,7 @@ def bugzilla_automation(command_context, out_dir):
|
||||
# TODO operate in VCS space. This requires teaching the VCS reader
|
||||
# to understand wildcards and/or for the relative path issue in the
|
||||
# VCS finder to be worked out.
|
||||
for p, m in sorted(_get_files_info(command_context, ["**"]).items()):
|
||||
for p, m in sorted(self._get_files_info(command_context, ["**"]).items()):
|
||||
if "BUG_COMPONENT" not in m:
|
||||
missing_component.add(p)
|
||||
print(
|
||||
@@ -281,8 +284,7 @@ def bugzilla_automation(command_context, out_dir):
|
||||
if missing_component:
|
||||
return 1
|
||||
|
||||
|
||||
def _get_files_info(command_context, paths, rev=None):
|
||||
def _get_files_info(self, command_context, paths, rev=None):
|
||||
reader = command_context.mozbuild_reader(config_mode="empty", vcs_revision=rev)
|
||||
|
||||
# Normalize to relative from topsrcdir.
|
||||
@@ -311,7 +313,9 @@ def _get_files_info(command_context, paths, rev=None):
|
||||
continue
|
||||
|
||||
if rev:
|
||||
raise InvalidPathException("cannot use wildcard in version control mode")
|
||||
raise InvalidPathException(
|
||||
"cannot use wildcard in version control mode"
|
||||
)
|
||||
|
||||
# finder is rooted at / for now.
|
||||
# TODO bug 1171069 tracks changing to relative.
|
||||
@@ -324,12 +328,11 @@ def _get_files_info(command_context, paths, rev=None):
|
||||
|
||||
return reader.files_info(allpaths)
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"file-info", "schedules", "Show the combined SCHEDULES for the files listed."
|
||||
)
|
||||
@CommandArgument("paths", nargs="+", help="Paths whose data to query")
|
||||
def file_info_schedules(command_context, paths):
|
||||
def file_info_schedules(self, command_context, paths):
|
||||
"""Show what is scheduled by the given files.
|
||||
|
||||
Given a requested set of files (which can be specified using
|
||||
|
||||
@@ -24,6 +24,7 @@ import mozpack.path as mozpath
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandArgumentGroup,
|
||||
CommandProvider,
|
||||
Command,
|
||||
SettingsProvider,
|
||||
SubCommand,
|
||||
@@ -32,6 +33,7 @@ from mach.decorators import (
|
||||
from mozbuild.base import (
|
||||
BinaryNotFoundException,
|
||||
BuildEnvironmentNotFoundException,
|
||||
MachCommandBase,
|
||||
MachCommandConditions as conditions,
|
||||
MozbuildObject,
|
||||
)
|
||||
@@ -65,6 +67,8 @@ class StoreDebugParamsAndWarnAction(argparse.Action):
|
||||
setattr(namespace, self.dest, values)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class Watch(MachCommandBase):
|
||||
@Command(
|
||||
"watch",
|
||||
category="post-build",
|
||||
@@ -77,7 +81,7 @@ class StoreDebugParamsAndWarnAction(argparse.Action):
|
||||
action="store_true",
|
||||
help="Verbose output for what commands the watcher is running.",
|
||||
)
|
||||
def watch(command_context, verbose=False):
|
||||
def watch(self, command_context, verbose=False):
|
||||
"""Watch and re-build (parts of) the source tree."""
|
||||
if not conditions.is_artifact_build(command_context):
|
||||
print(
|
||||
@@ -112,13 +116,14 @@ def watch(command_context, verbose=False):
|
||||
sys.exit(3)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class CargoProvider(MachCommandBase):
|
||||
@Command("cargo", category="build", description="Invoke cargo in useful ways.")
|
||||
def cargo(command_context):
|
||||
def cargo(self, command_context):
|
||||
"""Invoke cargo in useful ways."""
|
||||
command_context._sub_mach(["help", "cargo"])
|
||||
self._sub_mach(["help", "cargo"])
|
||||
return 1
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"cargo",
|
||||
"check",
|
||||
@@ -130,7 +135,9 @@ def cargo(command_context):
|
||||
action="store_true",
|
||||
help="Check all of the crates in the tree.",
|
||||
)
|
||||
@CommandArgument("crates", default=None, nargs="*", help="The crate name(s) to check.")
|
||||
@CommandArgument(
|
||||
"crates", default=None, nargs="*", help="The crate name(s) to check."
|
||||
)
|
||||
@CommandArgument(
|
||||
"--jobs",
|
||||
"-j",
|
||||
@@ -141,7 +148,9 @@ def cargo(command_context):
|
||||
help="Run the tests in parallel using multiple processes.",
|
||||
)
|
||||
@CommandArgument("-v", "--verbose", action="store_true", help="Verbose output.")
|
||||
def check(command_context, all_crates=None, crates=None, jobs=0, verbose=False):
|
||||
def check(
|
||||
self, command_context, all_crates=None, crates=None, jobs=0, verbose=False
|
||||
):
|
||||
# XXX duplication with `mach vendor rust`
|
||||
crates_and_roots = {
|
||||
"gkrust": "toolkit/library/rust",
|
||||
@@ -186,6 +195,8 @@ def check(command_context, all_crates=None, crates=None, jobs=0, verbose=False):
|
||||
return 0
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class Doctor(MachCommandBase):
|
||||
@Command(
|
||||
"doctor",
|
||||
category="devenv",
|
||||
@@ -203,7 +214,7 @@ def check(command_context, all_crates=None, crates=None, jobs=0, verbose=False):
|
||||
action="store_true",
|
||||
help="Print verbose information found by checks.",
|
||||
)
|
||||
def doctor(command_context, fix=False, verbose=False):
|
||||
def doctor(self, command_context, fix=False, verbose=False):
|
||||
"""Diagnose common build environment problems"""
|
||||
command_context.activate_virtualenv()
|
||||
from mozbuild.doctor import run_doctor
|
||||
@@ -216,10 +227,11 @@ def doctor(command_context, fix=False, verbose=False):
|
||||
)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class Clobber(MachCommandBase):
|
||||
NO_AUTO_LOG = True
|
||||
CLOBBER_CHOICES = {"objdir", "python", "gradle"}
|
||||
|
||||
|
||||
@Command(
|
||||
"clobber",
|
||||
category="build",
|
||||
@@ -233,7 +245,7 @@ CLOBBER_CHOICES = {"objdir", "python", "gradle"}
|
||||
"objdir and python).".format(", ".join(CLOBBER_CHOICES)),
|
||||
)
|
||||
@CommandArgument("--full", action="store_true", help="Perform a full clobber")
|
||||
def clobber(command_context, what, full=False):
|
||||
def clobber(self, command_context, what, full=False):
|
||||
"""Clean up the source and object directories.
|
||||
|
||||
Performing builds and running various commands generate various files.
|
||||
@@ -255,11 +267,11 @@ def clobber(command_context, what, full=False):
|
||||
By default, the command clobbers the `objdir` and `python` targets.
|
||||
"""
|
||||
what = set(what)
|
||||
invalid = what - CLOBBER_CHOICES
|
||||
invalid = what - self.CLOBBER_CHOICES
|
||||
if invalid:
|
||||
print(
|
||||
"Unknown clobber target(s): {}. Choose from {{{}}}".format(
|
||||
", ".join(invalid), ", ".join(CLOBBER_CHOICES)
|
||||
", ".join(invalid), ", ".join(self.CLOBBER_CHOICES)
|
||||
)
|
||||
)
|
||||
return 1
|
||||
@@ -332,8 +344,10 @@ def clobber(command_context, what, full=False):
|
||||
return ret
|
||||
|
||||
|
||||
NO_AUTO_LOG = True
|
||||
@CommandProvider
|
||||
class Logs(MachCommandBase):
|
||||
|
||||
NO_AUTO_LOG = True
|
||||
|
||||
@Command("show-log", category="post-build", description="Display mach logs")
|
||||
@CommandArgument(
|
||||
@@ -343,7 +357,7 @@ NO_AUTO_LOG = True
|
||||
help="Filename to read log data from. Defaults to the log of the last "
|
||||
"mach command.",
|
||||
)
|
||||
def show_log(command_context, log_file=None):
|
||||
def show_log(self, command_context, log_file=None):
|
||||
"""Show mach logs."""
|
||||
if not log_file:
|
||||
path = command_context._get_state_filename("last_log.json")
|
||||
@@ -368,7 +382,9 @@ def show_log(command_context, log_file=None):
|
||||
created, action, params = json.loads(line)
|
||||
if not startTime:
|
||||
startTime = created
|
||||
command_context.log_manager.terminal_handler.formatter.start_time = created
|
||||
command_context.log_manager.terminal_handler.formatter.start_time = (
|
||||
created
|
||||
)
|
||||
if "line" in params:
|
||||
record = logging.makeLogRecord(
|
||||
{
|
||||
@@ -394,17 +410,17 @@ def show_log(command_context, log_file=None):
|
||||
less.wait()
|
||||
|
||||
|
||||
# Provide commands for inspecting warnings.
|
||||
@CommandProvider
|
||||
class Warnings(MachCommandBase):
|
||||
"""Provide commands for inspecting warnings."""
|
||||
|
||||
|
||||
def database_path(command_context):
|
||||
def database_path(self, command_context):
|
||||
return command_context._get_state_filename("warnings.json")
|
||||
|
||||
|
||||
def get_warnings_database(command_context):
|
||||
def get_warnings_database(self, command_context):
|
||||
from mozbuild.compilation.warnings import WarningsDatabase
|
||||
|
||||
path = database_path(command_context)
|
||||
path = self.database_path(command_context)
|
||||
|
||||
database = WarningsDatabase()
|
||||
|
||||
@@ -413,7 +429,6 @@ def get_warnings_database(command_context):
|
||||
|
||||
return database
|
||||
|
||||
|
||||
@Command(
|
||||
"warnings-summary",
|
||||
category="post-build",
|
||||
@@ -429,13 +444,14 @@ def get_warnings_database(command_context):
|
||||
"report",
|
||||
default=None,
|
||||
nargs="?",
|
||||
help="Warnings report to display. If not defined, show the most recent report.",
|
||||
help="Warnings report to display. If not defined, show the most "
|
||||
"recent report.",
|
||||
)
|
||||
def summary(command_context, directory=None, report=None):
|
||||
database = get_warnings_database(command_context)
|
||||
def summary(self, command_context, directory=None, report=None):
|
||||
database = self.get_warnings_database(command_context)
|
||||
|
||||
if directory:
|
||||
dirpath = join_ensure_dir(command_context.topsrcdir, directory)
|
||||
dirpath = self.join_ensure_dir(command_context.topsrcdir, directory)
|
||||
if not dirpath:
|
||||
return 1
|
||||
else:
|
||||
@@ -451,7 +467,6 @@ def summary(command_context, directory=None, report=None):
|
||||
|
||||
print("%d\tTotal" % total)
|
||||
|
||||
|
||||
@Command(
|
||||
"warnings-list",
|
||||
category="post-build",
|
||||
@@ -470,10 +485,11 @@ def summary(command_context, directory=None, report=None):
|
||||
"report",
|
||||
default=None,
|
||||
nargs="?",
|
||||
help="Warnings report to display. If not defined, show the most recent report.",
|
||||
help="Warnings report to display. If not defined, show the most "
|
||||
"recent report.",
|
||||
)
|
||||
def list_warnings(command_context, directory=None, flags=None, report=None):
|
||||
database = get_warnings_database(command_context)
|
||||
def list_warnings(self, command_context, directory=None, flags=None, report=None):
|
||||
database = self.get_warnings_database(command_context)
|
||||
|
||||
by_name = sorted(database.warnings)
|
||||
|
||||
@@ -481,7 +497,7 @@ def list_warnings(command_context, directory=None, flags=None, report=None):
|
||||
|
||||
if directory:
|
||||
directory = mozpath.normsep(directory)
|
||||
dirpath = join_ensure_dir(topsrcdir, directory)
|
||||
dirpath = self.join_ensure_dir(topsrcdir, directory)
|
||||
if not dirpath:
|
||||
return 1
|
||||
|
||||
@@ -518,8 +534,7 @@ def list_warnings(command_context, directory=None, flags=None, report=None):
|
||||
% (filename, warning["line"], warning["flag"], warning["message"])
|
||||
)
|
||||
|
||||
|
||||
def join_ensure_dir(dir1, dir2):
|
||||
def join_ensure_dir(self, dir1, dir2):
|
||||
dir1 = mozpath.normpath(dir1)
|
||||
dir2 = mozpath.normsep(dir2)
|
||||
joined_path = mozpath.join(dir1, dir2)
|
||||
@@ -529,7 +544,11 @@ def join_ensure_dir(dir1, dir2):
|
||||
return None
|
||||
|
||||
|
||||
@Command("gtest", category="testing", description="Run GTest unit tests (C++ tests).")
|
||||
@CommandProvider
|
||||
class GTestCommands(MachCommandBase):
|
||||
@Command(
|
||||
"gtest", category="testing", description="Run GTest unit tests (C++ tests)."
|
||||
)
|
||||
@CommandArgument(
|
||||
"gtest_filter",
|
||||
default="*",
|
||||
@@ -540,7 +559,9 @@ def join_ensure_dir(dir1, dir2):
|
||||
"and another ':'-separated pattern list (called the negative patterns)."
|
||||
"Test names are of the format SUITE.NAME. Use --list-tests to see all.",
|
||||
)
|
||||
@CommandArgument("--list-tests", action="store_true", help="list all available tests")
|
||||
@CommandArgument(
|
||||
"--list-tests", action="store_true", help="list all available tests"
|
||||
)
|
||||
@CommandArgument(
|
||||
"--jobs",
|
||||
"-j",
|
||||
@@ -591,7 +612,7 @@ def join_ensure_dir(dir1, dir2):
|
||||
"--remoteTestRoot",
|
||||
dest="remote_test_root",
|
||||
group="Android",
|
||||
help="Remote directory to use as test root (eg. /data/local/tmp/test_root).",
|
||||
help="Remote directory to use as test root " "(eg. /data/local/tmp/test_root).",
|
||||
)
|
||||
@CommandArgument(
|
||||
"--libxul", dest="libxul_path", group="Android", help="Path to gtest libxul.so."
|
||||
@@ -628,6 +649,7 @@ def join_ensure_dir(dir1, dir2):
|
||||
"split as the Bourne shell would.",
|
||||
)
|
||||
def gtest(
|
||||
self,
|
||||
command_context,
|
||||
shuffle,
|
||||
jobs,
|
||||
@@ -674,10 +696,12 @@ def gtest(
|
||||
if jobs != 1:
|
||||
print("--jobs is not supported on Android and will be ignored")
|
||||
if debug or debugger or debugger_args:
|
||||
print("--debug options are not supported on Android and will be ignored")
|
||||
print(
|
||||
"--debug options are not supported on Android and will be ignored"
|
||||
)
|
||||
from mozrunner.devices.android_device import InstallIntent
|
||||
|
||||
return android_gtest(
|
||||
return self.android_gtest(
|
||||
command_context,
|
||||
cwd,
|
||||
shuffle,
|
||||
@@ -726,7 +750,9 @@ def gtest(
|
||||
# Note: we must normalize the path here so that gtest on Windows sees
|
||||
# a MOZ_GMP_PATH which has only Windows dir seperators, because
|
||||
# nsIFile cannot open the paths with non-Windows dir seperators.
|
||||
xre_path = os.path.join(os.path.normpath(command_context.topobjdir), "dist", "bin")
|
||||
xre_path = os.path.join(
|
||||
os.path.normpath(command_context.topobjdir), "dist", "bin"
|
||||
)
|
||||
gtest_env["MOZ_XRE_DIR"] = xre_path
|
||||
gtest_env["MOZ_GMP_PATH"] = os.pathsep.join(
|
||||
os.path.join(xre_path, p, "1.0") for p in ("gmp-fake", "gmp-fakeopenh264")
|
||||
@@ -789,8 +815,8 @@ def gtest(
|
||||
|
||||
return exit_code
|
||||
|
||||
|
||||
def android_gtest(
|
||||
self,
|
||||
command_context,
|
||||
test_dir,
|
||||
shuffle,
|
||||
@@ -852,6 +878,8 @@ def android_gtest(
|
||||
return exit_code
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class Package(MachCommandBase):
|
||||
@Command(
|
||||
"package",
|
||||
category="post-build",
|
||||
@@ -863,7 +891,7 @@ def android_gtest(
|
||||
action="store_true",
|
||||
help="Verbose output for what commands the packaging process is running.",
|
||||
)
|
||||
def package(command_context, verbose=False):
|
||||
def package(self, command_context, verbose=False):
|
||||
"""Package the built product for distribution."""
|
||||
ret = command_context._run_make(
|
||||
directory=".", target="package", silent=not verbose, ensure_exit_code=False
|
||||
@@ -878,7 +906,7 @@ def _get_android_install_parser():
|
||||
parser.add_argument(
|
||||
"--app",
|
||||
default="org.mozilla.geckoview_example",
|
||||
help="Android package to install (default: org.mozilla.geckoview_example)",
|
||||
help="Android package to install " "(default: org.mozilla.geckoview_example)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--verbose",
|
||||
@@ -896,6 +924,8 @@ def setup_install_parser():
|
||||
return argparse.ArgumentParser()
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class Install(MachCommandBase):
|
||||
@Command(
|
||||
"install",
|
||||
category="post-build",
|
||||
@@ -903,7 +933,7 @@ def setup_install_parser():
|
||||
parser=setup_install_parser,
|
||||
description="Install the package on the machine (or device in the case of Android).",
|
||||
)
|
||||
def install(command_context, **kwargs):
|
||||
def install(self, command_context, **kwargs):
|
||||
"""Install a package."""
|
||||
if conditions.is_android(command_context):
|
||||
from mozrunner.devices.android_device import (
|
||||
@@ -912,7 +942,9 @@ def install(command_context, **kwargs):
|
||||
)
|
||||
|
||||
ret = (
|
||||
verify_android_device(command_context, install=InstallIntent.YES, **kwargs)
|
||||
verify_android_device(
|
||||
command_context, install=InstallIntent.YES, **kwargs
|
||||
)
|
||||
== 0
|
||||
)
|
||||
else:
|
||||
@@ -946,7 +978,7 @@ def _get_android_run_parser():
|
||||
group.add_argument(
|
||||
"--app",
|
||||
default="org.mozilla.geckoview_example",
|
||||
help="Android package to run (default: org.mozilla.geckoview_example)",
|
||||
help="Android package to run " "(default: org.mozilla.geckoview_example)",
|
||||
)
|
||||
group.add_argument(
|
||||
"--intent",
|
||||
@@ -1205,6 +1237,8 @@ def setup_run_parser():
|
||||
return _get_desktop_run_parser()
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class RunProgram(MachCommandBase):
|
||||
@Command(
|
||||
"run",
|
||||
category="post-build",
|
||||
@@ -1212,16 +1246,16 @@ def setup_run_parser():
|
||||
parser=setup_run_parser,
|
||||
description="Run the compiled program, possibly under a debugger or DMD.",
|
||||
)
|
||||
def run(command_context, **kwargs):
|
||||
def run(self, command_context, **kwargs):
|
||||
"""Run the compiled program."""
|
||||
if conditions.is_android(command_context):
|
||||
return _run_android(command_context, **kwargs)
|
||||
return self._run_android(command_context, **kwargs)
|
||||
if conditions.is_jsshell(command_context):
|
||||
return _run_jsshell(command_context, **kwargs)
|
||||
return _run_desktop(command_context, **kwargs)
|
||||
|
||||
return self._run_jsshell(command_context, **kwargs)
|
||||
return self._run_desktop(command_context, **kwargs)
|
||||
|
||||
def _run_android(
|
||||
self,
|
||||
command_context,
|
||||
app="org.mozilla.geckoview_example",
|
||||
intent=None,
|
||||
@@ -1515,7 +1549,9 @@ platform connect {connect_url}
|
||||
process attach {continue_flag}-p {pid!s}
|
||||
""".lstrip()
|
||||
|
||||
obj_xul = os.path.join(command_context.topobjdir, "toolkit", "library", "build")
|
||||
obj_xul = os.path.join(
|
||||
command_context.topobjdir, "toolkit", "library", "build"
|
||||
)
|
||||
obj_mozglue = os.path.join(command_context.topobjdir, "mozglue", "build")
|
||||
obj_nss = os.path.join(command_context.topobjdir, "security")
|
||||
|
||||
@@ -1567,12 +1603,13 @@ process attach {continue_flag}-p {pid!s}
|
||||
if not use_existing_process:
|
||||
device.shell("am clear-debug-app")
|
||||
|
||||
|
||||
def _run_jsshell(command_context, params, debug, debugger, debugger_args):
|
||||
def _run_jsshell(self, command_context, params, debug, debugger, debugger_args):
|
||||
try:
|
||||
binpath = command_context.get_binary_path("app")
|
||||
except BinaryNotFoundException as e:
|
||||
command_context.log(logging.ERROR, "run", {"error": str(e)}, "ERROR: {error}")
|
||||
command_context.log(
|
||||
logging.ERROR, "run", {"error": str(e)}, "ERROR: {error}"
|
||||
)
|
||||
command_context.log(logging.INFO, "run", {"help": e.help()}, "{help}")
|
||||
return 1
|
||||
|
||||
@@ -1610,8 +1647,8 @@ def _run_jsshell(command_context, params, debug, debugger, debugger_args):
|
||||
args=args, ensure_exit_code=False, pass_thru=True, append_env=extra_env
|
||||
)
|
||||
|
||||
|
||||
def _run_desktop(
|
||||
self,
|
||||
command_context,
|
||||
params,
|
||||
packaged,
|
||||
@@ -1641,7 +1678,9 @@ def _run_desktop(
|
||||
else:
|
||||
binpath = app or command_context.get_binary_path("app")
|
||||
except BinaryNotFoundException as e:
|
||||
command_context.log(logging.ERROR, "run", {"error": str(e)}, "ERROR: {error}")
|
||||
command_context.log(
|
||||
logging.ERROR, "run", {"error": str(e)}, "ERROR: {error}"
|
||||
)
|
||||
if packaged:
|
||||
command_context.log(
|
||||
logging.INFO,
|
||||
@@ -1824,18 +1863,22 @@ def _run_desktop(
|
||||
)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class Buildsymbols(MachCommandBase):
|
||||
@Command(
|
||||
"buildsymbols",
|
||||
category="post-build",
|
||||
description="Produce a package of Breakpad-format symbols.",
|
||||
)
|
||||
def buildsymbols(command_context):
|
||||
def buildsymbols(self, command_context):
|
||||
"""Produce a package of debug symbols suitable for use with Breakpad."""
|
||||
return command_context._run_make(
|
||||
directory=".", target="buildsymbols", ensure_exit_code=False
|
||||
)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachDebug(MachCommandBase):
|
||||
@Command(
|
||||
"environment",
|
||||
category="build-dev",
|
||||
@@ -1848,11 +1891,11 @@ def buildsymbols(command_context):
|
||||
help="Print data in the given format.",
|
||||
)
|
||||
@CommandArgument("--output", "-o", type=str, help="Output to the given file.")
|
||||
@CommandArgument("--verbose", "-v", action="store_true", help="Print verbose output.")
|
||||
def environment(command_context, format, output=None, verbose=False):
|
||||
func = {"pretty": _environment_pretty, "json": _environment_json}[
|
||||
format.replace(".", "_")
|
||||
]
|
||||
@CommandArgument(
|
||||
"--verbose", "-v", action="store_true", help="Print verbose output."
|
||||
)
|
||||
def environment(self, command_context, format, output=None, verbose=False):
|
||||
func = getattr(self, "_environment_%s" % format.replace(".", "_"))
|
||||
|
||||
if output:
|
||||
# We want to preserve mtimes if the output file already exists
|
||||
@@ -1863,8 +1906,7 @@ def environment(command_context, format, output=None, verbose=False):
|
||||
return func(command_context, out, verbose)
|
||||
return func(command_context, sys.stdout, verbose)
|
||||
|
||||
|
||||
def _environment_pretty(command_context, out, verbose):
|
||||
def _environment_pretty(self, command_context, out, verbose):
|
||||
state_dir = command_context._mach_context.state_dir
|
||||
|
||||
print("platform:\n\t%s" % platform.platform(), file=out)
|
||||
@@ -1915,8 +1957,7 @@ def _environment_pretty(command_context, out, verbose):
|
||||
for k in sorted(config.defines):
|
||||
print("\t%s" % k, file=out)
|
||||
|
||||
|
||||
def _environment_json(command_context, out, verbose):
|
||||
def _environment_json(self, command_context, out, verbose):
|
||||
import json
|
||||
|
||||
class EnvironmentEncoder(json.JSONEncoder):
|
||||
@@ -1938,12 +1979,14 @@ def _environment_json(command_context, out, verbose):
|
||||
json.dump(command_context, cls=EnvironmentEncoder, sort_keys=True, fp=out)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class Repackage(MachCommandBase):
|
||||
@Command(
|
||||
"repackage",
|
||||
category="misc",
|
||||
description="Repackage artifacts into different formats.",
|
||||
)
|
||||
def repackage(command_context):
|
||||
def repackage(self, command_context):
|
||||
"""Repackages artifacts into different formats.
|
||||
|
||||
This is generally used after packages are signed by the signing
|
||||
@@ -1952,11 +1995,12 @@ def repackage(command_context):
|
||||
"""
|
||||
print("Usage: ./mach repackage [dmg|installer|mar] [args...]")
|
||||
|
||||
|
||||
@SubCommand("repackage", "dmg", description="Repackage a tar file into a .dmg for OSX")
|
||||
@SubCommand(
|
||||
"repackage", "dmg", description="Repackage a tar file into a .dmg for OSX"
|
||||
)
|
||||
@CommandArgument("--input", "-i", type=str, required=True, help="Input filename")
|
||||
@CommandArgument("--output", "-o", type=str, required=True, help="Output filename")
|
||||
def repackage_dmg(command_context, input, output):
|
||||
def repackage_dmg(self, command_context, input, output):
|
||||
if not os.path.exists(input):
|
||||
print("Input file does not exist: %s" % input)
|
||||
return 1
|
||||
@@ -1972,7 +2016,6 @@ def repackage_dmg(command_context, input, output):
|
||||
|
||||
repackage_dmg(input, output)
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"repackage", "installer", description="Repackage into a Windows installer exe"
|
||||
)
|
||||
@@ -2011,6 +2054,7 @@ def repackage_dmg(command_context, input, output):
|
||||
help="Run UPX on the self-extraction stub.",
|
||||
)
|
||||
def repackage_installer(
|
||||
self,
|
||||
command_context,
|
||||
tag,
|
||||
setupexe,
|
||||
@@ -2033,7 +2077,6 @@ def repackage_installer(
|
||||
use_upx=use_upx,
|
||||
)
|
||||
|
||||
|
||||
@SubCommand("repackage", "msi", description="Repackage into a MSI")
|
||||
@CommandArgument(
|
||||
"--wsx",
|
||||
@@ -2054,10 +2097,15 @@ def repackage_installer(
|
||||
"--arch", type=str, required=True, help="The architecture you are building."
|
||||
)
|
||||
@CommandArgument("--setupexe", type=str, required=True, help="setup.exe installer")
|
||||
@CommandArgument("--candle", type=str, required=False, help="location of candle binary")
|
||||
@CommandArgument("--light", type=str, required=False, help="location of light binary")
|
||||
@CommandArgument(
|
||||
"--candle", type=str, required=False, help="location of candle binary"
|
||||
)
|
||||
@CommandArgument(
|
||||
"--light", type=str, required=False, help="location of light binary"
|
||||
)
|
||||
@CommandArgument("--output", "-o", type=str, required=True, help="Output filename")
|
||||
def repackage_msi(
|
||||
self,
|
||||
command_context,
|
||||
wsx,
|
||||
version,
|
||||
@@ -2082,7 +2130,6 @@ def repackage_msi(
|
||||
output=output,
|
||||
)
|
||||
|
||||
|
||||
@SubCommand("repackage", "msix", description="Repackage into an MSIX")
|
||||
@CommandArgument(
|
||||
"--input",
|
||||
@@ -2173,6 +2220,7 @@ def repackage_msi(
|
||||
"(Default: false)",
|
||||
)
|
||||
def repackage_msix(
|
||||
self,
|
||||
command_context,
|
||||
input,
|
||||
version=None,
|
||||
@@ -2233,8 +2281,9 @@ def repackage_msix(
|
||||
)
|
||||
|
||||
if sign:
|
||||
repackage_sign_msix(command_context, output, force=False, verbose=verbose)
|
||||
|
||||
self.repackage_sign_msix(
|
||||
command_context, output, force=False, verbose=verbose
|
||||
)
|
||||
|
||||
@SubCommand("repackage", "sign-msix", description="Sign an MSIX for local testing")
|
||||
@CommandArgument("--input", type=str, required=True, help="MSIX to sign.")
|
||||
@@ -2250,7 +2299,7 @@ def repackage_msix(
|
||||
action="store_true",
|
||||
help="Be verbose. (Default: false)",
|
||||
)
|
||||
def repackage_sign_msix(command_context, input, force=False, verbose=False):
|
||||
def repackage_sign_msix(self, command_context, input, force=False, verbose=False):
|
||||
from mozbuild.repackaging.msix import sign_msix
|
||||
|
||||
command_context._set_log_level(verbose)
|
||||
@@ -2259,7 +2308,6 @@ def repackage_sign_msix(command_context, input, force=False, verbose=False):
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
@SubCommand("repackage", "mar", description="Repackage into complete MAR file")
|
||||
@CommandArgument("--input", "-i", type=str, required=True, help="Input filename")
|
||||
@CommandArgument("--mar", type=str, required=True, help="Mar binary path")
|
||||
@@ -2268,7 +2316,7 @@ def repackage_sign_msix(command_context, input, force=False, verbose=False):
|
||||
"--arch", type=str, required=True, help="The architecture you are building."
|
||||
)
|
||||
@CommandArgument("--mar-channel-id", type=str, help="Mar channel id")
|
||||
def repackage_mar(command_context, input, mar, output, arch, mar_channel_id):
|
||||
def repackage_mar(self, command_context, input, mar, output, arch, mar_channel_id):
|
||||
from mozbuild.repackaging.mar import repackage_mar
|
||||
|
||||
repackage_mar(
|
||||
@@ -2281,6 +2329,8 @@ def repackage_mar(command_context, input, mar, output, arch, mar_channel_id):
|
||||
)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class L10NCommands(MachCommandBase):
|
||||
@Command(
|
||||
"package-multi-locale",
|
||||
category="post-build",
|
||||
@@ -2297,7 +2347,7 @@ def repackage_mar(command_context, input, mar, output, arch, mar_channel_id):
|
||||
@CommandArgument(
|
||||
"--verbose", action="store_true", help="Log informative status messages."
|
||||
)
|
||||
def package_l10n(command_context, verbose=False, locales=[]):
|
||||
def package_l10n(self, command_context, verbose=False, locales=[]):
|
||||
if "RecursiveMake" not in command_context.substs["BUILD_BACKENDS"]:
|
||||
print(
|
||||
"Artifact builds do not support localization. "
|
||||
@@ -2425,6 +2475,8 @@ def package_l10n(command_context, verbose=False, locales=[]):
|
||||
return 0
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class CreateMachEnvironment(MachCommandBase):
|
||||
@Command(
|
||||
"create-mach-environment",
|
||||
category="devenv",
|
||||
@@ -2434,9 +2486,9 @@ def package_l10n(command_context, verbose=False, locales=[]):
|
||||
"-f",
|
||||
"--force",
|
||||
action="store_true",
|
||||
help=("Force re-creating the virtualenv even if it is already up-to-date."),
|
||||
help=("Force re-creating the virtualenv even if it is already " "up-to-date."),
|
||||
)
|
||||
def create_mach_environment(command_context, force=False):
|
||||
def create_mach_environment(self, command_context, force=False):
|
||||
"""Create the mach virtualenv."""
|
||||
from mozboot.util import get_mach_virtualenv_root
|
||||
from mozbuild.virtualenv import VirtualenvManager
|
||||
|
||||
@@ -32,19 +32,20 @@ class TestStaticAnalysis(unittest.TestCase):
|
||||
# world we should test the clang_analysis mach command
|
||||
# since that small function is an internal detail.
|
||||
# But there is zero test infra for that mach command
|
||||
from mozbuild.code_analysis.mach_commands import _is_ignored_path
|
||||
from mozbuild.code_analysis.mach_commands import StaticAnalysis
|
||||
|
||||
config = MozbuildObject.from_environment()
|
||||
context = mock.MagicMock()
|
||||
context.cwd = config.topsrcdir
|
||||
|
||||
cmd = StaticAnalysis(context)
|
||||
command_context = mock.MagicMock()
|
||||
command_context.topsrcdir = os.path.join("/root", "dir")
|
||||
path = os.path.join("/root", "dir", "path1")
|
||||
|
||||
ignored_dirs_re = r"path1|path2/here|path3\there"
|
||||
self.assertTrue(
|
||||
_is_ignored_path(command_context, ignored_dirs_re, path) is not None
|
||||
cmd._is_ignored_path(command_context, ignored_dirs_re, path) is not None
|
||||
)
|
||||
|
||||
# simulating a win32 env
|
||||
@@ -54,26 +55,27 @@ class TestStaticAnalysis(unittest.TestCase):
|
||||
os.sep = "\\"
|
||||
try:
|
||||
self.assertTrue(
|
||||
_is_ignored_path(command_context, ignored_dirs_re, win32_path)
|
||||
cmd._is_ignored_path(command_context, ignored_dirs_re, win32_path)
|
||||
is not None
|
||||
)
|
||||
finally:
|
||||
os.sep = old_sep
|
||||
|
||||
self.assertTrue(
|
||||
_is_ignored_path(command_context, ignored_dirs_re, "path2") is None
|
||||
cmd._is_ignored_path(command_context, ignored_dirs_re, "path2") is None
|
||||
)
|
||||
|
||||
def test_get_files(self):
|
||||
from mozbuild.code_analysis.mach_commands import get_abspath_files
|
||||
from mozbuild.code_analysis.mach_commands import StaticAnalysis
|
||||
|
||||
config = MozbuildObject.from_environment()
|
||||
context = mock.MagicMock()
|
||||
context.cwd = config.topsrcdir
|
||||
|
||||
cmd = StaticAnalysis(context)
|
||||
command_context = mock.MagicMock()
|
||||
command_context.topsrcdir = mozpath.join("/root", "dir")
|
||||
source = get_abspath_files(
|
||||
source = cmd.get_abspath_files(
|
||||
command_context, ["file1", mozpath.join("directory", "file2")]
|
||||
)
|
||||
|
||||
|
||||
27
python/mozbuild/mozbuild/vendor/mach_commands.py
vendored
27
python/mozbuild/mozbuild/vendor/mach_commands.py
vendored
@@ -7,11 +7,14 @@ from __future__ import absolute_import, print_function, unicode_literals
|
||||
import sys
|
||||
import logging
|
||||
|
||||
from mach.decorators import CommandArgument, Command, SubCommand
|
||||
from mach.decorators import CommandArgument, CommandProvider, Command, SubCommand
|
||||
|
||||
from mozbuild.base import MachCommandBase
|
||||
from mozbuild.vendor.moz_yaml import load_moz_yaml, MozYamlVerifyError
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class Vendor(MachCommandBase):
|
||||
# Fun quirk of ./mach - you can specify a default argument as well as subcommands.
|
||||
# If the default argument matches a subcommand, the subcommand gets called. If it
|
||||
# doesn't, we wind up in the default command.
|
||||
@@ -42,8 +45,11 @@ from mozbuild.vendor.moz_yaml import load_moz_yaml, MozYamlVerifyError
|
||||
@CommandArgument(
|
||||
"--verify", "-v", action="store_true", help="(Only) verify the manifest"
|
||||
)
|
||||
@CommandArgument("library", nargs=1, help="The moz.yaml file of the library to vendor.")
|
||||
@CommandArgument(
|
||||
"library", nargs=1, help="The moz.yaml file of the library to vendor."
|
||||
)
|
||||
def vendor(
|
||||
self,
|
||||
command_context,
|
||||
library,
|
||||
revision,
|
||||
@@ -76,19 +82,20 @@ def vendor(
|
||||
sys.exit(1)
|
||||
|
||||
if not ignore_modified and not check_for_update:
|
||||
check_modified_files(command_context)
|
||||
self.check_modified_files(command_context)
|
||||
if not revision:
|
||||
revision = "HEAD"
|
||||
|
||||
from mozbuild.vendor.vendor_manifest import VendorManifest
|
||||
|
||||
vendor_command = command_context._spawn(VendorManifest)
|
||||
vendor_command.vendor(library, manifest, revision, check_for_update, add_to_exports)
|
||||
vendor_command.vendor(
|
||||
library, manifest, revision, check_for_update, add_to_exports
|
||||
)
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def check_modified_files(command_context):
|
||||
def check_modified_files(self, command_context):
|
||||
"""
|
||||
Ensure that there aren't any uncommitted changes to files
|
||||
in the working copy, since we're going to change some state
|
||||
@@ -111,10 +118,8 @@ Please commit or stash these changes before vendoring, or re-run with `--ignore-
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"vendor",
|
||||
"rust",
|
||||
@@ -136,16 +141,14 @@ Please commit or stash these changes before vendoring, or re-run with `--ignore-
|
||||
),
|
||||
default=False,
|
||||
)
|
||||
def vendor_rust(command_context, **kwargs):
|
||||
def vendor_rust(self, command_context, **kwargs):
|
||||
from mozbuild.vendor.vendor_rust import VendorRust
|
||||
|
||||
vendor_command = command_context._spawn(VendorRust)
|
||||
vendor_command.vendor(**kwargs)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"vendor",
|
||||
"python",
|
||||
@@ -160,7 +163,7 @@ def vendor_rust(command_context, **kwargs):
|
||||
default=False,
|
||||
help="Keep all files, including tests and documentation.",
|
||||
)
|
||||
def vendor_python(command_context, **kwargs):
|
||||
def vendor_python(self, command_context, **kwargs):
|
||||
from mozbuild.vendor.vendor_python import VendorPython
|
||||
|
||||
if sys.version_info[:2] != (3, 6):
|
||||
|
||||
@@ -6,8 +6,8 @@ import sys
|
||||
from functools import partial
|
||||
import json
|
||||
|
||||
from mach.decorators import Command, CommandArgument
|
||||
from mozbuild.base import MachCommandConditions as conditions
|
||||
from mach.decorators import CommandProvider, Command, CommandArgument
|
||||
from mozbuild.base import MachCommandBase, MachCommandConditions as conditions
|
||||
|
||||
|
||||
_TRY_PLATFORMS = {
|
||||
@@ -30,9 +30,10 @@ def get_perftest_parser():
|
||||
return PerftestArgumentParser
|
||||
|
||||
|
||||
def get_parser():
|
||||
return run_perftest._mach_command._parser
|
||||
|
||||
@CommandProvider
|
||||
class Perftest(MachCommandBase):
|
||||
def get_parser(self):
|
||||
return self.run_perftest._mach_command._parser
|
||||
|
||||
@Command(
|
||||
"perftest",
|
||||
@@ -41,9 +42,9 @@ def get_parser():
|
||||
description="Run any flavor of perftest",
|
||||
parser=get_perftest_parser,
|
||||
)
|
||||
def run_perftest(command_context, **kwargs):
|
||||
def run_perftest(self, command_context, **kwargs):
|
||||
# original parser that brought us there
|
||||
original_parser = get_parser()
|
||||
original_parser = self.get_parser()
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
@@ -111,7 +112,9 @@ def run_perftest(command_context, **kwargs):
|
||||
if isinstance(platform, str):
|
||||
platform = [platform]
|
||||
|
||||
platform = ["%s-%s" % (plat, script_info.script_type.name) for plat in platform]
|
||||
platform = [
|
||||
"%s-%s" % (plat, script_info.script_type.name) for plat in platform
|
||||
]
|
||||
|
||||
for plat in platform:
|
||||
if plat not in _TRY_PLATFORMS:
|
||||
@@ -158,6 +161,8 @@ def run_perftest(command_context, **kwargs):
|
||||
print("\nFirefox. Fast For Good.\n")
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class PerftestTests(MachCommandBase):
|
||||
@Command("perftest-test", category="testing", description="Run perftest tests")
|
||||
@CommandArgument(
|
||||
"tests", default=None, nargs="*", help="Tests to run. By default will run all"
|
||||
@@ -172,7 +177,7 @@ def run_perftest(command_context, **kwargs):
|
||||
@CommandArgument(
|
||||
"-v", "--verbose", action="store_true", default=False, help="Verbose mode"
|
||||
)
|
||||
def run_tests(command_context, **kwargs):
|
||||
def run_tests(self, command_context, **kwargs):
|
||||
command_context.activate_virtualenv()
|
||||
|
||||
from pathlib import Path
|
||||
@@ -181,10 +186,9 @@ def run_tests(command_context, **kwargs):
|
||||
with temporary_env(
|
||||
COVERAGE_RCFILE=str(Path(HERE, ".coveragerc")), RUNNING_TESTS="YES"
|
||||
):
|
||||
_run_tests(command_context, **kwargs)
|
||||
self._run_tests(command_context, **kwargs)
|
||||
|
||||
|
||||
def _run_tests(command_context, **kwargs):
|
||||
def _run_tests(self, command_context, **kwargs):
|
||||
from pathlib import Path
|
||||
from mozperftest.runner import _setup_path
|
||||
from mozperftest.utils import (
|
||||
@@ -210,14 +214,18 @@ def _run_tests(command_context, **kwargs):
|
||||
|
||||
# pip-installing dependencies that require compilation or special setup
|
||||
for dep in vendors:
|
||||
install_package(command_context.virtualenv_manager, str(Path(pydeps, dep)))
|
||||
install_package(
|
||||
command_context.virtualenv_manager, str(Path(pydeps, dep))
|
||||
)
|
||||
|
||||
if not ON_TRY and not skip_linters:
|
||||
cmd = "./mach lint "
|
||||
if verbose:
|
||||
cmd += " -v"
|
||||
cmd += " " + str(HERE)
|
||||
if not checkout_script(cmd, label="linters", display=verbose, verbose=verbose):
|
||||
if not checkout_script(
|
||||
cmd, label="linters", display=verbose, verbose=verbose
|
||||
):
|
||||
raise AssertionError("Please fix your code.")
|
||||
|
||||
# running pytest with coverage
|
||||
|
||||
@@ -17,10 +17,9 @@ from mach.registrar import Registrar
|
||||
Registrar.categories = {"testing": []}
|
||||
Registrar.commands_by_category = {"testing": set()}
|
||||
|
||||
from mozbuild.base import MachCommandBase # noqa
|
||||
|
||||
import mozperftest.mach_commands # noqa
|
||||
from mozperftest.environment import MachEnvironment # noqa
|
||||
from mozperftest.mach_commands import Perftest, PerftestTests # noqa
|
||||
from mozperftest.tests.support import EXAMPLE_TEST, ROOT, running_on_try # noqa
|
||||
from mozperftest.utils import temporary_env, silence # noqa
|
||||
|
||||
@@ -46,7 +45,7 @@ class _TestMachEnvironment(MachEnvironment):
|
||||
|
||||
|
||||
@contextmanager
|
||||
def _get_command(command=mozperftest.mach_commands.run_perftest):
|
||||
def _get_command(klass=Perftest):
|
||||
from mozbuild.base import MozbuildObject
|
||||
from mozperftest.argparser import PerftestArgumentParser
|
||||
|
||||
@@ -69,59 +68,59 @@ def _get_command(command=mozperftest.mach_commands.run_perftest):
|
||||
return _run
|
||||
|
||||
try:
|
||||
command_context = MachCommandBase(context())
|
||||
obj = klass(context())
|
||||
parser = PerftestArgumentParser()
|
||||
obj.get_parser = lambda: parser
|
||||
|
||||
if command == mozperftest.mach_commands.run_perftest:
|
||||
command = _run_perftest(command)
|
||||
if isinstance(obj, Perftest):
|
||||
obj.run_perftest = _run_perftest(obj.run_perftest)
|
||||
|
||||
with mock.patch("mozperftest.mach_commands.get_parser", new=lambda: parser):
|
||||
yield command, command_context
|
||||
yield obj
|
||||
finally:
|
||||
shutil.rmtree(context.state_dir)
|
||||
|
||||
|
||||
@mock.patch("mozperftest.MachEnvironment", new=_TestMachEnvironment)
|
||||
@mock.patch("mozbuild.base.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("mozperftest.mach_commands.MachCommandBase.activate_virtualenv")
|
||||
def test_command(mocked_func):
|
||||
with _get_command() as (cmd, command_context), silence(command_context):
|
||||
cmd(command_context, tests=[EXAMPLE_TEST], flavor="desktop-browser")
|
||||
with _get_command() as test, silence(test):
|
||||
test.run_perftest(test, tests=[EXAMPLE_TEST], flavor="desktop-browser")
|
||||
|
||||
|
||||
@mock.patch("mozperftest.MachEnvironment")
|
||||
@mock.patch("mozbuild.base.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("mozperftest.mach_commands.MachCommandBase.activate_virtualenv")
|
||||
def test_command_iterations(venv, env):
|
||||
kwargs = {
|
||||
"tests": [EXAMPLE_TEST],
|
||||
"hooks": ITERATION_HOOKS,
|
||||
"flavor": "desktop-browser",
|
||||
}
|
||||
with _get_command() as (cmd, command_context), silence(command_context):
|
||||
cmd(command_context, **kwargs)
|
||||
with _get_command() as test, silence(test):
|
||||
test.run_perftest(test, **kwargs)
|
||||
# the hook changes the iteration value to 5.
|
||||
# each iteration generates 5 calls, so we want to see 25
|
||||
assert len(env.mock_calls) == 25
|
||||
|
||||
|
||||
@mock.patch("mozperftest.MachEnvironment")
|
||||
@mock.patch("mozbuild.base.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("mozperftest.mach_commands.MachCommandBase.activate_virtualenv")
|
||||
def test_hooks_state(venv, env):
|
||||
kwargs = {
|
||||
"tests": [EXAMPLE_TEST],
|
||||
"hooks": STATE_HOOKS,
|
||||
"flavor": "desktop-browser",
|
||||
}
|
||||
with _get_command() as (cmd, command_context), silence(command_context):
|
||||
cmd(command_context, **kwargs)
|
||||
with _get_command() as test, silence(test):
|
||||
test.run_perftest(test, **kwargs)
|
||||
|
||||
|
||||
@mock.patch("mozperftest.MachEnvironment", new=_TestMachEnvironment)
|
||||
@mock.patch("mozbuild.base.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("mozperftest.mach_commands.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("tryselect.push.push_to_try")
|
||||
def test_push_command(push_to_try, venv):
|
||||
with _get_command() as (cmd, command_context), silence(command_context):
|
||||
cmd(
|
||||
command_context,
|
||||
with _get_command() as test, silence(test):
|
||||
test.run_perftest(
|
||||
test,
|
||||
tests=[EXAMPLE_TEST],
|
||||
flavor="desktop-browser",
|
||||
push_to_try=True,
|
||||
@@ -132,13 +131,13 @@ def test_push_command(push_to_try, venv):
|
||||
|
||||
|
||||
@mock.patch("mozperftest.MachEnvironment", new=_TestMachEnvironment)
|
||||
@mock.patch("mozbuild.base.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("mozperftest.mach_commands.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("tryselect.push.push_to_try")
|
||||
def test_push_command_unknown_platforms(push_to_try, venv):
|
||||
# full stop when a platform is unknown
|
||||
with _get_command() as (cmd, command_context), pytest.raises(NotImplementedError):
|
||||
cmd(
|
||||
command_context,
|
||||
with _get_command() as test, pytest.raises(NotImplementedError):
|
||||
test.run_perftest(
|
||||
test,
|
||||
tests=[EXAMPLE_TEST],
|
||||
flavor="desktop-browser",
|
||||
push_to_try=True,
|
||||
@@ -147,15 +146,12 @@ def test_push_command_unknown_platforms(push_to_try, venv):
|
||||
|
||||
|
||||
@mock.patch("mozperftest.MachEnvironment", new=_TestMachEnvironment)
|
||||
@mock.patch("mozbuild.base.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("mozperftest.mach_commands.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("tryselect.push.push_to_try")
|
||||
def test_push_command_several_platforms(push_to_try, venv):
|
||||
with running_on_try(False), _get_command() as (
|
||||
cmd,
|
||||
command_context,
|
||||
): # , silence(command_context):
|
||||
cmd(
|
||||
command_context,
|
||||
with running_on_try(False), _get_command() as test: # , silence(test):
|
||||
test.run_perftest(
|
||||
test,
|
||||
tests=[EXAMPLE_TEST],
|
||||
flavor="desktop-browser",
|
||||
push_to_try=True,
|
||||
@@ -169,45 +165,39 @@ def test_push_command_several_platforms(push_to_try, venv):
|
||||
|
||||
|
||||
@mock.patch("mozperftest.MachEnvironment", new=_TestMachEnvironment)
|
||||
@mock.patch("mozbuild.base.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("mozperftest.mach_commands.MachCommandBase.activate_virtualenv")
|
||||
def test_doc_flavor(mocked_func):
|
||||
with _get_command() as (cmd, command_context), silence(command_context):
|
||||
cmd(command_context, tests=[EXAMPLE_TEST], flavor="doc")
|
||||
with _get_command() as test, silence(test):
|
||||
test.run_perftest(test, tests=[EXAMPLE_TEST], flavor="doc")
|
||||
|
||||
|
||||
@mock.patch("mozperftest.MachEnvironment", new=_TestMachEnvironment)
|
||||
@mock.patch("mozbuild.base.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("mozperftest.mach_commands.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("mozperftest.utils.run_script")
|
||||
def test_test_runner(*mocked):
|
||||
from mozperftest.mach_commands import run_tests
|
||||
|
||||
with running_on_try(False), _get_command(run_tests) as (cmd, command_context):
|
||||
cmd(command_context, tests=[EXAMPLE_TEST], verbose=True)
|
||||
with running_on_try(False), _get_command(PerftestTests) as test:
|
||||
test.run_tests(test, tests=[EXAMPLE_TEST], verbose=True)
|
||||
|
||||
|
||||
@mock.patch("mozperftest.MachEnvironment", new=_TestMachEnvironment)
|
||||
@mock.patch("mozbuild.base.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("mozperftest.mach_commands.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("mozperftest.utils.run_python_script")
|
||||
def test_test_runner_on_try(*mocked):
|
||||
from mozperftest.mach_commands import run_tests
|
||||
|
||||
# simulating on try to run the paths parser
|
||||
with running_on_try(), _get_command(run_tests) as (cmd, command_context):
|
||||
cmd(command_context, tests=[EXAMPLE_TEST])
|
||||
with running_on_try(), _get_command(PerftestTests) as test:
|
||||
test.run_tests(test, tests=[EXAMPLE_TEST])
|
||||
|
||||
|
||||
@mock.patch("mozperftest.MachEnvironment", new=_TestMachEnvironment)
|
||||
@mock.patch("mozbuild.base.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("mozperftest.mach_commands.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("mozperftest.utils.run_script")
|
||||
def test_test_runner_coverage(*mocked):
|
||||
from mozperftest.mach_commands import run_tests
|
||||
|
||||
# simulating with coverage not installed
|
||||
with running_on_try(False), _get_command(run_tests) as (cmd, command_context):
|
||||
with running_on_try(False), _get_command(PerftestTests) as test:
|
||||
old = list(sys.meta_path)
|
||||
sys.meta_path = []
|
||||
try:
|
||||
cmd(command_context, tests=[EXAMPLE_TEST])
|
||||
test.run_tests(test, tests=[EXAMPLE_TEST])
|
||||
finally:
|
||||
sys.meta_path = old
|
||||
|
||||
@@ -233,24 +223,21 @@ def resolve_tests(tests=None):
|
||||
|
||||
|
||||
@mock.patch("mozperftest.MachEnvironment", new=_TestMachEnvironment)
|
||||
@mock.patch("mozbuild.base.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("mozperftest.mach_commands.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("mozperftest.fzf.fzf.select", new=fzf_selection)
|
||||
@mock.patch("moztest.resolve.TestResolver.resolve_tests", new=resolve_tests())
|
||||
def test_fzf_flavor(*mocked):
|
||||
with running_on_try(False), _get_command() as (
|
||||
cmd,
|
||||
command_context,
|
||||
): # , silence():
|
||||
cmd(command_context, flavor="desktop-browser")
|
||||
with running_on_try(False), _get_command() as test: # , silence():
|
||||
test.run_perftest(test, flavor="desktop-browser")
|
||||
|
||||
|
||||
@mock.patch("mozperftest.MachEnvironment", new=_TestMachEnvironment)
|
||||
@mock.patch("mozbuild.base.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("mozperftest.mach_commands.MachCommandBase.activate_virtualenv")
|
||||
@mock.patch("mozperftest.fzf.fzf.select", new=fzf_selection)
|
||||
@mock.patch("moztest.resolve.TestResolver.resolve_tests", new=resolve_tests([]))
|
||||
def test_fzf_nothing_selected(*mocked):
|
||||
with running_on_try(False), _get_command() as (cmd, command_context), silence():
|
||||
cmd(command_context, flavor="desktop-browser")
|
||||
with running_on_try(False), _get_command() as test, silence():
|
||||
test.run_perftest(test, flavor="desktop-browser")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -10,22 +10,24 @@ from __future__ import absolute_import, print_function, unicode_literals
|
||||
import sys
|
||||
import logging
|
||||
|
||||
from mach.decorators import CommandArgument, Command, SubCommand
|
||||
from mach.decorators import CommandArgument, CommandProvider, Command, SubCommand
|
||||
|
||||
from mozbuild.base import MachCommandBase
|
||||
from mozilla_version.gecko import GeckoVersion
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command(
|
||||
"release",
|
||||
category="release",
|
||||
description="Task that are part of the release process.",
|
||||
)
|
||||
def release(command_context):
|
||||
def release(self, command_context):
|
||||
"""
|
||||
The release subcommands all relate to the release process.
|
||||
"""
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"release",
|
||||
"buglist",
|
||||
@@ -40,8 +42,8 @@ def release(command_context):
|
||||
@CommandArgument("--product", required=True, help="The product being built.")
|
||||
@CommandArgument("--repo", help="The repo being built.")
|
||||
@CommandArgument("--revision", required=True, help="The revision being built.")
|
||||
def buglist(command_context, version, product, revision, repo):
|
||||
setup_logging(command_context)
|
||||
def buglist(self, command_context, version, product, revision, repo):
|
||||
self.setup_logging(command_context)
|
||||
from mozrelease.buglist_creator import create_bugs_url
|
||||
|
||||
print(
|
||||
@@ -53,7 +55,6 @@ def buglist(command_context, version, product, revision, repo):
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"release",
|
||||
"send-buglist-email",
|
||||
@@ -78,13 +79,12 @@ def buglist(command_context, version, product, revision, repo):
|
||||
@CommandArgument("--revision", required=True, help="The revision being built.")
|
||||
@CommandArgument("--build-number", required=True, help="The build number")
|
||||
@CommandArgument("--task-group-id", help="The task group of the build.")
|
||||
def buglist_email(command_context, **options):
|
||||
setup_logging(command_context)
|
||||
def buglist_email(self, command_context, **options):
|
||||
self.setup_logging(command_context)
|
||||
from mozrelease.buglist_creator import email_release_drivers
|
||||
|
||||
email_release_drivers(**options)
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"release",
|
||||
"push-scriptworker-canary",
|
||||
@@ -110,8 +110,10 @@ def buglist_email(command_context, **options):
|
||||
required=False,
|
||||
help="Taskcluster secret with ssh-key to use for hg.mozilla.org",
|
||||
)
|
||||
def push_scriptworker_canary(command_context, scriptworkers, addresses, ssh_key_secret):
|
||||
setup_logging(command_context)
|
||||
def push_scriptworker_canary(
|
||||
self, command_context, scriptworkers, addresses, ssh_key_secret
|
||||
):
|
||||
self.setup_logging(command_context)
|
||||
from mozrelease.scriptworker_canary import push_canary
|
||||
|
||||
push_canary(
|
||||
@@ -120,8 +122,7 @@ def push_scriptworker_canary(command_context, scriptworkers, addresses, ssh_key_
|
||||
ssh_key_secret=ssh_key_secret,
|
||||
)
|
||||
|
||||
|
||||
def setup_logging(command_context, quiet=False, verbose=True):
|
||||
def setup_logging(self, command_context, quiet=False, verbose=True):
|
||||
"""
|
||||
Set up Python logging for all loggers, sending results to stderr (so
|
||||
that command output can be redirected easily) and adding the typical
|
||||
|
||||
@@ -24,10 +24,12 @@ from six import iteritems
|
||||
from mach.decorators import (
|
||||
Command,
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
SubCommand,
|
||||
)
|
||||
|
||||
from mozbuild.base import (
|
||||
MachCommandBase,
|
||||
MozbuildObject,
|
||||
BinaryNotFoundException,
|
||||
)
|
||||
@@ -50,17 +52,19 @@ def setup():
|
||||
os.environ["PATH"] = "{}:{}".format(path, os.environ["PATH"])
|
||||
|
||||
|
||||
def remotedir(command_context):
|
||||
@CommandProvider
|
||||
class RemoteCommands(MachCommandBase):
|
||||
def remotedir(self, command_context):
|
||||
return os.path.join(command_context.topsrcdir, "remote")
|
||||
|
||||
|
||||
@Command("remote", category="misc", description="Remote protocol related operations.")
|
||||
def remote(command_context):
|
||||
@Command(
|
||||
"remote", category="misc", description="Remote protocol related operations."
|
||||
)
|
||||
def remote(self, command_context):
|
||||
"""The remote subcommands all relate to the remote protocol."""
|
||||
command_context._sub_mach(["help", "remote"])
|
||||
return 1
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"remote", "vendor-puppeteer", "Pull in latest changes of the Puppeteer client."
|
||||
)
|
||||
@@ -83,13 +87,15 @@ def remote(command_context):
|
||||
default=True,
|
||||
help="Do not install the just-pulled Puppeteer package,",
|
||||
)
|
||||
def vendor_puppeteer(command_context, repository, commitish, install):
|
||||
puppeteer_dir = os.path.join(remotedir(command_context), "test", "puppeteer")
|
||||
def vendor_puppeteer(self, command_context, repository, commitish, install):
|
||||
puppeteer_dir = os.path.join(
|
||||
self.remotedir(command_context), "test", "puppeteer"
|
||||
)
|
||||
|
||||
# Preserve our custom mocha reporter
|
||||
shutil.move(
|
||||
os.path.join(puppeteer_dir, "json-mocha-reporter.js"),
|
||||
remotedir(command_context),
|
||||
self.remotedir(command_context),
|
||||
)
|
||||
shutil.rmtree(puppeteer_dir, ignore_errors=True)
|
||||
os.makedirs(puppeteer_dir)
|
||||
@@ -120,7 +126,7 @@ def vendor_puppeteer(command_context, repository, commitish, install):
|
||||
shutil.rmtree(dir_path)
|
||||
|
||||
shutil.move(
|
||||
os.path.join(remotedir(command_context), "json-mocha-reporter.js"),
|
||||
os.path.join(self.remotedir(command_context), "json-mocha-reporter.js"),
|
||||
puppeteer_dir,
|
||||
)
|
||||
|
||||
@@ -578,6 +584,8 @@ def create_parser_puppeteer():
|
||||
return p
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class PuppeteerTest(MachCommandBase):
|
||||
@Command(
|
||||
"puppeteer-test",
|
||||
category="testing",
|
||||
@@ -585,6 +593,7 @@ def create_parser_puppeteer():
|
||||
parser=create_parser_puppeteer,
|
||||
)
|
||||
def puppeteer_test(
|
||||
self,
|
||||
command_context,
|
||||
binary=None,
|
||||
ci=False,
|
||||
@@ -645,7 +654,7 @@ def puppeteer_test(
|
||||
if verbosity > 2:
|
||||
prefs["remote.log.truncate"] = False
|
||||
|
||||
install_puppeteer(command_context, product, ci)
|
||||
self.install_puppeteer(command_context, product, ci)
|
||||
|
||||
params = {
|
||||
"binary": binary,
|
||||
@@ -667,8 +676,7 @@ def puppeteer_test(
|
||||
except Exception as e:
|
||||
exit(EX_SOFTWARE, e)
|
||||
|
||||
|
||||
def install_puppeteer(command_context, product, ci):
|
||||
def install_puppeteer(self, command_context, product, ci):
|
||||
setup()
|
||||
env = {}
|
||||
from mozversioncontrol import get_repository_object
|
||||
@@ -689,7 +697,9 @@ def install_puppeteer(command_context, product, ci):
|
||||
shutil.rmtree(lib_dir)
|
||||
|
||||
command = "ci" if ci else "install"
|
||||
npm(command, cwd=os.path.join(command_context.topsrcdir, puppeteer_dir), env=env)
|
||||
npm(
|
||||
command, cwd=os.path.join(command_context.topsrcdir, puppeteer_dir), env=env
|
||||
)
|
||||
|
||||
|
||||
def exit(code, error=None):
|
||||
|
||||
@@ -6,12 +6,14 @@ import os
|
||||
import sys
|
||||
|
||||
from mach.util import UserError
|
||||
from mozbuild.base import MachCommandBase
|
||||
from mozpack.files import FileFinder
|
||||
from mozpack.path import basedir
|
||||
|
||||
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
|
||||
@@ -62,6 +64,8 @@ def is_excluded_directory(directory, exclusions):
|
||||
return False
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command(
|
||||
"generate-test-certs",
|
||||
category="devenv",
|
||||
@@ -72,7 +76,7 @@ def is_excluded_directory(directory, exclusions):
|
||||
nargs="*",
|
||||
help="Specification files for test certs. If omitted, all certs are regenerated.",
|
||||
)
|
||||
def generate_test_certs(command_context, specifications):
|
||||
def generate_test_certs(self, command_context, specifications):
|
||||
"""Generate test certificates and keys from specifications."""
|
||||
|
||||
command_context.activate_virtualenv()
|
||||
@@ -80,7 +84,7 @@ def generate_test_certs(command_context, specifications):
|
||||
import pykey
|
||||
|
||||
if not specifications:
|
||||
specifications = find_all_specifications(command_context)
|
||||
specifications = self.find_all_specifications(command_context)
|
||||
|
||||
for specification in specifications:
|
||||
if is_certspec_file(specification):
|
||||
@@ -94,8 +98,7 @@ def generate_test_certs(command_context, specifications):
|
||||
run_module_main_on(module, os.path.abspath(specification))
|
||||
return 0
|
||||
|
||||
|
||||
def find_all_specifications(command_context):
|
||||
def find_all_specifications(self, command_context):
|
||||
"""Searches the source tree for all specification files
|
||||
and returns them as a list."""
|
||||
specifications = []
|
||||
|
||||
@@ -18,9 +18,11 @@ from functools import partial
|
||||
from mach.decorators import (
|
||||
Command,
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
SettingsProvider,
|
||||
SubCommand,
|
||||
)
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
import taskgraph.main
|
||||
from taskgraph.main import commands as taskgraph_commands
|
||||
@@ -143,28 +145,28 @@ def get_taskgraph_decision_parser():
|
||||
return parser
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command(
|
||||
"taskgraph",
|
||||
category="ci",
|
||||
description="Manipulate TaskCluster task graphs defined in-tree",
|
||||
)
|
||||
def taskgraph_command(command_context):
|
||||
def taskgraph(self, command_context):
|
||||
"""The taskgraph subcommands all relate to the generation of task graphs
|
||||
for Gecko continuous integration. A task graph is a set of tasks linked
|
||||
by dependencies: for example, a binary must be built before it is tested,
|
||||
and that build may further depend on various toolchains, libraries, etc.
|
||||
"""
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"taskgraph",
|
||||
"tasks",
|
||||
description="Show all tasks in the taskgraph",
|
||||
parser=partial(get_taskgraph_command_parser, "tasks"),
|
||||
)
|
||||
def taskgraph_tasks(command_context, **options):
|
||||
return run_show_taskgraph(command_context, **options)
|
||||
|
||||
def taskgraph_tasks(self, command_context, **options):
|
||||
return self.run_show_taskgraph(command_context, **options)
|
||||
|
||||
@SubCommand(
|
||||
"taskgraph",
|
||||
@@ -172,9 +174,8 @@ def taskgraph_tasks(command_context, **options):
|
||||
description="Show the full taskgraph",
|
||||
parser=partial(get_taskgraph_command_parser, "full"),
|
||||
)
|
||||
def taskgraph_full(command_context, **options):
|
||||
return run_show_taskgraph(command_context, **options)
|
||||
|
||||
def taskgraph_full(self, command_context, **options):
|
||||
return self.run_show_taskgraph(command_context, **options)
|
||||
|
||||
@SubCommand(
|
||||
"taskgraph",
|
||||
@@ -182,9 +183,8 @@ def taskgraph_full(command_context, **options):
|
||||
description="Show the target task set",
|
||||
parser=partial(get_taskgraph_command_parser, "target"),
|
||||
)
|
||||
def taskgraph_target(command_context, **options):
|
||||
return run_show_taskgraph(command_context, **options)
|
||||
|
||||
def taskgraph_target(self, command_context, **options):
|
||||
return self.run_show_taskgraph(command_context, **options)
|
||||
|
||||
@SubCommand(
|
||||
"taskgraph",
|
||||
@@ -192,9 +192,8 @@ def taskgraph_target(command_context, **options):
|
||||
description="Show the target taskgraph",
|
||||
parser=partial(get_taskgraph_command_parser, "target-graph"),
|
||||
)
|
||||
def taskgraph_target_graph(command_context, **options):
|
||||
return run_show_taskgraph(command_context, **options)
|
||||
|
||||
def taskgraph_target_graph(self, command_context, **options):
|
||||
return self.run_show_taskgraph(command_context, **options)
|
||||
|
||||
@SubCommand(
|
||||
"taskgraph",
|
||||
@@ -202,9 +201,8 @@ def taskgraph_target_graph(command_context, **options):
|
||||
description="Show the optimized taskgraph",
|
||||
parser=partial(get_taskgraph_command_parser, "optimized"),
|
||||
)
|
||||
def taskgraph_optimized(command_context, **options):
|
||||
return run_show_taskgraph(command_context, **options)
|
||||
|
||||
def taskgraph_optimized(self, command_context, **options):
|
||||
return self.run_show_taskgraph(command_context, **options)
|
||||
|
||||
@SubCommand(
|
||||
"taskgraph",
|
||||
@@ -212,17 +210,16 @@ def taskgraph_optimized(command_context, **options):
|
||||
description="Show the morphed taskgraph",
|
||||
parser=partial(get_taskgraph_command_parser, "morphed"),
|
||||
)
|
||||
def taskgraph_morphed(command_context, **options):
|
||||
return run_show_taskgraph(command_context, **options)
|
||||
def taskgraph_morphed(self, command_context, **options):
|
||||
return self.run_show_taskgraph(command_context, **options)
|
||||
|
||||
|
||||
def run_show_taskgraph(command_context, **options):
|
||||
def run_show_taskgraph(self, command_context, **options):
|
||||
# There are cases where we don't want to set up mach logging (e.g logs
|
||||
# are being redirected to disk). By monkeypatching the 'setup_logging'
|
||||
# function we can let 'taskgraph.main' decide whether or not to log to
|
||||
# the terminal.
|
||||
taskgraph.main.setup_logging = partial(
|
||||
setup_logging,
|
||||
self.setup_logging,
|
||||
command_context,
|
||||
quiet=options["quiet"],
|
||||
verbose=options["verbose"],
|
||||
@@ -230,7 +227,6 @@ def run_show_taskgraph(command_context, **options):
|
||||
show_taskgraph = options.pop("func")
|
||||
return show_taskgraph(options)
|
||||
|
||||
|
||||
@SubCommand("taskgraph", "actions", description="Write actions.json to stdout")
|
||||
@CommandArgument(
|
||||
"--root", "-r", help="root of the taskgraph definition relative to topsrcdir"
|
||||
@@ -248,11 +244,11 @@ def run_show_taskgraph(command_context, **options):
|
||||
"--parameters",
|
||||
"-p",
|
||||
default="project=mozilla-central",
|
||||
help="parameters file (.yml or .json; see `taskcluster/docs/parameters.rst`)`",
|
||||
help="parameters file (.yml or .json; see "
|
||||
"`taskcluster/docs/parameters.rst`)`",
|
||||
)
|
||||
def taskgraph_actions(command_context, **options):
|
||||
return show_actions(command_context, options)
|
||||
|
||||
def taskgraph_actions(self, command_context, **options):
|
||||
return self.show_actions(command_context, options)
|
||||
|
||||
@SubCommand(
|
||||
"taskgraph",
|
||||
@@ -260,14 +256,14 @@ def taskgraph_actions(command_context, **options):
|
||||
description="Run the decision task",
|
||||
parser=get_taskgraph_decision_parser,
|
||||
)
|
||||
def taskgraph_decision(command_context, **options):
|
||||
def taskgraph_decision(self, command_context, **options):
|
||||
"""Run the decision task: generate a task graph and submit to
|
||||
TaskCluster. This is only meant to be called within decision tasks,
|
||||
and requires a great many arguments. Commands like `mach taskgraph
|
||||
optimized` are better suited to use on the command line, and can take
|
||||
the parameters file generated by a decision task."""
|
||||
try:
|
||||
setup_logging(command_context)
|
||||
self.setup_logging(command_context)
|
||||
start = time.monotonic()
|
||||
ret = taskgraph_commands["decision"].func(options)
|
||||
end = time.monotonic()
|
||||
@@ -293,47 +289,43 @@ def taskgraph_decision(command_context, **options):
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"taskgraph",
|
||||
"cron",
|
||||
description="Provide a pointer to the new `.cron.yml` handler.",
|
||||
)
|
||||
def taskgraph_cron(command_context, **options):
|
||||
def taskgraph_cron(self, command_context, **options):
|
||||
print(
|
||||
'Handling of ".cron.yml" files has move to '
|
||||
"https://hg.mozilla.org/ci/ci-admin/file/default/build-decision."
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"taskgraph",
|
||||
"action-callback",
|
||||
description="Run action callback used by action tasks",
|
||||
parser=partial(get_taskgraph_command_parser, "action-callback"),
|
||||
)
|
||||
def action_callback(command_context, **options):
|
||||
setup_logging(command_context)
|
||||
def action_callback(self, command_context, **options):
|
||||
self.setup_logging(command_context)
|
||||
taskgraph_commands["action-callback"].func(options)
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"taskgraph",
|
||||
"test-action-callback",
|
||||
description="Run an action callback in a testing mode",
|
||||
parser=partial(get_taskgraph_command_parser, "test-action-callback"),
|
||||
)
|
||||
def test_action_callback(command_context, **options):
|
||||
setup_logging(command_context)
|
||||
def test_action_callback(self, command_context, **options):
|
||||
self.setup_logging(command_context)
|
||||
|
||||
if not options["parameters"]:
|
||||
options["parameters"] = "project=mozilla-central"
|
||||
|
||||
taskgraph_commands["test-action-callback"].func(options)
|
||||
|
||||
|
||||
def setup_logging(command_context, quiet=False, verbose=True):
|
||||
def setup_logging(self, command_context, quiet=False, verbose=True):
|
||||
"""
|
||||
Set up Python logging for all loggers, sending results to stderr (so
|
||||
that command output can be redirected easily) and adding the typical
|
||||
@@ -355,15 +347,14 @@ def setup_logging(command_context, quiet=False, verbose=True):
|
||||
# all of the taskgraph logging is unstructured logging
|
||||
command_context.log_manager.enable_unstructured()
|
||||
|
||||
|
||||
def show_actions(command_context, options):
|
||||
def show_actions(self, command_context, options):
|
||||
import taskgraph
|
||||
import taskgraph.actions
|
||||
import taskgraph.generator
|
||||
import taskgraph.parameters
|
||||
|
||||
try:
|
||||
setup_logging(
|
||||
self.setup_logging(
|
||||
command_context, quiet=options["quiet"], verbose=options["verbose"]
|
||||
)
|
||||
parameters = taskgraph.parameters.parameters_loader(options["parameters"])
|
||||
@@ -384,6 +375,8 @@ def show_actions(command_context, options):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class TaskClusterImagesProvider(MachCommandBase):
|
||||
@Command(
|
||||
"taskcluster-load-image",
|
||||
category="ci",
|
||||
@@ -391,24 +384,22 @@ def show_actions(command_context, options):
|
||||
"have docker installed and running for this to work.",
|
||||
parser=partial(get_taskgraph_command_parser, "load-image"),
|
||||
)
|
||||
def load_image(command_context, **kwargs):
|
||||
def load_image(self, command_context, **kwargs):
|
||||
taskgraph_commands["load-image"].func(kwargs)
|
||||
|
||||
|
||||
@Command(
|
||||
"taskcluster-build-image",
|
||||
category="ci",
|
||||
description="Build a Docker image",
|
||||
parser=partial(get_taskgraph_command_parser, "build-image"),
|
||||
)
|
||||
def build_image(command_context, **kwargs):
|
||||
def build_image(self, command_context, **kwargs):
|
||||
try:
|
||||
taskgraph_commands["build-image"].func(kwargs)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@Command(
|
||||
"taskcluster-image-digest",
|
||||
category="ci",
|
||||
@@ -416,10 +407,12 @@ def build_image(command_context, **kwargs):
|
||||
"current contents of the tree.",
|
||||
parser=partial(get_taskgraph_command_parser, "build-image"),
|
||||
)
|
||||
def image_digest(command_context, **kwargs):
|
||||
def image_digest(self, command_context, **kwargs):
|
||||
taskgraph_commands["image-digest"].func(kwargs)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class TaskClusterPartialsData(MachCommandBase):
|
||||
@Command(
|
||||
"release-history",
|
||||
category="ci",
|
||||
@@ -434,13 +427,15 @@ def image_digest(command_context, **kwargs):
|
||||
@CommandArgument(
|
||||
"--product", default="Firefox", help="The product identifier, such as 'Firefox'"
|
||||
)
|
||||
def generate_partials_builds(command_context, product, branch):
|
||||
def generate_partials_builds(self, command_context, product, branch):
|
||||
from taskgraph.util.partials import populate_release_history
|
||||
|
||||
try:
|
||||
import yaml
|
||||
|
||||
release_history = {"release_history": populate_release_history(product, branch)}
|
||||
release_history = {
|
||||
"release_history": populate_release_history(product, branch)
|
||||
}
|
||||
print(
|
||||
yaml.safe_dump(
|
||||
release_history, allow_unicode=True, default_flow_style=False
|
||||
|
||||
@@ -12,6 +12,7 @@ import sys
|
||||
import six
|
||||
|
||||
from mozbuild.base import (
|
||||
MachCommandBase,
|
||||
MachCommandConditions as conditions,
|
||||
BinaryNotFoundException,
|
||||
)
|
||||
@@ -19,6 +20,7 @@ from mozbuild.base import (
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandArgumentGroup,
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
|
||||
@@ -35,13 +37,14 @@ def setup_awsy_argument_parser():
|
||||
return parser
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
AWSY_PATH = os.path.dirname(os.path.realpath(__file__))
|
||||
if AWSY_PATH not in sys.path:
|
||||
sys.path.append(AWSY_PATH)
|
||||
from awsy import ITERATIONS, PER_TAB_PAUSE, SETTLE_WAIT_TIME, MAX_TABS
|
||||
|
||||
|
||||
def run_awsy(command_context, tests, binary=None, **kwargs):
|
||||
def run_awsy(self, command_context, tests, binary=None, **kwargs):
|
||||
import json
|
||||
from mozlog.structured import commandline
|
||||
|
||||
@@ -132,7 +135,9 @@ def run_awsy(command_context, tests, binary=None, **kwargs):
|
||||
tp5nzip = os.path.join(page_load_test_dir, "tp5n.zip")
|
||||
tp5nmanifest = os.path.join(page_load_test_dir, "tp5n", "tp5n.manifest")
|
||||
if not os.path.exists(tp5nmanifest):
|
||||
unzip_args = {"args": ["unzip", "-q", "-o", tp5nzip, "-d", page_load_test_dir]}
|
||||
unzip_args = {
|
||||
"args": ["unzip", "-q", "-o", tp5nzip, "-d", page_load_test_dir]
|
||||
}
|
||||
try:
|
||||
command_context.run_process(**unzip_args)
|
||||
except Exception as exc:
|
||||
@@ -154,7 +159,9 @@ def run_awsy(command_context, tests, binary=None, **kwargs):
|
||||
|
||||
# If '--preferences' was not specified supply our default set.
|
||||
if not kwargs["prefs_files"]:
|
||||
kwargs["prefs_files"] = [os.path.join(awsy_source_dir, "conf", "prefs.json")]
|
||||
kwargs["prefs_files"] = [
|
||||
os.path.join(awsy_source_dir, "conf", "prefs.json")
|
||||
]
|
||||
|
||||
# Setup DMD env vars if necessary.
|
||||
if kwargs["dmd"]:
|
||||
@@ -196,7 +203,6 @@ def run_awsy(command_context, tests, binary=None, **kwargs):
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
@Command(
|
||||
"awsy-test",
|
||||
category="testing",
|
||||
@@ -249,7 +255,7 @@ def run_awsy(command_context, tests, binary=None, **kwargs):
|
||||
action="store",
|
||||
type=int,
|
||||
dest="entities",
|
||||
help="Number of urls to load. Defaults to the total number of urls.",
|
||||
help="Number of urls to load. Defaults to the total number of " "urls.",
|
||||
)
|
||||
@CommandArgument(
|
||||
"--max-tabs",
|
||||
@@ -257,7 +263,7 @@ def run_awsy(command_context, tests, binary=None, **kwargs):
|
||||
action="store",
|
||||
type=int,
|
||||
dest="maxTabs",
|
||||
help="Maximum number of tabs to open. Defaults to %s." % MAX_TABS,
|
||||
help="Maximum number of tabs to open. " "Defaults to %s." % MAX_TABS,
|
||||
)
|
||||
@CommandArgument(
|
||||
"--iterations",
|
||||
@@ -274,7 +280,8 @@ def run_awsy(command_context, tests, binary=None, **kwargs):
|
||||
action="store",
|
||||
type=int,
|
||||
dest="perTabPause",
|
||||
help="Seconds to wait in between opening tabs. Defaults to %s." % PER_TAB_PAUSE,
|
||||
help="Seconds to wait in between opening tabs. "
|
||||
"Defaults to %s." % PER_TAB_PAUSE,
|
||||
)
|
||||
@CommandArgument(
|
||||
"--settle-wait-time",
|
||||
@@ -301,7 +308,7 @@ def run_awsy(command_context, tests, binary=None, **kwargs):
|
||||
default=False,
|
||||
help="Use the tp6 pageset during testing.",
|
||||
)
|
||||
def run_awsy_test(command_context, tests, **kwargs):
|
||||
def run_awsy_test(self, command_context, tests, **kwargs):
|
||||
"""mach awsy-test runs the in-tree version of the Are We Slim Yet
|
||||
(AWSY) tests.
|
||||
|
||||
@@ -347,4 +354,4 @@ def run_awsy_test(command_context, tests, **kwargs):
|
||||
)
|
||||
command_context.log(logging.INFO, "awsy", {"help": e.help()}, "{help}")
|
||||
return 1
|
||||
return run_awsy(command_context, tests, **kwargs)
|
||||
return self.run_awsy(command_context, tests, **kwargs)
|
||||
|
||||
@@ -7,19 +7,20 @@ import sys
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
from mach.decorators import CommandArgument, Command
|
||||
from mozbuild.base import BinaryNotFoundException
|
||||
from mach.decorators import CommandArgument, CommandProvider, Command
|
||||
from mozbuild.base import MachCommandBase, BinaryNotFoundException
|
||||
|
||||
requirements = os.path.join(os.path.dirname(__file__), "requirements", "base.txt")
|
||||
|
||||
|
||||
def _init(command_context):
|
||||
@CommandProvider
|
||||
class CondprofileCommandProvider(MachCommandBase):
|
||||
def _init(self, command_context):
|
||||
command_context.activate_virtualenv()
|
||||
command_context.virtualenv_manager.install_pip_requirements(
|
||||
requirements, require_hashes=False
|
||||
)
|
||||
|
||||
|
||||
@Command("fetch-condprofile", category="testing")
|
||||
@CommandArgument("--target-dir", default=None, help="Target directory")
|
||||
@CommandArgument("--platform", default=None, help="Platform")
|
||||
@@ -34,6 +35,7 @@ def _init(command_context):
|
||||
help="Repository",
|
||||
)
|
||||
def fetch(
|
||||
self,
|
||||
command_context,
|
||||
target_dir,
|
||||
platform,
|
||||
@@ -43,7 +45,7 @@ def fetch(
|
||||
download_cache,
|
||||
repo,
|
||||
):
|
||||
_init(command_context)
|
||||
self._init(command_context)
|
||||
from condprof.client import get_profile
|
||||
from condprof.util import get_current_platform
|
||||
|
||||
@@ -57,7 +59,6 @@ def fetch(
|
||||
target_dir, platform, scenario, customization, task_id, download_cache, repo
|
||||
)
|
||||
|
||||
|
||||
@Command("run-condprofile", category="testing")
|
||||
@CommandArgument("archive", help="Archives Dir", type=str, default=None)
|
||||
@CommandArgument("--firefox", help="Firefox Binary", type=str, default=None)
|
||||
@@ -88,9 +89,9 @@ def fetch(
|
||||
default=sys.platform.startswith("win") and "geckodriver.exe" or "geckodriver",
|
||||
)
|
||||
@CommandArgument("--device-name", help="Name of the device", type=str, default=None)
|
||||
def run(command_context, **kw):
|
||||
def run(self, command_context, **kw):
|
||||
os.environ["MANUAL_MACH_RUN"] = "1"
|
||||
_init(command_context)
|
||||
self._init(command_context)
|
||||
|
||||
if kw["firefox"] is None:
|
||||
try:
|
||||
|
||||
@@ -10,12 +10,14 @@ import os
|
||||
import sys
|
||||
|
||||
from mozbuild.base import (
|
||||
MachCommandBase,
|
||||
MachCommandConditions as conditions,
|
||||
BinaryNotFoundException,
|
||||
)
|
||||
|
||||
from mach.decorators import (
|
||||
Command,
|
||||
CommandProvider,
|
||||
)
|
||||
|
||||
|
||||
@@ -85,6 +87,8 @@ def run_firefox_ui_test(testtype=None, topsrcdir=None, **kwargs):
|
||||
return 0
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command(
|
||||
"firefox-ui-functional",
|
||||
category="testing",
|
||||
@@ -92,9 +96,11 @@ def run_firefox_ui_test(testtype=None, topsrcdir=None, **kwargs):
|
||||
description="Run the functional test suite of Firefox UI tests.",
|
||||
parser=setup_argument_parser_functional,
|
||||
)
|
||||
def run_firefox_ui_functional(command_context, **kwargs):
|
||||
def run_firefox_ui_functional(self, command_context, **kwargs):
|
||||
try:
|
||||
kwargs["binary"] = kwargs["binary"] or command_context.get_binary_path("app")
|
||||
kwargs["binary"] = kwargs["binary"] or command_context.get_binary_path(
|
||||
"app"
|
||||
)
|
||||
except BinaryNotFoundException as e:
|
||||
command_context.log(
|
||||
logging.ERROR,
|
||||
|
||||
@@ -11,11 +11,14 @@ from mach.decorators import (
|
||||
Command,
|
||||
CommandArgument,
|
||||
CommandArgumentGroup,
|
||||
CommandProvider,
|
||||
)
|
||||
|
||||
from mozbuild.base import BinaryNotFoundException
|
||||
from mozbuild.base import MachCommandBase, BinaryNotFoundException
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class GeckoDriver(MachCommandBase):
|
||||
@Command(
|
||||
"geckodriver",
|
||||
category="post-build",
|
||||
@@ -49,9 +52,10 @@ from mozbuild.base import BinaryNotFoundException
|
||||
metavar="params",
|
||||
type=str,
|
||||
group="debugging",
|
||||
help="Flags to pass to the debugger itself; split as the Bourne shell would.",
|
||||
help="Flags to pass to the debugger itself; "
|
||||
"split as the Bourne shell would.",
|
||||
)
|
||||
def run(command_context, binary, params, debug, debugger, debugger_args):
|
||||
def run(self, command_context, binary, params, debug, debugger, debugger_args):
|
||||
try:
|
||||
binpath = command_context.get_binary_path("geckodriver")
|
||||
except BinaryNotFoundException as e:
|
||||
|
||||
@@ -9,8 +9,10 @@ import sys
|
||||
from argparse import Namespace
|
||||
|
||||
from mach.decorators import (
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
parser = None
|
||||
@@ -117,13 +119,15 @@ def setup_argument_parser():
|
||||
return parser
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class GtestCommands(MachCommandBase):
|
||||
@Command(
|
||||
"gtest",
|
||||
category="testing",
|
||||
description="Run the gtest harness.",
|
||||
parser=setup_argument_parser,
|
||||
)
|
||||
def gtest(command_context, **kwargs):
|
||||
def gtest(self, command_context, **kwargs):
|
||||
command_context._mach_context.activate_mozharness_venv()
|
||||
result = run_gtest(command_context._mach_context, **kwargs)
|
||||
return 0 if result else 1
|
||||
|
||||
@@ -12,6 +12,7 @@ import subprocess
|
||||
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
Command,
|
||||
SettingsProvider,
|
||||
SubCommand,
|
||||
@@ -19,6 +20,7 @@ from mach.decorators import (
|
||||
|
||||
from mozbuild.base import (
|
||||
BuildEnvironmentNotFoundException,
|
||||
MachCommandBase,
|
||||
MachCommandConditions as conditions,
|
||||
)
|
||||
|
||||
@@ -158,6 +160,8 @@ def create_parser_addtest():
|
||||
return parser
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class AddTest(MachCommandBase):
|
||||
@Command(
|
||||
"addtest",
|
||||
category="testing",
|
||||
@@ -165,6 +169,7 @@ def create_parser_addtest():
|
||||
parser=create_parser_addtest,
|
||||
)
|
||||
def addtest(
|
||||
self,
|
||||
command_context,
|
||||
suite=None,
|
||||
test=None,
|
||||
@@ -190,9 +195,9 @@ def addtest(
|
||||
|
||||
abs_test = os.path.abspath(test)
|
||||
if doc is None:
|
||||
doc = guess_doc(abs_test)
|
||||
doc = self.guess_doc(abs_test)
|
||||
if suite is None:
|
||||
guessed_suite, err = guess_suite(abs_test)
|
||||
guessed_suite, err = self.guess_suite(abs_test)
|
||||
if err:
|
||||
print(err)
|
||||
return 1
|
||||
@@ -292,13 +297,11 @@ def addtest(
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def guess_doc(abs_test):
|
||||
def guess_doc(self, abs_test):
|
||||
filename = os.path.basename(abs_test)
|
||||
return os.path.splitext(filename)[1].strip(".")
|
||||
|
||||
|
||||
def guess_suite(abs_test):
|
||||
def guess_suite(self, abs_test):
|
||||
# If you pass a abs_test, try to detect the type based on the name
|
||||
# and folder. This detection can be skipped if you pass the `type` arg.
|
||||
err = None
|
||||
@@ -322,7 +325,7 @@ def guess_suite(abs_test):
|
||||
elif (
|
||||
filename.startswith("test_")
|
||||
and has_xpcshell_ini
|
||||
and guess_doc(abs_test) == "js"
|
||||
and self.guess_doc(abs_test) == "js"
|
||||
):
|
||||
guessed_suite = "xpcshell"
|
||||
else:
|
||||
@@ -341,13 +344,15 @@ def guess_suite(abs_test):
|
||||
return guessed_suite, err
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class Test(MachCommandBase):
|
||||
@Command(
|
||||
"test",
|
||||
category="testing",
|
||||
description="Run tests (detects the kind of test and runs it).",
|
||||
parser=get_test_parser,
|
||||
)
|
||||
def test(command_context, what, extra_args, **log_args):
|
||||
def test(self, command_context, what, extra_args, **log_args):
|
||||
"""Run tests from names or paths.
|
||||
|
||||
mach test accepts arguments specifying which tests to run. Each argument
|
||||
@@ -468,6 +473,8 @@ def test(command_context, what, extra_args, **log_args):
|
||||
return status
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command(
|
||||
"cppunittest", category="testing", description="Run cpp unit tests (C++ tests)."
|
||||
)
|
||||
@@ -486,7 +493,7 @@ def test(command_context, what, extra_args, **log_args):
|
||||
"directories, or omitted. If omitted, the entire test suite is "
|
||||
"executed.",
|
||||
)
|
||||
def run_cppunit_test(command_context, **params):
|
||||
def run_cppunit_test(self, command_context, **params):
|
||||
from mozlog import commandline
|
||||
|
||||
log = params.get("log")
|
||||
@@ -517,15 +524,14 @@ def run_cppunit_test(command_context, **params):
|
||||
)
|
||||
|
||||
verify_android_device(command_context, install=InstallIntent.NO)
|
||||
return run_android_test(tests, symbols_path, manifest_path, log)
|
||||
return self.run_android_test(tests, symbols_path, manifest_path, log)
|
||||
|
||||
return run_desktop_test(
|
||||
return self.run_desktop_test(
|
||||
command_context, tests, symbols_path, manifest_path, utility_path, log
|
||||
)
|
||||
|
||||
|
||||
def run_desktop_test(
|
||||
command_context, tests, symbols_path, manifest_path, utility_path, log
|
||||
self, command_context, tests, symbols_path, manifest_path, utility_path, log
|
||||
):
|
||||
import runcppunittests as cppunittests
|
||||
from mozlog import commandline
|
||||
@@ -548,8 +554,9 @@ def run_desktop_test(
|
||||
|
||||
return 0 if result else 1
|
||||
|
||||
|
||||
def run_android_test(command_context, tests, symbols_path, manifest_path, log):
|
||||
def run_android_test(
|
||||
self, command_context, tests, symbols_path, manifest_path, log
|
||||
):
|
||||
import remotecppunittests as remotecppunittests
|
||||
from mozlog import commandline
|
||||
|
||||
@@ -567,7 +574,9 @@ def run_android_test(command_context, tests, symbols_path, manifest_path, log):
|
||||
options.local_lib = command_context.bindir.replace("bin", "fennec")
|
||||
for file in os.listdir(os.path.join(command_context.topobjdir, "dist")):
|
||||
if file.endswith(".apk") and file.startswith("fennec"):
|
||||
options.local_apk = os.path.join(command_context.topobjdir, "dist", file)
|
||||
options.local_apk = os.path.join(
|
||||
command_context.topobjdir, "dist", file
|
||||
)
|
||||
log.info("using APK: " + options.local_apk)
|
||||
break
|
||||
|
||||
@@ -585,6 +594,8 @@ def executable_name(name):
|
||||
return name + ".exe" if sys.platform.startswith("win") else name
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class SpiderMonkeyTests(MachCommandBase):
|
||||
@Command(
|
||||
"jstests",
|
||||
category="testing",
|
||||
@@ -596,7 +607,7 @@ def executable_name(name):
|
||||
nargs=argparse.REMAINDER,
|
||||
help="Extra arguments to pass down to the test harness.",
|
||||
)
|
||||
def run_jstests(command_context, shell, params):
|
||||
def run_jstests(self, command_context, shell, params):
|
||||
import subprocess
|
||||
|
||||
command_context.virtualenv_manager.ensure()
|
||||
@@ -611,7 +622,6 @@ def run_jstests(command_context, shell, params):
|
||||
|
||||
return subprocess.call(jstest_cmd)
|
||||
|
||||
|
||||
@Command(
|
||||
"jit-test",
|
||||
category="testing",
|
||||
@@ -630,7 +640,7 @@ def run_jstests(command_context, shell, params):
|
||||
nargs=argparse.REMAINDER,
|
||||
help="Extra arguments to pass down to the test harness.",
|
||||
)
|
||||
def run_jittests(command_context, shell, cgc, params):
|
||||
def run_jittests(self, command_context, shell, cgc, params):
|
||||
import subprocess
|
||||
|
||||
command_context.virtualenv_manager.ensure()
|
||||
@@ -639,7 +649,9 @@ def run_jittests(command_context, shell, cgc, params):
|
||||
js = shell or os.path.join(command_context.bindir, executable_name("js"))
|
||||
jittest_cmd = [
|
||||
python,
|
||||
os.path.join(command_context.topsrcdir, "js", "src", "jit-test", "jit_test.py"),
|
||||
os.path.join(
|
||||
command_context.topsrcdir, "js", "src", "jit-test", "jit_test.py"
|
||||
),
|
||||
js,
|
||||
] + params
|
||||
|
||||
@@ -649,8 +661,9 @@ def run_jittests(command_context, shell, cgc, params):
|
||||
|
||||
return subprocess.call(jittest_cmd, env=env)
|
||||
|
||||
|
||||
@Command("jsapi-tests", category="testing", description="Run SpiderMonkey JSAPI tests.")
|
||||
@Command(
|
||||
"jsapi-tests", category="testing", description="Run SpiderMonkey JSAPI tests."
|
||||
)
|
||||
@CommandArgument(
|
||||
"test_name",
|
||||
nargs="?",
|
||||
@@ -658,7 +671,7 @@ def run_jittests(command_context, shell, cgc, params):
|
||||
help="Test to run. Can be a prefix or omitted. If "
|
||||
"omitted, the entire test suite is executed.",
|
||||
)
|
||||
def run_jsapitests(command_context, test_name=None):
|
||||
def run_jsapitests(self, command_context, test_name=None):
|
||||
import subprocess
|
||||
|
||||
jsapi_tests_cmd = [
|
||||
@@ -675,8 +688,7 @@ def run_jsapitests(command_context, test_name=None):
|
||||
print(f"jsapi-tests failed, exit code {result}")
|
||||
return result
|
||||
|
||||
|
||||
def run_check_js_msg(command_context):
|
||||
def run_check_js_msg(self, command_context):
|
||||
import subprocess
|
||||
|
||||
command_context.virtualenv_manager.ensure()
|
||||
@@ -684,7 +696,9 @@ def run_check_js_msg(command_context):
|
||||
|
||||
check_cmd = [
|
||||
python,
|
||||
os.path.join(command_context.topsrcdir, "config", "check_js_msg_encoding.py"),
|
||||
os.path.join(
|
||||
command_context.topsrcdir, "config", "check_js_msg_encoding.py"
|
||||
),
|
||||
]
|
||||
|
||||
return subprocess.call(check_cmd)
|
||||
@@ -696,19 +710,23 @@ def get_jsshell_parser():
|
||||
return get_parser()
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class JsShellTests(MachCommandBase):
|
||||
@Command(
|
||||
"jsshell-bench",
|
||||
category="testing",
|
||||
parser=get_jsshell_parser,
|
||||
description="Run benchmarks in the SpiderMonkey JS shell.",
|
||||
)
|
||||
def run_jsshelltests(command_context, **kwargs):
|
||||
def run_jsshelltests(self, command_context, **kwargs):
|
||||
command_context.activate_virtualenv()
|
||||
from jsshell import benchmark
|
||||
|
||||
return benchmark.run(**kwargs)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class CramTest(MachCommandBase):
|
||||
@Command(
|
||||
"cramtest",
|
||||
category="testing",
|
||||
@@ -727,7 +745,9 @@ def run_jsshelltests(command_context, **kwargs):
|
||||
help="Extra arguments to pass down to the cram binary. See "
|
||||
"'./mach python -m cram -- -h' for a list of available options.",
|
||||
)
|
||||
def cramtest(command_context, cram_args=None, test_paths=None, test_objects=None):
|
||||
def cramtest(
|
||||
self, command_context, cram_args=None, test_paths=None, test_objects=None
|
||||
):
|
||||
command_context.activate_virtualenv()
|
||||
import mozinfo
|
||||
from manifestparser import TestManifest
|
||||
@@ -757,24 +777,26 @@ def cramtest(command_context, cram_args=None, test_paths=None, test_objects=None
|
||||
return subprocess.call(cmd, cwd=command_context.topsrcdir)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class TestInfoCommand(MachCommandBase):
|
||||
from datetime import date, timedelta
|
||||
|
||||
|
||||
@Command(
|
||||
"test-info", category="testing", description="Display historical test results."
|
||||
)
|
||||
def test_info(command_context):
|
||||
def test_info(self, command_context):
|
||||
"""
|
||||
All functions implemented as subcommands.
|
||||
"""
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"test-info",
|
||||
"tests",
|
||||
description="Display historical test result summary for named tests.",
|
||||
)
|
||||
@CommandArgument("test_names", nargs=argparse.REMAINDER, help="Test(s) of interest.")
|
||||
@CommandArgument(
|
||||
"test_names", nargs=argparse.REMAINDER, help="Test(s) of interest."
|
||||
)
|
||||
@CommandArgument(
|
||||
"--start",
|
||||
default=(date.today() - timedelta(7)).strftime("%Y-%m-%d"),
|
||||
@@ -795,6 +817,7 @@ def test_info(command_context):
|
||||
)
|
||||
@CommandArgument("--verbose", action="store_true", help="Enable debug logging.")
|
||||
def test_info_tests(
|
||||
self,
|
||||
command_context,
|
||||
test_names,
|
||||
start,
|
||||
@@ -814,7 +837,6 @@ def test_info_tests(
|
||||
show_bugs,
|
||||
)
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"test-info",
|
||||
"report",
|
||||
@@ -876,6 +898,7 @@ def test_info_tests(
|
||||
@CommandArgument("--output-file", help="Path to report file.")
|
||||
@CommandArgument("--verbose", action="store_true", help="Enable debug logging.")
|
||||
def test_report(
|
||||
self,
|
||||
command_context,
|
||||
components,
|
||||
flavor,
|
||||
@@ -917,7 +940,6 @@ def test_report(
|
||||
output_file,
|
||||
)
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"test-info",
|
||||
"report-diff",
|
||||
@@ -937,20 +959,22 @@ def test_report(
|
||||
"will be written to standard output.",
|
||||
)
|
||||
@CommandArgument("--verbose", action="store_true", help="Enable debug logging.")
|
||||
def test_report_diff(command_context, before, after, output_file, verbose):
|
||||
def test_report_diff(self, command_context, before, after, output_file, verbose):
|
||||
import testinfo
|
||||
|
||||
ti = testinfo.TestInfoReport(verbose)
|
||||
ti.report_diff(before, after, output_file)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class RustTests(MachCommandBase):
|
||||
@Command(
|
||||
"rusttests",
|
||||
category="testing",
|
||||
conditions=[conditions.is_non_artifact_build],
|
||||
description="Run rust unit tests (via cargo test).",
|
||||
)
|
||||
def run_rusttests(command_context, **kwargs):
|
||||
def run_rusttests(self, command_context, **kwargs):
|
||||
return command_context._mach_context.commands.dispatch(
|
||||
"build",
|
||||
command_context._mach_context,
|
||||
@@ -958,13 +982,15 @@ def run_rusttests(command_context, **kwargs):
|
||||
)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class TestFluentMigration(MachCommandBase):
|
||||
@Command(
|
||||
"fluent-migration-test",
|
||||
category="testing",
|
||||
description="Test Fluent migration recipes.",
|
||||
)
|
||||
@CommandArgument("test_paths", nargs="*", metavar="N", help="Recipe paths to test.")
|
||||
def run_migration_tests(command_context, test_paths=None, **kwargs):
|
||||
def run_migration_tests(self, command_context, test_paths=None, **kwargs):
|
||||
if not test_paths:
|
||||
test_paths = []
|
||||
command_context.activate_virtualenv()
|
||||
|
||||
@@ -13,10 +13,12 @@ import sys
|
||||
from six import iteritems
|
||||
|
||||
from mach.decorators import (
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
|
||||
from mozbuild.base import (
|
||||
MachCommandBase,
|
||||
MachCommandConditions as conditions,
|
||||
BinaryNotFoundException,
|
||||
)
|
||||
@@ -61,6 +63,8 @@ def run_marionette(tests, binary=None, topsrcdir=None, **kwargs):
|
||||
return 0
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MarionetteTest(MachCommandBase):
|
||||
@Command(
|
||||
"marionette-test",
|
||||
category="testing",
|
||||
@@ -68,7 +72,7 @@ def run_marionette(tests, binary=None, topsrcdir=None, **kwargs):
|
||||
conditions=[functools.partial(conditions.is_buildapp_in, apps=SUPPORTED_APPS)],
|
||||
parser=create_parser_tests,
|
||||
)
|
||||
def marionette_test(command_context, tests, **kwargs):
|
||||
def marionette_test(self, command_context, tests, **kwargs):
|
||||
if "test_objects" in kwargs:
|
||||
tests = []
|
||||
for obj in kwargs["test_objects"]:
|
||||
|
||||
@@ -11,8 +11,10 @@ import sys
|
||||
from functools import partial
|
||||
|
||||
from mach.decorators import (
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
parser = None
|
||||
|
||||
@@ -59,6 +61,8 @@ def setup_marionette_argument_parser():
|
||||
return parser
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command(
|
||||
"marionette-test",
|
||||
category="testing",
|
||||
@@ -66,6 +70,6 @@ def setup_marionette_argument_parser():
|
||||
"using marionette).",
|
||||
parser=setup_marionette_argument_parser,
|
||||
)
|
||||
def run_marionette_test(command_context, **kwargs):
|
||||
def run_marionette_test(self, command_context, **kwargs):
|
||||
command_context.context.activate_mozharness_venv()
|
||||
return run_marionette(command_context.context, **kwargs)
|
||||
|
||||
@@ -14,12 +14,14 @@ import sys
|
||||
import warnings
|
||||
|
||||
from mozbuild.base import (
|
||||
MachCommandBase,
|
||||
MachCommandConditions as conditions,
|
||||
MozbuildObject,
|
||||
)
|
||||
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
|
||||
@@ -295,6 +297,8 @@ def verify_host_bin():
|
||||
return 0
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command(
|
||||
"mochitest",
|
||||
category="testing",
|
||||
@@ -303,7 +307,12 @@ def verify_host_bin():
|
||||
parser=setup_argument_parser,
|
||||
)
|
||||
def run_mochitest_general(
|
||||
command_context, flavor=None, test_objects=None, resolve_tests=True, **kwargs
|
||||
self,
|
||||
command_context,
|
||||
flavor=None,
|
||||
test_objects=None,
|
||||
resolve_tests=True,
|
||||
**kwargs
|
||||
):
|
||||
from mochitest_options import ALL_FLAVORS
|
||||
from mozlog.commandline import setup_logging
|
||||
@@ -330,7 +339,9 @@ def run_mochitest_general(
|
||||
break
|
||||
else:
|
||||
flavors = [
|
||||
f for f, v in six.iteritems(ALL_FLAVORS) if buildapp in v["enabled_apps"]
|
||||
f
|
||||
for f, v in six.iteritems(ALL_FLAVORS)
|
||||
if buildapp in v["enabled_apps"]
|
||||
]
|
||||
|
||||
from mozbuild.controller.building import BuildDriver
|
||||
@@ -355,7 +366,9 @@ def run_mochitest_general(
|
||||
|
||||
if not kwargs.get("log"):
|
||||
# Create shared logger
|
||||
format_args = {"level": command_context._mach_context.settings["test"]["level"]}
|
||||
format_args = {
|
||||
"level": command_context._mach_context.settings["test"]["level"]
|
||||
}
|
||||
if len(tests) == 1:
|
||||
format_args["verbose"] = True
|
||||
format_args["compact"] = False
|
||||
@@ -465,7 +478,9 @@ def run_mochitest_general(
|
||||
if not app:
|
||||
app = "org.mozilla.geckoview.test"
|
||||
device_serial = kwargs.get("deviceSerial")
|
||||
install = InstallIntent.NO if kwargs.get("no_install") else InstallIntent.YES
|
||||
install = (
|
||||
InstallIntent.NO if kwargs.get("no_install") else InstallIntent.YES
|
||||
)
|
||||
|
||||
# verify installation
|
||||
verify_android_device(
|
||||
@@ -493,9 +508,7 @@ def run_mochitest_general(
|
||||
# specific mochitest suite has to be loaded. See Bug 1637463.
|
||||
harness_args.update({"suite_name": suite_name})
|
||||
|
||||
result = run_mochitest(
|
||||
command_context._mach_context, tests=tests, **harness_args
|
||||
)
|
||||
result = run_mochitest(command_context, tests=tests, **harness_args)
|
||||
|
||||
if result:
|
||||
overall = result
|
||||
@@ -511,6 +524,8 @@ def run_mochitest_general(
|
||||
return overall
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class GeckoviewJunitCommands(MachCommandBase):
|
||||
@Command(
|
||||
"geckoview-junit",
|
||||
category="testing",
|
||||
@@ -525,7 +540,7 @@ def run_mochitest_general(
|
||||
action="store_true",
|
||||
default=False,
|
||||
)
|
||||
def run_junit(command_context, no_install, **kwargs):
|
||||
def run_junit(self, command_context, no_install, **kwargs):
|
||||
command_context._ensure_state_subdir_exists(".")
|
||||
|
||||
from mozrunner.devices.android_device import (
|
||||
@@ -551,11 +566,15 @@ def run_junit(command_context, no_install, **kwargs):
|
||||
if not kwargs.get("log"):
|
||||
from mozlog.commandline import setup_logging
|
||||
|
||||
format_args = {"level": command_context._mach_context.settings["test"]["level"]}
|
||||
format_args = {
|
||||
"level": command_context._mach_context.settings["test"]["level"]
|
||||
}
|
||||
default_format = command_context._mach_context.settings["test"]["format"]
|
||||
kwargs["log"] = setup_logging(
|
||||
"mach-mochitest", kwargs, {default_format: sys.stdout}, format_args
|
||||
)
|
||||
|
||||
mochitest = command_context._spawn(MochitestRunner)
|
||||
return mochitest.run_geckoview_junit_test(command_context._mach_context, **kwargs)
|
||||
return mochitest.run_geckoview_junit_test(
|
||||
command_context._mach_context, **kwargs
|
||||
)
|
||||
|
||||
@@ -11,8 +11,10 @@ from argparse import Namespace
|
||||
from functools import partial
|
||||
|
||||
from mach.decorators import (
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
parser = None
|
||||
@@ -191,23 +193,24 @@ def setup_junit_argument_parser():
|
||||
return parser
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MochitestCommands(MachCommandBase):
|
||||
@Command(
|
||||
"mochitest",
|
||||
category="testing",
|
||||
description="Run the mochitest harness.",
|
||||
parser=setup_mochitest_argument_parser,
|
||||
)
|
||||
def mochitest(command_context, **kwargs):
|
||||
def mochitest(self, command_context, **kwargs):
|
||||
command_context._mach_context.activate_mozharness_venv()
|
||||
return run_test(command_context._mach_context, False, **kwargs)
|
||||
|
||||
|
||||
@Command(
|
||||
"geckoview-junit",
|
||||
category="testing",
|
||||
description="Run the geckoview-junit harness.",
|
||||
parser=setup_junit_argument_parser,
|
||||
)
|
||||
def geckoview_junit(command_context, **kwargs):
|
||||
def geckoview_junit(self, command_context, **kwargs):
|
||||
command_context._mach_context.activate_mozharness_venv()
|
||||
return run_test(command_context._mach_context, True, **kwargs)
|
||||
|
||||
@@ -16,10 +16,11 @@ from six.moves.urllib.request import pathname2url
|
||||
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
|
||||
from mozbuild.base import MozbuildObject
|
||||
from mozbuild.base import MachCommandBase, MozbuildObject
|
||||
from mozbuild.base import MachCommandConditions as conditions
|
||||
from argparse import ArgumentParser
|
||||
|
||||
@@ -206,6 +207,8 @@ class MozharnessRunner(MozbuildObject):
|
||||
return rv
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MozharnessCommands(MachCommandBase):
|
||||
@Command(
|
||||
"mozharness",
|
||||
category="testing",
|
||||
@@ -213,6 +216,6 @@ class MozharnessRunner(MozbuildObject):
|
||||
conditions=[conditions.is_firefox_or_android],
|
||||
parser=get_parser,
|
||||
)
|
||||
def mozharness(command_context, **kwargs):
|
||||
def mozharness(self, command_context, **kwargs):
|
||||
runner = command_context._spawn(MozharnessRunner)
|
||||
return runner.run_suite(kwargs.pop("suite_name")[0], **kwargs)
|
||||
|
||||
@@ -17,9 +17,10 @@ import subprocess
|
||||
import sys
|
||||
|
||||
import mozfile
|
||||
from mach.decorators import Command
|
||||
from mach.decorators import Command, CommandProvider
|
||||
from mozboot.util import get_state_dir
|
||||
from mozbuild.base import (
|
||||
MachCommandBase,
|
||||
MozbuildObject,
|
||||
BinaryNotFoundException,
|
||||
)
|
||||
@@ -309,20 +310,24 @@ def create_parser():
|
||||
return create_parser(mach_interface=True)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachRaptor(MachCommandBase):
|
||||
@Command(
|
||||
"raptor",
|
||||
category="testing",
|
||||
description="Run Raptor performance tests.",
|
||||
parser=create_parser,
|
||||
)
|
||||
def run_raptor(command_context, **kwargs):
|
||||
def run_raptor(self, command_context, **kwargs):
|
||||
# Defers this import so that a transitive dependency doesn't
|
||||
# stop |mach bootstrap| from running
|
||||
from raptor.power import enable_charging, disable_charging
|
||||
|
||||
build_obj = command_context
|
||||
|
||||
is_android = Conditions.is_android(build_obj) or kwargs["app"] in ANDROID_BROWSERS
|
||||
is_android = (
|
||||
Conditions.is_android(build_obj) or kwargs["app"] in ANDROID_BROWSERS
|
||||
)
|
||||
|
||||
if is_android:
|
||||
from mozrunner.devices.android_device import (
|
||||
@@ -332,7 +337,9 @@ def run_raptor(command_context, **kwargs):
|
||||
from mozdevice import ADBDeviceFactory
|
||||
|
||||
install = (
|
||||
InstallIntent.NO if kwargs.pop("noinstall", False) else InstallIntent.YES
|
||||
InstallIntent.NO
|
||||
if kwargs.pop("noinstall", False)
|
||||
else InstallIntent.YES
|
||||
)
|
||||
verbose = False
|
||||
if (
|
||||
@@ -383,12 +390,11 @@ def run_raptor(command_context, **kwargs):
|
||||
if kwargs["power_test"] and device:
|
||||
enable_charging(device)
|
||||
|
||||
|
||||
@Command(
|
||||
"raptor-test",
|
||||
category="testing",
|
||||
description="Run Raptor performance tests.",
|
||||
parser=create_parser,
|
||||
)
|
||||
def run_raptor_test(command_context, **kwargs):
|
||||
return run_raptor(command_context, **kwargs)
|
||||
def run_raptor_test(self, command_context, **kwargs):
|
||||
return self.run_raptor(command_context, **kwargs)
|
||||
|
||||
@@ -15,9 +15,10 @@ import socket
|
||||
|
||||
from mozbuild.base import (
|
||||
MozbuildObject,
|
||||
MachCommandBase,
|
||||
BinaryNotFoundException,
|
||||
)
|
||||
from mach.decorators import Command
|
||||
from mach.decorators import CommandProvider, Command
|
||||
|
||||
HERE = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
@@ -122,13 +123,15 @@ def create_parser():
|
||||
return create_parser(mach_interface=True)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command(
|
||||
"talos-test",
|
||||
category="testing",
|
||||
description="Run talos tests (performance testing).",
|
||||
parser=create_parser,
|
||||
)
|
||||
def run_talos_test(command_context, **kwargs):
|
||||
def run_talos_test(self, command_context, **kwargs):
|
||||
talos = command_context._spawn(TalosRunner)
|
||||
|
||||
try:
|
||||
|
||||
@@ -5,14 +5,18 @@
|
||||
from __future__ import absolute_import, print_function
|
||||
import os
|
||||
|
||||
from mach.decorators import Command, CommandArgument
|
||||
from mach.decorators import Command, CommandArgument, CommandProvider
|
||||
from mozbuild.base import MachCommandBase
|
||||
from mozpack.copier import Jarrer
|
||||
from mozpack.files import FileFinder
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command("tps-build", category="testing", description="Build TPS add-on.")
|
||||
@CommandArgument("--dest", default=None, help="Where to write add-on.")
|
||||
def build(command_context, dest):
|
||||
def build(self, command_context, dest):
|
||||
"""TPS tests for Sync."""
|
||||
src = os.path.join(
|
||||
command_context.topsrcdir, "services", "sync", "tps", "extensions", "tps"
|
||||
)
|
||||
|
||||
@@ -12,11 +12,13 @@ import sys
|
||||
from six import iteritems
|
||||
|
||||
from mozbuild.base import (
|
||||
MachCommandBase,
|
||||
MachCommandConditions as conditions,
|
||||
MozbuildObject,
|
||||
)
|
||||
|
||||
from mach.decorators import (
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
|
||||
@@ -466,10 +468,12 @@ def create_parser_testpaths():
|
||||
return parser
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@staticmethod
|
||||
def setup(command_context):
|
||||
command_context.activate_virtualenv()
|
||||
|
||||
|
||||
@Command(
|
||||
"web-platform-tests",
|
||||
category="testing",
|
||||
@@ -477,8 +481,8 @@ def setup(command_context):
|
||||
description="Run web-platform-tests.",
|
||||
parser=create_parser_wpt,
|
||||
)
|
||||
def run_web_platform_tests(command_context, **params):
|
||||
setup(command_context)
|
||||
def run_web_platform_tests(self, command_context, **params):
|
||||
self.setup(command_context)
|
||||
if params["product"] is None:
|
||||
if conditions.is_android(command_context):
|
||||
params["product"] = "firefox_android"
|
||||
@@ -510,11 +514,12 @@ def run_web_platform_tests(command_context, **params):
|
||||
conditions.is_android(command_context)
|
||||
and params["product"] != "firefox_android"
|
||||
):
|
||||
logger.warning("Must specify --product=firefox_android in Android environment.")
|
||||
logger.warning(
|
||||
"Must specify --product=firefox_android in Android environment."
|
||||
)
|
||||
|
||||
return wpt_runner.run(logger, **params)
|
||||
|
||||
|
||||
@Command(
|
||||
"wpt",
|
||||
category="testing",
|
||||
@@ -522,9 +527,8 @@ def run_web_platform_tests(command_context, **params):
|
||||
description="Run web-platform-tests.",
|
||||
parser=create_parser_wpt,
|
||||
)
|
||||
def run_wpt(command_context, **params):
|
||||
return run_web_platform_tests(command_context, **params)
|
||||
|
||||
def run_wpt(self, command_context, **params):
|
||||
return self.run_web_platform_tests(command_context, **params)
|
||||
|
||||
@Command(
|
||||
"web-platform-tests-update",
|
||||
@@ -532,8 +536,8 @@ def run_wpt(command_context, **params):
|
||||
description="Update web-platform-test metadata.",
|
||||
parser=create_parser_update,
|
||||
)
|
||||
def update_web_platform_tests(command_context, **params):
|
||||
setup(command_context)
|
||||
def update_web_platform_tests(self, command_context, **params):
|
||||
self.setup(command_context)
|
||||
command_context.virtualenv_manager.install_pip_package("html5lib==1.0.1")
|
||||
command_context.virtualenv_manager.install_pip_package("ujson")
|
||||
command_context.virtualenv_manager.install_pip_package("requests")
|
||||
@@ -542,16 +546,14 @@ def update_web_platform_tests(command_context, **params):
|
||||
logger = wpt_updater.setup_logging(**params)
|
||||
return wpt_updater.run_update(logger, **params)
|
||||
|
||||
|
||||
@Command(
|
||||
"wpt-update",
|
||||
category="testing",
|
||||
description="Update web-platform-test metadata.",
|
||||
parser=create_parser_update,
|
||||
)
|
||||
def update_wpt(command_context, **params):
|
||||
return update_web_platform_tests(command_context, **params)
|
||||
|
||||
def update_wpt(self, command_context, **params):
|
||||
return self.update_web_platform_tests(command_context, **params)
|
||||
|
||||
@Command(
|
||||
"wpt-manifest-update",
|
||||
@@ -559,8 +561,8 @@ def update_wpt(command_context, **params):
|
||||
description="Update web-platform-test manifests.",
|
||||
parser=create_parser_manifest_update,
|
||||
)
|
||||
def wpt_manifest_update(command_context, **params):
|
||||
setup(command_context)
|
||||
def wpt_manifest_update(self, command_context, **params):
|
||||
self.setup(command_context)
|
||||
wpt_setup = command_context._spawn(WebPlatformTestsRunnerSetup)
|
||||
wpt_runner = WebPlatformTestsRunner(wpt_setup)
|
||||
logger = wpt_runner.setup_logging(**params)
|
||||
@@ -570,15 +572,14 @@ def wpt_manifest_update(command_context, **params):
|
||||
)
|
||||
return 0 if wpt_runner.update_manifest(logger, **params) else 1
|
||||
|
||||
|
||||
@Command(
|
||||
"wpt-serve",
|
||||
category="testing",
|
||||
description="Run the wpt server",
|
||||
parser=create_parser_serve,
|
||||
)
|
||||
def wpt_serve(command_context, **params):
|
||||
setup(command_context)
|
||||
def wpt_serve(self, command_context, **params):
|
||||
self.setup(command_context)
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger("web-platform-tests")
|
||||
@@ -586,61 +587,58 @@ def wpt_serve(command_context, **params):
|
||||
wpt_serve = command_context._spawn(WebPlatformTestsServeRunner)
|
||||
return wpt_serve.run(**params)
|
||||
|
||||
|
||||
@Command(
|
||||
"wpt-metadata-summary",
|
||||
category="testing",
|
||||
description="Create a json summary of the wpt metadata",
|
||||
parser=create_parser_metadata_summary,
|
||||
)
|
||||
def wpt_summary(command_context, **params):
|
||||
def wpt_summary(self, command_context, **params):
|
||||
import metasummary
|
||||
|
||||
wpt_setup = command_context._spawn(WebPlatformTestsRunnerSetup)
|
||||
return metasummary.run(wpt_setup.topsrcdir, wpt_setup.topobjdir, **params)
|
||||
|
||||
|
||||
@Command("wpt-metadata-merge", category="testing", parser=create_parser_metadata_merge)
|
||||
def wpt_meta_merge(command_context, **params):
|
||||
@Command(
|
||||
"wpt-metadata-merge", category="testing", parser=create_parser_metadata_merge
|
||||
)
|
||||
def wpt_meta_merge(self, command_context, **params):
|
||||
import metamerge
|
||||
|
||||
if params["dest"] is None:
|
||||
params["dest"] = params["current"]
|
||||
return metamerge.run(**params)
|
||||
|
||||
|
||||
@Command(
|
||||
"wpt-unittest",
|
||||
category="testing",
|
||||
description="Run the wpt tools and wptrunner unit tests",
|
||||
parser=create_parser_unittest,
|
||||
)
|
||||
def wpt_unittest(command_context, **params):
|
||||
setup(command_context)
|
||||
def wpt_unittest(self, command_context, **params):
|
||||
self.setup(command_context)
|
||||
command_context.virtualenv_manager.install_pip_package("tox")
|
||||
runner = command_context._spawn(WebPlatformTestsUnittestRunner)
|
||||
return 0 if runner.run(**params) else 1
|
||||
|
||||
|
||||
@Command(
|
||||
"wpt-test-paths",
|
||||
category="testing",
|
||||
description="Get a mapping from test ids to files",
|
||||
parser=create_parser_testpaths,
|
||||
)
|
||||
def wpt_test_paths(command_context, **params):
|
||||
def wpt_test_paths(self, command_context, **params):
|
||||
runner = command_context._spawn(WebPlatformTestsTestPathsRunner)
|
||||
runner.run(**params)
|
||||
return 0
|
||||
|
||||
|
||||
@Command(
|
||||
"wpt-fission-regressions",
|
||||
category="testing",
|
||||
description="Dump a list of fission-specific regressions",
|
||||
parser=create_parser_fission_regressions,
|
||||
)
|
||||
def wpt_fission_regressions(command_context, **params):
|
||||
def wpt_fission_regressions(self, command_context, **params):
|
||||
runner = command_context._spawn(WebPlatformTestsFissionRegressionsRunner)
|
||||
runner.run(**params)
|
||||
return 0
|
||||
|
||||
@@ -9,8 +9,10 @@ import sys
|
||||
|
||||
from mach_commands_base import WebPlatformTestsRunner, create_parser_wpt
|
||||
from mach.decorators import (
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
|
||||
class WebPlatformTestsRunnerSetup(object):
|
||||
@@ -70,14 +72,15 @@ class WebPlatformTestsRunnerSetup(object):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command("web-platform-tests", category="testing", parser=create_parser_wpt)
|
||||
def run_web_platform_tests(command_context, **kwargs):
|
||||
def run_web_platform_tests(self, command_context, **kwargs):
|
||||
command_context._mach_context.activate_mozharness_venv()
|
||||
return WebPlatformTestsRunner(
|
||||
WebPlatformTestsRunnerSetup(command_context._mach_context)
|
||||
).run(**kwargs)
|
||||
|
||||
|
||||
@Command("wpt", category="testing", parser=create_parser_wpt)
|
||||
def run_wpt(command_context, **params):
|
||||
def run_wpt(self, command_context, **params):
|
||||
return command_context.run_web_platform_tests(**params)
|
||||
|
||||
@@ -14,12 +14,14 @@ import sys
|
||||
from mozlog import structured
|
||||
|
||||
from mozbuild.base import (
|
||||
MachCommandBase,
|
||||
MozbuildObject,
|
||||
MachCommandConditions as conditions,
|
||||
BinaryNotFoundException,
|
||||
)
|
||||
|
||||
from mach.decorators import (
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
|
||||
@@ -217,6 +219,8 @@ def get_parser():
|
||||
return parser_desktop()
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command(
|
||||
"xpcshell-test",
|
||||
category="testing",
|
||||
@@ -224,7 +228,7 @@ def get_parser():
|
||||
conditions=[lambda *args: True],
|
||||
parser=get_parser,
|
||||
)
|
||||
def run_xpcshell_test(command_context, test_objects=None, **params):
|
||||
def run_xpcshell_test(self, command_context, test_objects=None, **params):
|
||||
from mozbuild.controller.building import BuildDriver
|
||||
|
||||
if test_objects is not None:
|
||||
|
||||
@@ -14,8 +14,10 @@ import mozlog
|
||||
from xpcshellcommandline import parser_desktop
|
||||
|
||||
from mach.decorators import (
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
|
||||
def run_xpcshell(context, **kwargs):
|
||||
@@ -50,12 +52,14 @@ def run_xpcshell(context, **kwargs):
|
||||
return xpcshell.runTests(**vars(args))
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MochitestCommands(MachCommandBase):
|
||||
@Command(
|
||||
"xpcshell-test",
|
||||
category="testing",
|
||||
description="Run the xpcshell harness.",
|
||||
parser=parser_desktop,
|
||||
)
|
||||
def xpcshell(command_context, **kwargs):
|
||||
def xpcshell(self, command_context, **kwargs):
|
||||
command_context._mach_context.activate_mozharness_venv()
|
||||
return run_xpcshell(command_context._mach_context, **kwargs)
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
# 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/.
|
||||
|
||||
from mach.decorators import Command, CommandArgument
|
||||
from mach.decorators import CommandProvider, Command, CommandArgument
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class DataReviewer(MachCommandBase):
|
||||
@Command(
|
||||
"data-review",
|
||||
category="misc",
|
||||
@@ -13,7 +16,7 @@ from mach.decorators import Command, CommandArgument
|
||||
@CommandArgument(
|
||||
"bug", default=None, nargs="?", type=str, help="bug number or search pattern"
|
||||
)
|
||||
def data_review(command_context, bug=None):
|
||||
def data_review(self, command_context, bug=None):
|
||||
# Get the metrics_index's list of metrics indices
|
||||
# by loading the index as a module.
|
||||
from os import path
|
||||
|
||||
@@ -8,9 +8,10 @@ import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
from mach.decorators import Command
|
||||
from mach.decorators import CommandProvider, Command
|
||||
|
||||
from mozbuild.base import (
|
||||
MachCommandBase,
|
||||
MachCommandConditions as conditions,
|
||||
BinaryNotFoundException,
|
||||
)
|
||||
@@ -64,6 +65,8 @@ def run_telemetry(tests, binary=None, topsrcdir=None, **kwargs):
|
||||
return 0
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class TelemetryTest(MachCommandBase):
|
||||
@Command(
|
||||
"telemetry-tests-client",
|
||||
category="testing",
|
||||
@@ -71,7 +74,7 @@ def run_telemetry(tests, binary=None, topsrcdir=None, **kwargs):
|
||||
conditions=[conditions.is_firefox_or_android],
|
||||
parser=create_parser_tests,
|
||||
)
|
||||
def telemetry_test(command_context, tests, **kwargs):
|
||||
def telemetry_test(self, command_context, tests, **kwargs):
|
||||
if "test_objects" in kwargs:
|
||||
tests = []
|
||||
for obj in kwargs["test_objects"]:
|
||||
|
||||
@@ -42,7 +42,7 @@ import sys
|
||||
import time
|
||||
|
||||
from six import StringIO
|
||||
from mach.decorators import CommandArgument, Command
|
||||
from mach.decorators import CommandArgument, CommandProvider, Command
|
||||
from mozbuild.base import MachCommandBase, BinaryNotFoundException
|
||||
from mozbuild.util import mkdir
|
||||
import mozpack.path as mozpath
|
||||
@@ -151,19 +151,21 @@ host_fetches = {
|
||||
}
|
||||
|
||||
|
||||
def artifact_cache_path(command_context):
|
||||
@CommandProvider
|
||||
class MachBrowsertime(MachCommandBase):
|
||||
def artifact_cache_path(self, command_context):
|
||||
r"""Downloaded artifacts will be kept here."""
|
||||
# The convention is $MOZBUILD_STATE_PATH/cache/$FEATURE.
|
||||
return mozpath.join(command_context._mach_context.state_dir, "cache", "browsertime")
|
||||
return mozpath.join(
|
||||
command_context._mach_context.state_dir, "cache", "browsertime"
|
||||
)
|
||||
|
||||
|
||||
def state_path(command_context):
|
||||
def state_path(self, command_context):
|
||||
r"""Unpacked artifacts will be kept here."""
|
||||
# The convention is $MOZBUILD_STATE_PATH/$FEATURE.
|
||||
return mozpath.join(command_context._mach_context.state_dir, "browsertime")
|
||||
|
||||
|
||||
def setup_prerequisites(command_context):
|
||||
def setup_prerequisites(self, command_context):
|
||||
r"""Install browsertime and visualmetrics.py prerequisites."""
|
||||
|
||||
from mozbuild.action.tooltool import unpack_file
|
||||
@@ -189,7 +191,7 @@ def setup_prerequisites(command_context):
|
||||
|
||||
# Download the visualmetrics.py requirements.
|
||||
artifact_cache = ArtifactCache(
|
||||
artifact_cache_path(command_context),
|
||||
self.artifact_cache_path(command_context),
|
||||
log=command_context.log,
|
||||
skip_cache=False,
|
||||
)
|
||||
@@ -202,8 +204,8 @@ def setup_prerequisites(command_context):
|
||||
if fetch.get("unpack", True):
|
||||
cwd = os.getcwd()
|
||||
try:
|
||||
mkdir(state_path(command_context))
|
||||
os.chdir(state_path(command_context))
|
||||
mkdir(self.state_path(command_context))
|
||||
os.chdir(self.state_path(command_context))
|
||||
command_context.log(
|
||||
logging.INFO,
|
||||
"browsertime",
|
||||
@@ -216,15 +218,19 @@ def setup_prerequisites(command_context):
|
||||
# so we make one for it here
|
||||
mkdir(fetch.get("path"))
|
||||
os.chdir(
|
||||
os.path.join(state_path(command_context), fetch.get("path"))
|
||||
os.path.join(
|
||||
self.state_path(command_context), fetch.get("path")
|
||||
)
|
||||
)
|
||||
unpack_file(archive)
|
||||
os.chdir(state_path(command_context))
|
||||
os.chdir(self.state_path(command_context))
|
||||
else:
|
||||
unpack_file(archive)
|
||||
|
||||
# Make sure the expected path exists after extraction
|
||||
path = os.path.join(state_path(command_context), fetch.get("path"))
|
||||
path = os.path.join(
|
||||
self.state_path(command_context), fetch.get("path")
|
||||
)
|
||||
if not os.path.exists(path):
|
||||
raise Exception("Cannot find an extracted directory: %s" % path)
|
||||
|
||||
@@ -242,20 +248,24 @@ def setup_prerequisites(command_context):
|
||||
os.chmod(loc_to_change, st.st_mode | stat.S_IEXEC)
|
||||
except Exception as e:
|
||||
raise Exception(
|
||||
"Could not set executable bit in %s, error: %s" % (path, str(e))
|
||||
"Could not set executable bit in %s, error: %s"
|
||||
% (path, str(e))
|
||||
)
|
||||
finally:
|
||||
os.chdir(cwd)
|
||||
|
||||
|
||||
def setup_browsertime(command_context, should_clobber=False, new_upstream_url=""):
|
||||
def setup_browsertime(
|
||||
self, command_context, should_clobber=False, new_upstream_url=""
|
||||
):
|
||||
r"""Install browsertime and visualmetrics.py prerequisites and the Node.js package."""
|
||||
|
||||
sys.path.append(mozpath.join(command_context.topsrcdir, "tools", "lint", "eslint"))
|
||||
sys.path.append(
|
||||
mozpath.join(command_context.topsrcdir, "tools", "lint", "eslint")
|
||||
)
|
||||
import setup_helper
|
||||
|
||||
if not new_upstream_url:
|
||||
setup_prerequisites(command_context)
|
||||
self.setup_prerequisites(command_context)
|
||||
|
||||
if new_upstream_url:
|
||||
package_json_path = os.path.join(BROWSERTIME_ROOT, "package.json")
|
||||
@@ -321,21 +331,19 @@ def setup_browsertime(command_context, should_clobber=False, new_upstream_url=""
|
||||
if new_upstream_url or AUTOMATION:
|
||||
return 0
|
||||
|
||||
return check(command_context)
|
||||
return self.check(command_context)
|
||||
|
||||
|
||||
def node(command_context, args):
|
||||
def node(self, command_context, args):
|
||||
r"""Invoke node (interactively) with the given arguments."""
|
||||
return command_context.run_process(
|
||||
[node_path()] + args,
|
||||
append_env=append_env(command_context),
|
||||
append_env=self.append_env(command_context),
|
||||
pass_thru=True, # Allow user to run Node interactively.
|
||||
ensure_exit_code=False, # Don't throw on non-zero exit code.
|
||||
cwd=mozpath.join(command_context.topsrcdir),
|
||||
)
|
||||
|
||||
|
||||
def append_env(command_context, append_path=True):
|
||||
def append_env(self, command_context, append_path=True):
|
||||
fetches = host_fetches[host_platform()]
|
||||
|
||||
# Ensure that bare `ffmpeg` and ImageMagick commands
|
||||
@@ -344,13 +352,13 @@ def append_env(command_context, append_path=True):
|
||||
# We should update the script itself to accept this configuration.
|
||||
path = os.environ.get("PATH", "").split(os.pathsep) if append_path else []
|
||||
path_to_ffmpeg = mozpath.join(
|
||||
state_path(command_context), fetches["ffmpeg"]["path"]
|
||||
self.state_path(command_context), fetches["ffmpeg"]["path"]
|
||||
)
|
||||
|
||||
path_to_imagemagick = None
|
||||
if "ImageMagick" in fetches:
|
||||
path_to_imagemagick = mozpath.join(
|
||||
state_path(command_context), fetches["ImageMagick"]["path"]
|
||||
self.state_path(command_context), fetches["ImageMagick"]["path"]
|
||||
)
|
||||
|
||||
if path_to_imagemagick:
|
||||
@@ -358,7 +366,7 @@ def append_env(command_context, append_path=True):
|
||||
# want to ensure that our ffmpeg goes first, just in case.
|
||||
path.insert(
|
||||
0,
|
||||
state_path(command_context)
|
||||
self.state_path(command_context)
|
||||
if host_platform().startswith("win")
|
||||
else mozpath.join(path_to_imagemagick, "bin"),
|
||||
) # noqa
|
||||
@@ -425,8 +433,7 @@ def append_env(command_context, append_path=True):
|
||||
|
||||
return append_env
|
||||
|
||||
|
||||
def _need_install(command_context, package):
|
||||
def _need_install(self, command_context, package):
|
||||
from pip._internal.req.constructors import install_req_from_line
|
||||
|
||||
req = install_req_from_line(package)
|
||||
@@ -439,8 +446,7 @@ def _need_install(command_context, package):
|
||||
site_packages = os.path.abspath(req.satisfied_by.location)
|
||||
return not site_packages.startswith(venv_site_lib)
|
||||
|
||||
|
||||
def activate_browsertime_virtualenv(command_context, *args, **kwargs):
|
||||
def activate_browsertime_virtualenv(self, command_context, *args, **kwargs):
|
||||
r"""Activates virtualenv.
|
||||
|
||||
This function will also install Pillow and pyssim if needed.
|
||||
@@ -450,21 +456,21 @@ def activate_browsertime_virtualenv(command_context, *args, **kwargs):
|
||||
|
||||
# installing Python deps on the fly
|
||||
for dep in ("Pillow==%s" % PILLOW_VERSION, "pyssim==%s" % PYSSIM_VERSION):
|
||||
if _need_install(command_context, dep):
|
||||
if self._need_install(command_context, dep):
|
||||
command_context.virtualenv_manager._run_pip(["install", dep])
|
||||
|
||||
|
||||
def check(command_context):
|
||||
def check(self, command_context):
|
||||
r"""Run `visualmetrics.py --check`."""
|
||||
command_context.activate_virtualenv()
|
||||
|
||||
args = ["--check"]
|
||||
status = command_context.run_process(
|
||||
[command_context.virtualenv_manager.python_path, visualmetrics_path()] + args,
|
||||
[command_context.virtualenv_manager.python_path, visualmetrics_path()]
|
||||
+ args,
|
||||
# For --check, don't allow user's path to interfere with
|
||||
# path testing except on Linux, where ImageMagick needs to
|
||||
# be installed manually.
|
||||
append_env=append_env(
|
||||
append_env=self.append_env(
|
||||
command_context, append_path=host_platform().startswith("linux")
|
||||
),
|
||||
pass_thru=True,
|
||||
@@ -485,10 +491,9 @@ def check(command_context):
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
|
||||
return node(command_context, [browsertime_path()] + ["--version"])
|
||||
return self.node(command_context, [browsertime_path()] + ["--version"])
|
||||
|
||||
|
||||
def extra_default_args(command_context, args=[]):
|
||||
def extra_default_args(self, command_context, args=[]):
|
||||
# Add Mozilla-specific default arguments. This is tricky because browsertime is quite
|
||||
# loose about arguments; repeat arguments are generally accepted but then produce
|
||||
# difficult to interpret type errors.
|
||||
@@ -568,10 +573,11 @@ def extra_default_args(command_context, args=[]):
|
||||
|
||||
return extra_args
|
||||
|
||||
|
||||
def _verify_node_install(command_context):
|
||||
def _verify_node_install(self, command_context):
|
||||
# check if Node is installed
|
||||
sys.path.append(mozpath.join(command_context.topsrcdir, "tools", "lint", "eslint"))
|
||||
sys.path.append(
|
||||
mozpath.join(command_context.topsrcdir, "tools", "lint", "eslint")
|
||||
)
|
||||
import setup_helper
|
||||
|
||||
with silence():
|
||||
@@ -589,7 +595,6 @@ def _verify_node_install(command_context):
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@Command(
|
||||
"browsertime",
|
||||
category="testing",
|
||||
@@ -619,6 +624,7 @@ def _verify_node_install(command_context):
|
||||
)
|
||||
@CommandArgument("args", nargs=argparse.REMAINDER)
|
||||
def browsertime(
|
||||
self,
|
||||
command_context,
|
||||
args,
|
||||
verbose=False,
|
||||
@@ -652,21 +658,23 @@ def browsertime(
|
||||
time.sleep(5)
|
||||
|
||||
if update_upstream_url:
|
||||
return setup_browsertime(command_context, new_upstream_url=update_upstream_url)
|
||||
return self.setup_browsertime(
|
||||
command_context, new_upstream_url=update_upstream_url
|
||||
)
|
||||
elif setup:
|
||||
return setup_browsertime(command_context, should_clobber=clobber)
|
||||
return self.setup_browsertime(command_context, should_clobber=clobber)
|
||||
else:
|
||||
if not _verify_node_install(command_context):
|
||||
if not self._verify_node_install(command_context):
|
||||
return 1
|
||||
|
||||
if check:
|
||||
return check(command_context)
|
||||
return self.check(command_context)
|
||||
|
||||
if browsertime_help:
|
||||
args.append("--help")
|
||||
|
||||
activate_browsertime_virtualenv(command_context)
|
||||
default_args = extra_default_args(command_context, args)
|
||||
self.activate_browsertime_virtualenv(command_context)
|
||||
default_args = self.extra_default_args(command_context, args)
|
||||
if default_args == 1:
|
||||
return 1
|
||||
return node(command_context, [browsertime_path()] + default_args + args)
|
||||
return self.node(command_context, [browsertime_path()] + default_args + args)
|
||||
|
||||
@@ -8,9 +8,11 @@ from appdirs import user_config_dir
|
||||
from hglib.error import CommandError
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
from mach.base import FailedCommandError
|
||||
from mozbuild.base import MachCommandBase
|
||||
from mozrelease.scriptworker_canary import get_secret
|
||||
from pathlib import Path
|
||||
from redo import retry
|
||||
@@ -20,6 +22,8 @@ import os
|
||||
import tempfile
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class CompareLocales(MachCommandBase):
|
||||
@Command(
|
||||
"compare-locales",
|
||||
category="build",
|
||||
@@ -40,7 +44,7 @@ import tempfile
|
||||
"locales",
|
||||
nargs="*",
|
||||
metavar="locale-code",
|
||||
help="Locale code and top-level directory of each localization",
|
||||
help="Locale code and top-level directory of " "each localization",
|
||||
)
|
||||
@CommandArgument(
|
||||
"-q",
|
||||
@@ -52,7 +56,9 @@ Specified once, don't show obsolete entities. Specified twice, also hide
|
||||
missing entities. Specify thrice to exclude warnings and four times to
|
||||
just show stats""",
|
||||
)
|
||||
@CommandArgument("-m", "--merge", help="""Use this directory to stage merged files""")
|
||||
@CommandArgument(
|
||||
"-m", "--merge", help="""Use this directory to stage merged files"""
|
||||
)
|
||||
@CommandArgument(
|
||||
"--validate", action="store_true", help="Run compare-locales against reference"
|
||||
)
|
||||
@@ -76,7 +82,7 @@ the output file, pass "-" to serialize to stdout and hide the default output.
|
||||
@CommandArgument(
|
||||
"--return-zero", action="store_true", help="Return 0 regardless of l10n status"
|
||||
)
|
||||
def compare(command_context, **kwargs):
|
||||
def compare(self, command_context, **kwargs):
|
||||
"""Run compare-locales."""
|
||||
from compare_locales.commands import CompareLocales
|
||||
|
||||
@@ -114,6 +120,8 @@ FXTREE_PATH = VCT_PATH / "hgext" / "firefoxtree"
|
||||
HGRC_PATH = Path(user_config_dir("hg")).joinpath("hgrc")
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class CrossChannel(MachCommandBase):
|
||||
@Command(
|
||||
"l10n-cross-channel",
|
||||
category="misc",
|
||||
@@ -157,6 +165,7 @@ HGRC_PATH = Path(user_config_dir("hg")).joinpath("hgrc")
|
||||
""",
|
||||
)
|
||||
def cross_channel(
|
||||
self,
|
||||
command_context,
|
||||
strings_path,
|
||||
outgoing_path,
|
||||
@@ -182,7 +191,7 @@ def cross_channel(
|
||||
try:
|
||||
with tempfile.TemporaryDirectory() as ssh_key_dir:
|
||||
retry(
|
||||
_do_create_content,
|
||||
self._do_create_content,
|
||||
attempts=attempts,
|
||||
retry_exceptions=(RetryError,),
|
||||
args=(
|
||||
@@ -197,8 +206,8 @@ def cross_channel(
|
||||
except RetryError as exc:
|
||||
raise FailedCommandError(exc) from exc
|
||||
|
||||
|
||||
def _do_create_content(
|
||||
self,
|
||||
command_context,
|
||||
strings_path,
|
||||
outgoing_path,
|
||||
@@ -228,7 +237,7 @@ def _do_create_content(
|
||||
ssh_key_file.chmod(0o600)
|
||||
# Set up firefoxtree for comm per bug 1659691 comment 22
|
||||
if os.environ.get("MOZ_AUTOMATION") and not HGRC_PATH.exists():
|
||||
_clone_hg_repo(command_context, VCT_URL, VCT_PATH)
|
||||
self._clone_hg_repo(command_context, VCT_URL, VCT_PATH)
|
||||
hgrc_content = [
|
||||
"[extensions]",
|
||||
f"firefoxtree = {FXTREE_PATH}",
|
||||
@@ -243,18 +252,20 @@ def _do_create_content(
|
||||
]
|
||||
)
|
||||
HGRC_PATH.write_text("\n".join(hgrc_content))
|
||||
if strings_path.exists() and _check_outgoing(command_context, strings_path):
|
||||
_strip_outgoing(command_context, strings_path)
|
||||
if strings_path.exists() and self._check_outgoing(
|
||||
command_context, strings_path
|
||||
):
|
||||
self._strip_outgoing(command_context, strings_path)
|
||||
# Clone strings + source repos, pull heads
|
||||
for repo_config in (config["strings"], *config["source"].values()):
|
||||
if not repo_config["path"].exists():
|
||||
_clone_hg_repo(
|
||||
self._clone_hg_repo(
|
||||
command_context, repo_config["url"], str(repo_config["path"])
|
||||
)
|
||||
for head in repo_config["heads"].keys():
|
||||
command = ["hg", "--cwd", str(repo_config["path"]), "pull"]
|
||||
command.append(head)
|
||||
status = _retry_run_process(
|
||||
status = self._retry_run_process(
|
||||
command_context, command, ensure_exit_code=False
|
||||
)
|
||||
if status not in (0, 255): # 255 on pull with no changes
|
||||
@@ -269,32 +280,34 @@ def _do_create_content(
|
||||
"-r",
|
||||
head,
|
||||
]
|
||||
status = _retry_run_process(
|
||||
status = self._retry_run_process(
|
||||
command_context, command, ensure_exit_code=False
|
||||
)
|
||||
if status not in (0, 255): # 255 on pull with no changes
|
||||
raise RetryError(f"Failure on update: status {status}!")
|
||||
_check_hg_repo(
|
||||
self._check_hg_repo(
|
||||
command_context,
|
||||
repo_config["path"],
|
||||
heads=repo_config.get("heads", {}).keys(),
|
||||
)
|
||||
else:
|
||||
_check_hg_repo(command_context, strings_path)
|
||||
self._check_hg_repo(command_context, strings_path)
|
||||
for repo_config in config.get("source", {}).values():
|
||||
_check_hg_repo(
|
||||
self._check_hg_repo(
|
||||
command_context,
|
||||
repo_config["path"],
|
||||
heads=repo_config.get("heads", {}).keys(),
|
||||
)
|
||||
if _check_outgoing(command_context, strings_path):
|
||||
if self._check_outgoing(command_context, strings_path):
|
||||
raise RetryError(f"check: Outgoing changes in {strings_path}!")
|
||||
|
||||
if "create" in actions:
|
||||
try:
|
||||
status = ccc.create_content()
|
||||
changes = True
|
||||
_create_outgoing_patch(command_context, outgoing_path, strings_path)
|
||||
self._create_outgoing_patch(
|
||||
command_context, outgoing_path, strings_path
|
||||
)
|
||||
except CommandError as exc:
|
||||
if exc.ret != 1:
|
||||
raise RetryError(exc) from exc
|
||||
@@ -302,7 +315,7 @@ def _do_create_content(
|
||||
|
||||
if "push" in actions:
|
||||
if changes:
|
||||
_retry_run_process(
|
||||
self._retry_run_process(
|
||||
command_context,
|
||||
[
|
||||
"hg",
|
||||
@@ -320,9 +333,8 @@ def _do_create_content(
|
||||
|
||||
return status
|
||||
|
||||
|
||||
def _check_outgoing(command_context, strings_path):
|
||||
status = _retry_run_process(
|
||||
def _check_outgoing(self, command_context, strings_path):
|
||||
status = self._retry_run_process(
|
||||
command_context,
|
||||
["hg", "--cwd", str(strings_path), "out", "-r", "."],
|
||||
ensure_exit_code=False,
|
||||
@@ -331,11 +343,12 @@ def _check_outgoing(command_context, strings_path):
|
||||
return True
|
||||
if status == 1:
|
||||
return False
|
||||
raise RetryError(f"Outgoing check in {strings_path} returned unexpected {status}!")
|
||||
raise RetryError(
|
||||
f"Outgoing check in {strings_path} returned unexpected {status}!"
|
||||
)
|
||||
|
||||
|
||||
def _strip_outgoing(command_context, strings_path):
|
||||
_retry_run_process(
|
||||
def _strip_outgoing(self, command_context, strings_path):
|
||||
self._retry_run_process(
|
||||
command_context,
|
||||
[
|
||||
"hg",
|
||||
@@ -349,8 +362,7 @@ def _strip_outgoing(command_context, strings_path):
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def _create_outgoing_patch(command_context, path, strings_path):
|
||||
def _create_outgoing_patch(self, command_context, path, strings_path):
|
||||
if not path:
|
||||
return
|
||||
if not path.parent.exists():
|
||||
@@ -360,7 +372,7 @@ def _create_outgoing_patch(command_context, path, strings_path):
|
||||
def writeln(line):
|
||||
fh.write(f"{line}\n")
|
||||
|
||||
_retry_run_process(
|
||||
self._retry_run_process(
|
||||
command_context,
|
||||
[
|
||||
"hg",
|
||||
@@ -375,25 +387,22 @@ def _create_outgoing_patch(command_context, path, strings_path):
|
||||
line_handler=writeln,
|
||||
)
|
||||
|
||||
|
||||
def _retry_run_process(command_context, *args, error_msg=None, **kwargs):
|
||||
def _retry_run_process(self, command_context, *args, error_msg=None, **kwargs):
|
||||
try:
|
||||
return command_context.run_process(*args, **kwargs)
|
||||
except Exception as exc:
|
||||
raise RetryError(error_msg or str(exc)) from exc
|
||||
|
||||
|
||||
def _check_hg_repo(command_context, path, heads=None):
|
||||
def _check_hg_repo(self, command_context, path, heads=None):
|
||||
if not (path.is_dir() and (path / ".hg").is_dir()):
|
||||
raise RetryError(f"{path} is not a Mercurial repository")
|
||||
if heads:
|
||||
for head in heads:
|
||||
_retry_run_process(
|
||||
self._retry_run_process(
|
||||
command_context,
|
||||
["hg", "--cwd", str(path), "log", "-r", head],
|
||||
error_msg=f"check: {path} has no head {head}!",
|
||||
)
|
||||
|
||||
|
||||
def _clone_hg_repo(command_context, url, path):
|
||||
_retry_run_process(command_context, ["hg", "clone", url, str(path)])
|
||||
def _clone_hg_repo(self, command_context, url, path):
|
||||
self._retry_run_process(command_context, ["hg", "clone", url, str(path)])
|
||||
|
||||
@@ -8,11 +8,13 @@ import os
|
||||
|
||||
from mozbuild.base import (
|
||||
BuildEnvironmentNotFoundException,
|
||||
MachCommandBase,
|
||||
)
|
||||
|
||||
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
|
||||
@@ -59,13 +61,15 @@ def get_global_excludes(topsrcdir):
|
||||
return excludes
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command(
|
||||
"lint",
|
||||
category="devenv",
|
||||
description="Run linters.",
|
||||
parser=setup_argument_parser,
|
||||
)
|
||||
def lint(command_context, *runargs, **lintargs):
|
||||
def lint(self, command_context, *runargs, **lintargs):
|
||||
"""Run linters."""
|
||||
command_context.activate_virtualenv()
|
||||
from mozlint import cli, parser
|
||||
@@ -90,7 +94,6 @@ def lint(command_context, *runargs, **lintargs):
|
||||
)
|
||||
return cli.run(*runargs, **lintargs)
|
||||
|
||||
|
||||
@Command(
|
||||
"eslint",
|
||||
category="devenv",
|
||||
@@ -123,7 +126,7 @@ def lint(command_context, *runargs, **lintargs):
|
||||
nargs=argparse.REMAINDER,
|
||||
help="Extra args that will be forwarded to eslint.",
|
||||
)
|
||||
def eslint(command_context, paths, extra_args=[], **kwargs):
|
||||
def eslint(self, command_context, paths, extra_args=[], **kwargs):
|
||||
command_context._mach_context.commands.dispatch(
|
||||
"lint",
|
||||
command_context._mach_context,
|
||||
@@ -133,14 +136,13 @@ def eslint(command_context, paths, extra_args=[], **kwargs):
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
@Command(
|
||||
"format",
|
||||
category="devenv",
|
||||
description="Format files, alternative to 'lint --fix' ",
|
||||
parser=setup_argument_parser,
|
||||
)
|
||||
def format_files(command_context, paths, extra_args=[], **kwargs):
|
||||
def format_files(self, command_context, paths, extra_args=[], **kwargs):
|
||||
linters = kwargs["linters"]
|
||||
|
||||
if not linters:
|
||||
@@ -159,5 +161,9 @@ def format_files(command_context, paths, extra_args=[], **kwargs):
|
||||
|
||||
kwargs["fix"] = True
|
||||
command_context._mach_context.commands.dispatch(
|
||||
"lint", command_context._mach_context, paths=paths, argv=extra_args, **kwargs
|
||||
"lint",
|
||||
command_context._mach_context,
|
||||
paths=paths,
|
||||
argv=extra_args,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
@@ -12,11 +12,12 @@ import sys
|
||||
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
Command,
|
||||
SubCommand,
|
||||
)
|
||||
|
||||
from mozbuild.base import MozbuildObject
|
||||
from mozbuild.base import MachCommandBase, MozbuildObject
|
||||
|
||||
|
||||
def _get_busted_bugs(payload):
|
||||
@@ -30,12 +31,14 @@ def _get_busted_bugs(payload):
|
||||
return response.json().get("bugs", [])
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class BustedProvider(MachCommandBase):
|
||||
@Command(
|
||||
"busted",
|
||||
category="misc",
|
||||
description="Query known bugs in our tooling, and file new ones.",
|
||||
)
|
||||
def busted_default(command_context):
|
||||
def busted_default(self, command_context):
|
||||
unresolved = _get_busted_bugs({"resolution": "---"})
|
||||
creation_time = datetime.now() - timedelta(days=15)
|
||||
creation_time = creation_time.strftime("%Y-%m-%dT%H-%M-%SZ")
|
||||
@@ -59,7 +62,6 @@ def busted_default(command_context):
|
||||
else:
|
||||
print("No known tooling issues found.")
|
||||
|
||||
|
||||
@SubCommand("busted", "file", description="File a bug for busted tooling.")
|
||||
@CommandArgument(
|
||||
"against",
|
||||
@@ -70,7 +72,7 @@ def busted_default(command_context):
|
||||
"can also run `mach busted file general`."
|
||||
),
|
||||
)
|
||||
def busted_file(command_context, against):
|
||||
def busted_file(self, command_context, against):
|
||||
import webbrowser
|
||||
|
||||
if (
|
||||
@@ -234,6 +236,8 @@ appropriate highlighter.
|
||||
"""
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class PastebinProvider(MachCommandBase):
|
||||
@Command("pastebin", category="misc", description=MACH_PASTEBIN_DESCRIPTION)
|
||||
@CommandArgument(
|
||||
"--list-highlighters",
|
||||
@@ -260,7 +264,9 @@ appropriate highlighter.
|
||||
default=None,
|
||||
help="Path to file for upload to paste.mozilla.org",
|
||||
)
|
||||
def pastebin(command_context, list_highlighters, highlighter, expires, verbose, path):
|
||||
def pastebin(
|
||||
self, command_context, list_highlighters, highlighter, expires, verbose, path
|
||||
):
|
||||
import requests
|
||||
|
||||
def verbose_print(*args, **kwargs):
|
||||
@@ -271,7 +277,7 @@ def pastebin(command_context, list_highlighters, highlighter, expires, verbose,
|
||||
# Show known highlighters and exit.
|
||||
if list_highlighters:
|
||||
lexers = set(EXTENSION_TO_HIGHLIGHTER.values())
|
||||
print("Available lexers:\n - %s" % "\n - ".join(sorted(lexers)))
|
||||
print("Available lexers:\n" " - %s" % "\n - ".join(sorted(lexers)))
|
||||
return 0
|
||||
|
||||
# Get a correct expiry value.
|
||||
@@ -426,25 +432,29 @@ def mozregression_create_parser():
|
||||
return loader.create_parser()
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MozregressionCommand(MachCommandBase):
|
||||
@Command(
|
||||
"mozregression",
|
||||
category="misc",
|
||||
description=("Regression range finder for nightly and inbound builds."),
|
||||
description=("Regression range finder for nightly" " and inbound builds."),
|
||||
parser=mozregression_create_parser,
|
||||
)
|
||||
def run(command_context, **options):
|
||||
def run(self, command_context, **options):
|
||||
command_context.activate_virtualenv()
|
||||
mozregression = PypiBasedTool("mozregression")
|
||||
mozregression.run(**options)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class NodeCommands(MachCommandBase):
|
||||
@Command(
|
||||
"node",
|
||||
category="devenv",
|
||||
description="Run the NodeJS interpreter used for building.",
|
||||
)
|
||||
@CommandArgument("args", nargs=argparse.REMAINDER)
|
||||
def node(command_context, args):
|
||||
def node(self, command_context, args):
|
||||
from mozbuild.nodeutil import find_node_executable
|
||||
|
||||
# Avoid logging the command
|
||||
@@ -458,14 +468,13 @@ def node(command_context, args):
|
||||
ensure_exit_code=False, # Don't throw on non-zero exit code.
|
||||
)
|
||||
|
||||
|
||||
@Command(
|
||||
"npm",
|
||||
category="devenv",
|
||||
description="Run the npm executable from the NodeJS used for building.",
|
||||
)
|
||||
@CommandArgument("args", nargs=argparse.REMAINDER)
|
||||
def npm(command_context, args):
|
||||
def npm(self, command_context, args):
|
||||
from mozbuild.nodeutil import find_npm_executable
|
||||
|
||||
# Avoid logging the command
|
||||
@@ -503,31 +512,30 @@ def logspam_create_parser(subcommand):
|
||||
from functools import partial
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class LogspamCommand(MachCommandBase):
|
||||
@Command(
|
||||
"logspam",
|
||||
category="misc",
|
||||
description=("Warning categorizer for treeherder test runs."),
|
||||
)
|
||||
def logspam(command_context):
|
||||
def logspam(self, command_context):
|
||||
pass
|
||||
|
||||
|
||||
@SubCommand("logspam", "report", parser=partial(logspam_create_parser, "report"))
|
||||
def report(command_context, **options):
|
||||
def report(self, command_context, **options):
|
||||
command_context.activate_virtualenv()
|
||||
logspam = PypiBasedTool("logspam")
|
||||
logspam.run(command="report", **options)
|
||||
|
||||
|
||||
@SubCommand("logspam", "bisect", parser=partial(logspam_create_parser, "bisect"))
|
||||
def bisect(command_context, **options):
|
||||
def bisect(self, command_context, **options):
|
||||
command_context.activate_virtualenv()
|
||||
logspam = PypiBasedTool("logspam")
|
||||
logspam.run(command="bisect", **options)
|
||||
|
||||
|
||||
@SubCommand("logspam", "file", parser=partial(logspam_create_parser, "file"))
|
||||
def create(command_context, **options):
|
||||
def create(self, command_context, **options):
|
||||
command_context.activate_virtualenv()
|
||||
logspam = PypiBasedTool("logspam")
|
||||
logspam.run(command="file", **options)
|
||||
|
||||
@@ -20,10 +20,12 @@ from functools import partial
|
||||
from pprint import pprint
|
||||
|
||||
from mach.registrar import Registrar
|
||||
from mozbuild.base import MachCommandBase
|
||||
from mozbuild.util import memoize
|
||||
from mach.decorators import (
|
||||
Command,
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
SubCommand,
|
||||
)
|
||||
|
||||
@@ -33,8 +35,9 @@ DOC_ROOT = os.path.join(topsrcdir, "docs")
|
||||
BASE_LINK = "http://gecko-docs.mozilla.org-l1.s3-website.us-west-2.amazonaws.com/"
|
||||
|
||||
|
||||
# Helps manage in-tree documentation.
|
||||
|
||||
@CommandProvider
|
||||
class Documentation(MachCommandBase):
|
||||
"""Helps manage in-tree documentation."""
|
||||
|
||||
@Command(
|
||||
"doc",
|
||||
@@ -81,7 +84,9 @@ BASE_LINK = "http://gecko-docs.mozilla.org-l1.s3-website.us-west-2.amazonaws.com
|
||||
help="Serve documentation on the specified host and port, "
|
||||
'default "localhost:5500".',
|
||||
)
|
||||
@CommandArgument("--upload", action="store_true", help="Upload generated files to S3.")
|
||||
@CommandArgument(
|
||||
"--upload", action="store_true", help="Upload generated files to S3."
|
||||
)
|
||||
@CommandArgument(
|
||||
"-j",
|
||||
"--jobs",
|
||||
@@ -89,9 +94,14 @@ BASE_LINK = "http://gecko-docs.mozilla.org-l1.s3-website.us-west-2.amazonaws.com
|
||||
dest="jobs",
|
||||
help="Distribute the build over N processes in parallel.",
|
||||
)
|
||||
@CommandArgument("--write-url", default=None, help="Write S3 Upload URL to text file")
|
||||
@CommandArgument("--verbose", action="store_true", help="Run Sphinx in verbose mode")
|
||||
@CommandArgument(
|
||||
"--write-url", default=None, help="Write S3 Upload URL to text file"
|
||||
)
|
||||
@CommandArgument(
|
||||
"--verbose", action="store_true", help="Run Sphinx in verbose mode"
|
||||
)
|
||||
def build_docs(
|
||||
self,
|
||||
command_context,
|
||||
path=None,
|
||||
fmt="html",
|
||||
@@ -107,7 +117,9 @@ def build_docs(
|
||||
):
|
||||
|
||||
# TODO: Bug 1704891 - move the ESLint setup tools to a shared place.
|
||||
sys.path.append(mozpath.join(command_context.topsrcdir, "tools", "lint", "eslint"))
|
||||
sys.path.append(
|
||||
mozpath.join(command_context.topsrcdir, "tools", "lint", "eslint")
|
||||
)
|
||||
import setup_helper
|
||||
|
||||
setup_helper.set_project_root(command_context.topsrcdir)
|
||||
@@ -122,7 +134,7 @@ def build_docs(
|
||||
os.environ["PATH"] = (
|
||||
mozpath.join(command_context.topsrcdir, "node_modules", ".bin")
|
||||
+ os.pathsep
|
||||
+ _node_path()
|
||||
+ self._node_path()
|
||||
+ os.pathsep
|
||||
+ os.environ["PATH"]
|
||||
)
|
||||
@@ -136,7 +148,7 @@ def build_docs(
|
||||
from livereload import Server
|
||||
from moztreedocs.package import create_tarball
|
||||
|
||||
unique_id = "%s/%s" % (project(), str(uuid.uuid1()))
|
||||
unique_id = "%s/%s" % (self.project(), str(uuid.uuid1()))
|
||||
|
||||
outdir = outdir or os.path.join(command_context.topobjdir, "docs")
|
||||
savedir = os.path.join(outdir, fmt)
|
||||
@@ -144,17 +156,17 @@ def build_docs(
|
||||
path = path or command_context.topsrcdir
|
||||
path = os.path.normpath(os.path.abspath(path))
|
||||
|
||||
docdir = _find_doc_dir(path)
|
||||
docdir = self._find_doc_dir(path)
|
||||
if not docdir:
|
||||
print(_dump_sphinx_backtrace())
|
||||
print(self._dump_sphinx_backtrace())
|
||||
return die(
|
||||
"failed to generate documentation:\n"
|
||||
"%s: could not find docs at this location" % path
|
||||
)
|
||||
|
||||
result = _run_sphinx(docdir, savedir, fmt=fmt, jobs=jobs, verbose=verbose)
|
||||
result = self._run_sphinx(docdir, savedir, fmt=fmt, jobs=jobs, verbose=verbose)
|
||||
if result != 0:
|
||||
print(_dump_sphinx_backtrace())
|
||||
print(self._dump_sphinx_backtrace())
|
||||
return die(
|
||||
"failed to generate documentation:\n"
|
||||
"%s: sphinx return code %d" % (path, result)
|
||||
@@ -172,12 +184,12 @@ def build_docs(
|
||||
print("Generated " + write_url)
|
||||
|
||||
if archive:
|
||||
archive_path = os.path.join(outdir, "%s.tar.gz" % project())
|
||||
archive_path = os.path.join(outdir, "%s.tar.gz" % self.project())
|
||||
create_tarball(archive_path, savedir)
|
||||
print("Archived to %s" % archive_path)
|
||||
|
||||
if upload:
|
||||
_s3_upload(savedir, project(), unique_id, version())
|
||||
self._s3_upload(savedir, self.project(), unique_id, self.version())
|
||||
|
||||
if not serve:
|
||||
index_path = os.path.join(savedir, "index.html")
|
||||
@@ -195,10 +207,10 @@ def build_docs(
|
||||
|
||||
server = Server()
|
||||
|
||||
sphinx_trees = manager().trees or {savedir: docdir}
|
||||
sphinx_trees = self.manager().trees or {savedir: docdir}
|
||||
for _, src in sphinx_trees.items():
|
||||
run_sphinx = partial(
|
||||
_run_sphinx, src, savedir, fmt=fmt, jobs=jobs, verbose=verbose
|
||||
self._run_sphinx, src, savedir, fmt=fmt, jobs=jobs, verbose=verbose
|
||||
)
|
||||
server.watch(src, run_sphinx)
|
||||
server.serve(
|
||||
@@ -208,8 +220,7 @@ def build_docs(
|
||||
open_url_delay=0.1 if auto_open else None,
|
||||
)
|
||||
|
||||
|
||||
def _dump_sphinx_backtrace():
|
||||
def _dump_sphinx_backtrace(self):
|
||||
"""
|
||||
If there is a sphinx dump file, read and return
|
||||
its content.
|
||||
@@ -234,11 +245,12 @@ def _dump_sphinx_backtrace():
|
||||
output += f.read()
|
||||
return output
|
||||
|
||||
|
||||
def _run_sphinx(docdir, savedir, config=None, fmt="html", jobs=None, verbose=None):
|
||||
def _run_sphinx(
|
||||
self, docdir, savedir, config=None, fmt="html", jobs=None, verbose=None
|
||||
):
|
||||
import sphinx.cmd.build
|
||||
|
||||
config = config or manager().conf_py_path
|
||||
config = config or self.manager().conf_py_path
|
||||
# When running sphinx with sentry, it adds significant overhead
|
||||
# and makes the build generation very very very slow
|
||||
# So, disable it to generate the doc faster
|
||||
@@ -260,18 +272,16 @@ def _run_sphinx(docdir, savedir, config=None, fmt="html", jobs=None, verbose=Non
|
||||
print(args)
|
||||
return sphinx.cmd.build.build_main(args)
|
||||
|
||||
|
||||
def manager():
|
||||
def manager(self):
|
||||
from moztreedocs import manager
|
||||
|
||||
return manager
|
||||
|
||||
|
||||
@memoize
|
||||
def _read_project_properties():
|
||||
def _read_project_properties(self):
|
||||
import imp
|
||||
|
||||
path = os.path.normpath(manager().conf_py_path)
|
||||
path = os.path.normpath(self.manager().conf_py_path)
|
||||
with open(path, "r") as fh:
|
||||
conf = imp.load_module("doc_conf", fh, path, (".py", "r", imp.PY_SOURCE))
|
||||
|
||||
@@ -283,24 +293,20 @@ def _read_project_properties():
|
||||
|
||||
return {"project": project, "version": getattr(conf, "version", None)}
|
||||
|
||||
def project(self):
|
||||
return self._read_project_properties()["project"]
|
||||
|
||||
def project():
|
||||
return _read_project_properties()["project"]
|
||||
def version(self):
|
||||
return self._read_project_properties()["version"]
|
||||
|
||||
|
||||
def version():
|
||||
return _read_project_properties()["version"]
|
||||
|
||||
|
||||
def _node_path():
|
||||
def _node_path(self):
|
||||
from mozbuild.nodeutil import find_node_executable
|
||||
|
||||
node, _ = find_node_executable()
|
||||
|
||||
return os.path.dirname(node)
|
||||
|
||||
|
||||
def _find_doc_dir(path):
|
||||
def _find_doc_dir(self, path):
|
||||
if os.path.isfile(path):
|
||||
return
|
||||
|
||||
@@ -313,8 +319,7 @@ def _find_doc_dir(path):
|
||||
if os.path.isdir(p):
|
||||
return p
|
||||
|
||||
|
||||
def _s3_upload(root, project, unique_id, version=None):
|
||||
def _s3_upload(self, root, project, unique_id, version=None):
|
||||
from moztreedocs.package import distribution_files
|
||||
from moztreedocs.upload import s3_upload, s3_set_redirects
|
||||
|
||||
@@ -373,13 +378,12 @@ def _s3_upload(root, project, unique_id, version=None):
|
||||
unique_link = BASE_LINK + unique_id + "/index.html"
|
||||
print("Uploaded documentation can be accessed here " + unique_link)
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"doc",
|
||||
"mach-telemetry",
|
||||
description="Generate documentation from Glean metrics.yaml files",
|
||||
)
|
||||
def generate_telemetry_docs(command_context):
|
||||
def generate_telemetry_docs(self, command_context):
|
||||
args = [
|
||||
sys.executable,
|
||||
"-m" "glean_parser",
|
||||
@@ -397,7 +401,10 @@ def generate_telemetry_docs(command_context):
|
||||
if handler.metrics_path is not None
|
||||
]
|
||||
args.extend(
|
||||
[os.path.join(command_context.topsrcdir, path) for path in set(metrics_paths)]
|
||||
[
|
||||
os.path.join(command_context.topsrcdir, path)
|
||||
for path in set(metrics_paths)
|
||||
]
|
||||
)
|
||||
subprocess.check_call(args)
|
||||
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import mozfile
|
||||
from mach.decorators import Command, CommandArgument
|
||||
from mach.decorators import CommandProvider, Command, CommandArgument
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class PhabricatorCommandProvider(MachCommandBase):
|
||||
@Command(
|
||||
"install-moz-phab",
|
||||
category="misc",
|
||||
@@ -19,7 +22,7 @@ from mach.decorators import Command, CommandArgument
|
||||
action="store_true",
|
||||
help="Force installation even if already installed.",
|
||||
)
|
||||
def install_moz_phab(command_context, force=False):
|
||||
def install_moz_phab(self, command_context, force=False):
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
|
||||
@@ -9,7 +9,9 @@ from distutils.version import StrictVersion
|
||||
from mach.decorators import (
|
||||
Command,
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
)
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
|
||||
def is_osx_10_10_or_greater(cls):
|
||||
@@ -19,7 +21,8 @@ def is_osx_10_10_or_greater(cls):
|
||||
return release and StrictVersion(release) >= StrictVersion("10.10")
|
||||
|
||||
|
||||
# Get system power consumption and related measurements.
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command(
|
||||
"power",
|
||||
category="misc",
|
||||
@@ -35,7 +38,7 @@ def is_osx_10_10_or_greater(cls):
|
||||
default=30000,
|
||||
help="The sample period, measured in milliseconds. Defaults to 30000.",
|
||||
)
|
||||
def power(command_context, interval):
|
||||
def power(self, command_context, interval):
|
||||
"""
|
||||
Get system power consumption and related measurements.
|
||||
"""
|
||||
|
||||
@@ -9,12 +9,13 @@ import os
|
||||
import sys
|
||||
|
||||
from mach.decorators import (
|
||||
CommandProvider,
|
||||
Command,
|
||||
SettingsProvider,
|
||||
SubCommand,
|
||||
)
|
||||
from mozboot.util import get_state_dir
|
||||
from mozbuild.base import BuildEnvironmentNotFoundException
|
||||
from mozbuild.base import BuildEnvironmentNotFoundException, MachCommandBase
|
||||
from mozbuild.util import memoize
|
||||
|
||||
|
||||
@@ -67,14 +68,15 @@ class TryConfig:
|
||||
]
|
||||
|
||||
|
||||
def init(command_context):
|
||||
@CommandProvider
|
||||
class TrySelect(MachCommandBase):
|
||||
def init(self, command_context):
|
||||
from tryselect import push
|
||||
|
||||
push.MAX_HISTORY = command_context._mach_context.settings["try"]["maxhistory"]
|
||||
|
||||
|
||||
@memoize
|
||||
def presets(command_context):
|
||||
def presets(self, command_context):
|
||||
from tryselect.preset import MergedHandler
|
||||
|
||||
# Create our handler using both local and in-tree presets. The first
|
||||
@@ -93,9 +95,8 @@ def presets(command_context):
|
||||
|
||||
return MergedHandler(*preset_paths)
|
||||
|
||||
|
||||
def handle_presets(
|
||||
command_context, preset_action=None, save=None, preset=None, **kwargs
|
||||
self, command_context, preset_action=None, save=None, preset=None, **kwargs
|
||||
):
|
||||
"""Handle preset related arguments.
|
||||
|
||||
@@ -105,9 +106,9 @@ def handle_presets(
|
||||
"""
|
||||
from tryselect.util.dicttools import merge
|
||||
|
||||
user_presets = presets(command_context).handlers[0]
|
||||
user_presets = self.presets(command_context).handlers[0]
|
||||
if preset_action == "list":
|
||||
presets(command_context).list()
|
||||
self.presets(command_context).list()
|
||||
sys.exit()
|
||||
|
||||
if preset_action == "edit":
|
||||
@@ -132,13 +133,13 @@ def handle_presets(
|
||||
sys.exit()
|
||||
|
||||
if preset:
|
||||
if preset not in presets(command_context):
|
||||
if preset not in self.presets(command_context):
|
||||
command_context._mach_context.parser.error(
|
||||
"preset '{}' does not exist".format(preset)
|
||||
)
|
||||
|
||||
name = preset
|
||||
preset = presets(command_context)[name]
|
||||
preset = self.presets(command_context)[name]
|
||||
selector = preset.pop("selector")
|
||||
preset.pop("description", None) # description isn't used by any selectors
|
||||
|
||||
@@ -147,7 +148,9 @@ def handle_presets(
|
||||
elif subcommand != selector:
|
||||
print(
|
||||
"error: preset '{}' exists for a different selector "
|
||||
"(did you mean to run 'mach try {}' instead?)".format(name, selector)
|
||||
"(did you mean to run 'mach try {}' instead?)".format(
|
||||
name, selector
|
||||
)
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
@@ -165,8 +168,7 @@ def handle_presets(
|
||||
|
||||
return kwargs
|
||||
|
||||
|
||||
def handle_try_config(command_context, **kwargs):
|
||||
def handle_try_config(self, command_context, **kwargs):
|
||||
from tryselect.util.dicttools import merge
|
||||
|
||||
to_validate = []
|
||||
@@ -186,12 +188,11 @@ def handle_try_config(command_context, **kwargs):
|
||||
cls.validate(**kwargs)
|
||||
return kwargs
|
||||
|
||||
|
||||
def run(command_context, **kwargs):
|
||||
kwargs = handle_presets(command_context, **kwargs)
|
||||
def run(self, command_context, **kwargs):
|
||||
kwargs = self.handle_presets(command_context, **kwargs)
|
||||
|
||||
if command_context._mach_context.handler.parser.task_configs:
|
||||
kwargs = handle_try_config(command_context, **kwargs)
|
||||
kwargs = self.handle_try_config(command_context, **kwargs)
|
||||
|
||||
mod = importlib.import_module(
|
||||
"tryselect.selectors.{}".format(
|
||||
@@ -200,14 +201,13 @@ def run(command_context, **kwargs):
|
||||
)
|
||||
return mod.run(**kwargs)
|
||||
|
||||
|
||||
@Command(
|
||||
"try",
|
||||
category="ci",
|
||||
description="Push selected tasks to the try server",
|
||||
parser=generic_parser,
|
||||
)
|
||||
def try_default(command_context, argv=None, **kwargs):
|
||||
def try_default(self, command_context, argv=None, **kwargs):
|
||||
"""Push selected tests to the try server.
|
||||
|
||||
The |mach try| command is a frontend for scheduling tasks to
|
||||
@@ -219,32 +219,31 @@ def try_default(command_context, argv=None, **kwargs):
|
||||
default. Run |mach try auto --help| for more information on
|
||||
scheduling with the `auto` selector.
|
||||
"""
|
||||
init(command_context)
|
||||
self.init(command_context)
|
||||
subcommand = command_context._mach_context.handler.subcommand
|
||||
# We do special handling of presets here so that `./mach try --preset foo`
|
||||
# works no matter what subcommand 'foo' was saved with.
|
||||
preset = kwargs["preset"]
|
||||
if preset:
|
||||
if preset not in presets(command_context):
|
||||
if preset not in self.presets(command_context):
|
||||
command_context._mach_context.handler.parser.error(
|
||||
"preset '{}' does not exist".format(preset)
|
||||
)
|
||||
|
||||
subcommand = presets(command_context)[preset]["selector"]
|
||||
subcommand = self.presets(command_context)[preset]["selector"]
|
||||
|
||||
sub = subcommand or command_context._mach_context.settings["try"]["default"]
|
||||
return command_context._mach_context.commands.dispatch(
|
||||
"try", command_context._mach_context, subcommand=sub, argv=argv, **kwargs
|
||||
)
|
||||
|
||||
|
||||
@SubCommand(
|
||||
"try",
|
||||
"fuzzy",
|
||||
description="Select tasks on try using a fuzzy finder",
|
||||
parser=get_parser("fuzzy"),
|
||||
)
|
||||
def try_fuzzy(command_context, **kwargs):
|
||||
def try_fuzzy(self, command_context, **kwargs):
|
||||
"""Select which tasks to run with a fuzzy finding interface (fzf).
|
||||
|
||||
When entering the fzf interface you'll be confronted by two panes. The
|
||||
@@ -319,7 +318,7 @@ def try_fuzzy(command_context, **kwargs):
|
||||
For more detailed documentation, please see:
|
||||
https://firefox-source-docs.mozilla.org/tools/try/selectors/fuzzy.html
|
||||
"""
|
||||
init(command_context)
|
||||
self.init(command_context)
|
||||
if kwargs.pop("interactive"):
|
||||
kwargs["query"].append("INTERACTIVE")
|
||||
|
||||
@@ -333,23 +332,22 @@ def try_fuzzy(command_context, **kwargs):
|
||||
kwargs_copy = kwargs.copy()
|
||||
kwargs_copy["push"] = False
|
||||
kwargs_copy["save"] = None
|
||||
kwargs["query"] = run(command_context, save_query=True, **kwargs_copy)
|
||||
kwargs["query"] = self.run(command_context, save_query=True, **kwargs_copy)
|
||||
if not kwargs["query"]:
|
||||
return
|
||||
|
||||
if kwargs.get("paths"):
|
||||
kwargs["test_paths"] = kwargs["paths"]
|
||||
|
||||
return run(command_context, **kwargs)
|
||||
|
||||
return self.run(command_context, **kwargs)
|
||||
|
||||
@SubCommand(
|
||||
"try",
|
||||
"chooser",
|
||||
description="Schedule tasks by selecting them from a web interface.",
|
||||
description="Schedule tasks by selecting them from a web " "interface.",
|
||||
parser=get_parser("chooser"),
|
||||
)
|
||||
def try_chooser(command_context, **kwargs):
|
||||
def try_chooser(self, command_context, **kwargs):
|
||||
"""Push tasks selected from a web interface to try.
|
||||
|
||||
This selector will build the taskgraph and spin up a dynamically
|
||||
@@ -357,15 +355,14 @@ def try_chooser(command_context, **kwargs):
|
||||
has been made, pressing the 'Push' button will automatically push the
|
||||
selection to try.
|
||||
"""
|
||||
init(command_context)
|
||||
self.init(command_context)
|
||||
command_context.activate_virtualenv()
|
||||
path = os.path.join(
|
||||
"tools", "tryselect", "selectors", "chooser", "requirements.txt"
|
||||
)
|
||||
command_context.virtualenv_manager.install_pip_requirements(path, quiet=True)
|
||||
|
||||
return run(command_context, **kwargs)
|
||||
|
||||
return self.run(command_context, **kwargs)
|
||||
|
||||
@SubCommand(
|
||||
"try",
|
||||
@@ -375,21 +372,19 @@ def try_chooser(command_context, **kwargs):
|
||||
"selector is EXPERIMENTAL.",
|
||||
parser=get_parser("auto"),
|
||||
)
|
||||
def try_auto(command_context, **kwargs):
|
||||
init(command_context)
|
||||
return run(command_context, **kwargs)
|
||||
|
||||
def try_auto(self, command_context, **kwargs):
|
||||
self.init(command_context)
|
||||
return self.run(command_context, **kwargs)
|
||||
|
||||
@SubCommand(
|
||||
"try",
|
||||
"again",
|
||||
description="Schedule a previously generated (non try syntax) push again.",
|
||||
description="Schedule a previously generated (non try syntax) " "push again.",
|
||||
parser=get_parser("again"),
|
||||
)
|
||||
def try_again(command_context, **kwargs):
|
||||
init(command_context)
|
||||
return run(command_context, **kwargs)
|
||||
|
||||
def try_again(self, command_context, **kwargs):
|
||||
self.init(command_context)
|
||||
return self.run(command_context, **kwargs)
|
||||
|
||||
@SubCommand(
|
||||
"try",
|
||||
@@ -397,7 +392,7 @@ def try_again(command_context, **kwargs):
|
||||
description="Push to try without scheduling any tasks.",
|
||||
parser=get_parser("empty"),
|
||||
)
|
||||
def try_empty(command_context, **kwargs):
|
||||
def try_empty(self, command_context, **kwargs):
|
||||
"""Push to try, running no builds or tests
|
||||
|
||||
This selector does not prompt you to run anything, it just pushes
|
||||
@@ -406,9 +401,8 @@ def try_empty(command_context, **kwargs):
|
||||
via Treeherder's Add New Jobs feature, located in the per-push
|
||||
menu.
|
||||
"""
|
||||
init(command_context)
|
||||
return run(command_context, **kwargs)
|
||||
|
||||
self.init(command_context)
|
||||
return self.run(command_context, **kwargs)
|
||||
|
||||
@SubCommand(
|
||||
"try",
|
||||
@@ -416,7 +410,7 @@ def try_empty(command_context, **kwargs):
|
||||
description="Select tasks on try using try syntax",
|
||||
parser=get_parser("syntax"),
|
||||
)
|
||||
def try_syntax(command_context, **kwargs):
|
||||
def try_syntax(self, command_context, **kwargs):
|
||||
"""Push the current tree to try, with the specified syntax.
|
||||
|
||||
Build options, platforms and regression tests may be selected
|
||||
@@ -454,7 +448,7 @@ def try_syntax(command_context, **kwargs):
|
||||
(installable from mach vcs-setup).
|
||||
|
||||
"""
|
||||
init(command_context)
|
||||
self.init(command_context)
|
||||
try:
|
||||
if command_context.substs.get("MOZ_ARTIFACT_BUILDS"):
|
||||
kwargs["local_artifact_build"] = True
|
||||
@@ -469,8 +463,7 @@ def try_syntax(command_context, **kwargs):
|
||||
print(CONFIG_ENVIRONMENT_NOT_FOUND)
|
||||
sys.exit(1)
|
||||
|
||||
return run(command_context, **kwargs)
|
||||
|
||||
return self.run(command_context, **kwargs)
|
||||
|
||||
@SubCommand(
|
||||
"try",
|
||||
@@ -478,11 +471,10 @@ def try_syntax(command_context, **kwargs):
|
||||
description="Select tasks on try using coverage data",
|
||||
parser=get_parser("coverage"),
|
||||
)
|
||||
def try_coverage(command_context, **kwargs):
|
||||
def try_coverage(self, command_context, **kwargs):
|
||||
"""Select which tasks to use using coverage data."""
|
||||
init(command_context)
|
||||
return run(command_context, **kwargs)
|
||||
|
||||
self.init(command_context)
|
||||
return self.run(command_context, **kwargs)
|
||||
|
||||
@SubCommand(
|
||||
"try",
|
||||
@@ -490,11 +482,10 @@ def try_coverage(command_context, **kwargs):
|
||||
description="Push the current tree to try, configured for a staging release.",
|
||||
parser=get_parser("release"),
|
||||
)
|
||||
def try_release(command_context, **kwargs):
|
||||
def try_release(self, command_context, **kwargs):
|
||||
"""Push the current tree to try, configured for a staging release."""
|
||||
init(command_context)
|
||||
return run(command_context, **kwargs)
|
||||
|
||||
self.init(command_context)
|
||||
return self.run(command_context, **kwargs)
|
||||
|
||||
@SubCommand(
|
||||
"try",
|
||||
@@ -502,10 +493,10 @@ def try_release(command_context, **kwargs):
|
||||
description="Run scriptworker tasks against a recent release.",
|
||||
parser=get_parser("scriptworker"),
|
||||
)
|
||||
def try_scriptworker(command_context, **kwargs):
|
||||
def try_scriptworker(self, command_context, **kwargs):
|
||||
"""Run scriptworker tasks against a recent release.
|
||||
|
||||
Requires VPN and shipit access.
|
||||
"""
|
||||
init(command_context)
|
||||
return run(command_context, **kwargs)
|
||||
self.init(command_context)
|
||||
return self.run(command_context, **kwargs)
|
||||
|
||||
@@ -13,9 +13,12 @@ import logging
|
||||
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
import mozpack.path as mozpath
|
||||
|
||||
import json
|
||||
@@ -43,24 +46,32 @@ PR_REPOSITORIES = {
|
||||
}
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class PullRequestImporter(MachCommandBase):
|
||||
@Command(
|
||||
"import-pr",
|
||||
category="misc",
|
||||
description="Import a pull request from Github to the local repo.",
|
||||
)
|
||||
@CommandArgument("-b", "--bug-number", help="Bug number to use in the commit messages.")
|
||||
@CommandArgument(
|
||||
"-b", "--bug-number", help="Bug number to use in the commit messages."
|
||||
)
|
||||
@CommandArgument(
|
||||
"-t",
|
||||
"--bugzilla-token",
|
||||
help="Bugzilla API token used to file a new bug if no bug number is provided.",
|
||||
help="Bugzilla API token used to file a new bug if no bug number is "
|
||||
"provided.",
|
||||
)
|
||||
@CommandArgument(
|
||||
"-r", "--reviewer", help="Reviewer nick to apply to commit messages."
|
||||
)
|
||||
@CommandArgument("-r", "--reviewer", help="Reviewer nick to apply to commit messages.")
|
||||
@CommandArgument(
|
||||
"pull_request",
|
||||
help="URL to the pull request to import (e.g. "
|
||||
"https://github.com/servo/webrender/pull/3665).",
|
||||
)
|
||||
def import_pr(
|
||||
self,
|
||||
command_context,
|
||||
pull_request,
|
||||
bug_number=None,
|
||||
@@ -122,7 +133,7 @@ def import_pr(
|
||||
"be added to commit messages.",
|
||||
)
|
||||
else:
|
||||
bug_number = _file_bug(
|
||||
bug_number = self._file_bug(
|
||||
command_context, bugzilla_token, repository, pr_number
|
||||
)
|
||||
elif bugzilla_token is not None:
|
||||
@@ -136,7 +147,9 @@ def import_pr(
|
||||
|
||||
pr_patch = requests.get(pull_request + ".patch")
|
||||
pr_patch.raise_for_status()
|
||||
for patch in _split_patches(pr_patch.content, bug_number, pull_request, reviewer):
|
||||
for patch in self._split_patches(
|
||||
pr_patch.content, bug_number, pull_request, reviewer
|
||||
):
|
||||
command_context.log(
|
||||
logging.INFO,
|
||||
"commit_msg",
|
||||
@@ -160,10 +173,11 @@ def import_pr(
|
||||
command_context.repository.commit(
|
||||
patch["commit_msg"], patch["author"], patch["date"], [target_dir]
|
||||
)
|
||||
command_context.log(logging.INFO, "commit_pass", {}, "Committed successfully.")
|
||||
command_context.log(
|
||||
logging.INFO, "commit_pass", {}, "Committed successfully."
|
||||
)
|
||||
|
||||
|
||||
def _file_bug(command_context, token, repo, pr_number):
|
||||
def _file_bug(self, command_context, token, repo, pr_number):
|
||||
import requests
|
||||
|
||||
bug = requests.post(
|
||||
@@ -171,7 +185,8 @@ def _file_bug(command_context, token, repo, pr_number):
|
||||
json={
|
||||
"product": repo["bugzilla_product"],
|
||||
"component": repo["bugzilla_component"],
|
||||
"summary": "Land %s#%s in mozilla-central" % (repo["github"], pr_number),
|
||||
"summary": "Land %s#%s in mozilla-central"
|
||||
% (repo["github"], pr_number),
|
||||
"version": "unspecified",
|
||||
},
|
||||
)
|
||||
@@ -183,8 +198,7 @@ def _file_bug(command_context, token, repo, pr_number):
|
||||
)
|
||||
return bugnumber
|
||||
|
||||
|
||||
def _split_patches(patchfile, bug_number, pull_request, reviewer):
|
||||
def _split_patches(self, patchfile, bug_number, pull_request, reviewer):
|
||||
INITIAL = 0
|
||||
HEADERS = 1
|
||||
STAT_AND_DIFF = 2
|
||||
@@ -201,17 +215,16 @@ def _split_patches(patchfile, bug_number, pull_request, reviewer):
|
||||
state = STAT_AND_DIFF
|
||||
elif state == STAT_AND_DIFF:
|
||||
if line.startswith(b"From "):
|
||||
yield _parse_patch(patch, bug_number, pull_request, reviewer)
|
||||
yield self._parse_patch(patch, bug_number, pull_request, reviewer)
|
||||
patch = b""
|
||||
state = HEADERS
|
||||
else:
|
||||
patch += line + b"\n"
|
||||
if len(patch) > 0:
|
||||
yield _parse_patch(patch, bug_number, pull_request, reviewer)
|
||||
yield self._parse_patch(patch, bug_number, pull_request, reviewer)
|
||||
return
|
||||
|
||||
|
||||
def _parse_patch(patch, bug_number, pull_request, reviewer):
|
||||
def _parse_patch(self, patch, bug_number, pull_request, reviewer):
|
||||
import email
|
||||
from email import (
|
||||
header,
|
||||
|
||||
Reference in New Issue
Block a user