183 lines
5.4 KiB
Python
183 lines
5.4 KiB
Python
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
import multiprocessing
|
|
import os
|
|
import time
|
|
import webbrowser
|
|
from dataclasses import dataclass
|
|
from threading import Timer
|
|
|
|
from gecko_taskgraph.target_tasks import filter_by_uncommon_try_tasks
|
|
|
|
from tryselect.cli import BaseTryParser
|
|
from tryselect.push import (
|
|
check_working_directory,
|
|
generate_try_task_config,
|
|
push_to_try,
|
|
)
|
|
from tryselect.tasks import generate_tasks
|
|
|
|
here = os.path.abspath(os.path.dirname(__file__))
|
|
|
|
|
|
@dataclass
|
|
class ChooserConfig:
|
|
use_artifact: bool = False
|
|
pernosco_active: bool = False
|
|
rebuild_multiplier: int = 1
|
|
priority_preset: bool = False
|
|
|
|
|
|
class ChooserParser(BaseTryParser):
|
|
name = "chooser"
|
|
arguments = []
|
|
common_groups = ["push", "task"]
|
|
task_configs = [
|
|
"artifact",
|
|
"browsertime",
|
|
"chemspill-prio",
|
|
"disable-pgo",
|
|
"env",
|
|
"existing-tasks",
|
|
"extensions",
|
|
"gecko-profile",
|
|
"path",
|
|
"pernosco",
|
|
"rebuild",
|
|
"worker-overrides",
|
|
]
|
|
|
|
|
|
def run(
|
|
metrics,
|
|
update=False,
|
|
query=None,
|
|
try_config_params=None,
|
|
full=False,
|
|
parameters=None,
|
|
save=False,
|
|
preset=None,
|
|
mod_presets=False,
|
|
stage_changes=False,
|
|
dry_run=False,
|
|
message="{msg}",
|
|
closed_tree=False,
|
|
push_to_vcs=False,
|
|
):
|
|
from .app import create_application
|
|
|
|
push = not stage_changes and not dry_run
|
|
check_working_directory(push)
|
|
|
|
metrics.mach_try.taskgraph_generation_duration.start()
|
|
tg = generate_tasks(parameters, full)
|
|
metrics.mach_try.taskgraph_generation_duration.stop()
|
|
|
|
metrics.mach_try.task_filtering_duration.start()
|
|
# Remove tasks that are not to be shown unless `--full` is specified.
|
|
if not full:
|
|
excluded_tasks = [
|
|
label
|
|
for label in tg.tasks.keys()
|
|
if not filter_by_uncommon_try_tasks(label)
|
|
]
|
|
for task in excluded_tasks:
|
|
tg.tasks.pop(task)
|
|
|
|
metrics.mach_try.task_filtering_duration.stop()
|
|
|
|
queue = multiprocessing.Queue()
|
|
|
|
try_config_params = try_config_params or {}
|
|
try_task_config = try_config_params.setdefault("try_task_config", {})
|
|
rebuild_multiplier, priority_preset = resolve_large_push_context(try_task_config)
|
|
config = ChooserConfig(
|
|
use_artifact=bool(try_task_config.get("use-artifact-builds")),
|
|
pernosco_active=bool(try_task_config.get("pernosco")),
|
|
rebuild_multiplier=rebuild_multiplier,
|
|
priority_preset=priority_preset,
|
|
)
|
|
|
|
if os.environ.get("WERKZEUG_RUN_MAIN") == "true":
|
|
# we are in the reloader process, don't open the browser or do any try stuff
|
|
app = create_application(tg, queue, config)
|
|
app.run()
|
|
return
|
|
|
|
# give app a second to start before opening the browser
|
|
url = "http://127.0.0.1:5000"
|
|
Timer(1, lambda: webbrowser.open(url)).start()
|
|
print(f"Starting trychooser on {url}")
|
|
process = multiprocessing.Process(
|
|
target=create_and_run_application,
|
|
args=(tg, queue, config),
|
|
)
|
|
process.start()
|
|
|
|
metrics.mach_try.interactive_duration.start()
|
|
result = queue.get()
|
|
metrics.mach_try.interactive_duration.stop()
|
|
|
|
# Allow the close page to render before terminating the process.
|
|
time.sleep(1)
|
|
process.terminate()
|
|
|
|
selected = result["tasks"]
|
|
use_artifact = result["use_artifact"]
|
|
if not selected:
|
|
print("no tasks selected")
|
|
return
|
|
|
|
resolve_artifact_state(try_task_config, config.use_artifact, use_artifact)
|
|
|
|
msg = f"Try Chooser Enhanced ({len(selected)} tasks selected)"
|
|
return push_to_try(
|
|
"chooser",
|
|
message.format(msg=msg),
|
|
metrics,
|
|
try_task_config=generate_try_task_config(
|
|
"chooser", selected, params=try_config_params
|
|
),
|
|
stage_changes=stage_changes,
|
|
dry_run=dry_run,
|
|
closed_tree=closed_tree,
|
|
push_to_vcs=push_to_vcs,
|
|
)
|
|
|
|
|
|
def resolve_large_push_context(try_task_config):
|
|
"""Match push.generate_try_task_config's math for the chooser warning.
|
|
|
|
Returns (rebuild_multiplier, priority_preset). rebuild_multiplier is the
|
|
per-label rebuild count, defaulting to 1 when ``rebuild`` is absent,
|
|
mirroring push.py. priority_preset is True when an explicit priority was
|
|
passed in, since push.py skips the deprioritization prompt in that case.
|
|
"""
|
|
rebuild_multiplier = try_task_config.get("rebuild", 1)
|
|
priority_preset = "priority" in try_task_config
|
|
return rebuild_multiplier, priority_preset
|
|
|
|
|
|
def resolve_artifact_state(try_task_config, initial_use_artifact, use_artifact):
|
|
if use_artifact:
|
|
try_task_config["use-artifact-builds"] = True
|
|
try_task_config["disable-pgo"] = True
|
|
return
|
|
|
|
try_task_config.pop("use-artifact-builds", None)
|
|
# --artifact (task_config.Artifact) sets disable-pgo as a consequence
|
|
# of enabling artifact builds. If we entered the chooser with artifact
|
|
# on and the user toggled it off, clear disable-pgo too. An explicit
|
|
# --disable-pgo run leaves initial_use_artifact=False and is preserved.
|
|
if initial_use_artifact:
|
|
try_task_config.pop("disable-pgo", None)
|
|
|
|
|
|
def create_and_run_application(tg, queue: multiprocessing.Queue, config=None):
|
|
from .app import create_application
|
|
|
|
app = create_application(tg, queue, config)
|
|
app.run()
|