316 lines
11 KiB
Python
316 lines
11 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/.
|
|
"""
|
|
Transform the repackage task into an actual task description.
|
|
"""
|
|
|
|
|
|
import copy
|
|
|
|
from taskgraph.transforms.base import TransformSequence
|
|
from taskgraph.util.dependencies import get_primary_dependency
|
|
from taskgraph.util.schema import Schema, optionally_keyed_by, resolve_keyed_by
|
|
from taskgraph.util.taskcluster import get_artifact_prefix
|
|
from voluptuous import Optional, Required
|
|
|
|
from gecko_taskgraph.transforms.repackage import (
|
|
PACKAGE_FORMATS as PACKAGE_FORMATS_VANILLA,
|
|
)
|
|
from gecko_taskgraph.transforms.task import task_description_schema
|
|
from gecko_taskgraph.util.attributes import copy_attributes_from_dependent_job
|
|
from gecko_taskgraph.util.partners import get_partner_config_by_kind
|
|
from gecko_taskgraph.util.platforms import archive_format, executable_extension
|
|
from gecko_taskgraph.util.workertypes import worker_type_implementation
|
|
|
|
# When repacking the stub installer we need to pass a zip file and package name to the
|
|
# repackage task. This is not needed for vanilla stub but analogous to the full installer.
|
|
PACKAGE_FORMATS = copy.deepcopy(PACKAGE_FORMATS_VANILLA)
|
|
PACKAGE_FORMATS["installer-stub"]["inputs"]["package"] = "target-stub{archive_format}"
|
|
PACKAGE_FORMATS["installer-stub"]["args"].extend(["--package-name", "{package-name}"])
|
|
|
|
packaging_description_schema = Schema(
|
|
{
|
|
# unique label to describe this repackaging task
|
|
Optional("label"): str,
|
|
# Routes specific to this task, if defined
|
|
Optional("routes"): [str],
|
|
# passed through directly to the job description
|
|
Optional("extra"): task_description_schema["extra"],
|
|
# Shipping product and phase
|
|
Optional("shipping-product"): task_description_schema["shipping-product"],
|
|
Optional("shipping-phase"): task_description_schema["shipping-phase"],
|
|
Required("package-formats"): optionally_keyed_by(
|
|
"build-platform", "build-type", [str]
|
|
),
|
|
# All l10n jobs use mozharness
|
|
Required("mozharness"): {
|
|
# Config files passed to the mozharness script
|
|
Required("config"): optionally_keyed_by("build-platform", [str]),
|
|
# Additional paths to look for mozharness configs in. These should be
|
|
# relative to the base of the source checkout
|
|
Optional("config-paths"): [str],
|
|
# if true, perform a checkout of a comm-central based branch inside the
|
|
# gecko checkout
|
|
Optional("comm-checkout"): bool,
|
|
},
|
|
# Override the default priority for the project
|
|
Optional("priority"): task_description_schema["priority"],
|
|
Optional("task-from"): task_description_schema["task-from"],
|
|
Optional("attributes"): task_description_schema["attributes"],
|
|
Optional("dependencies"): task_description_schema["dependencies"],
|
|
}
|
|
)
|
|
|
|
transforms = TransformSequence()
|
|
|
|
|
|
@transforms.add
|
|
def remove_name(config, jobs):
|
|
for job in jobs:
|
|
if "name" in job:
|
|
del job["name"]
|
|
yield job
|
|
|
|
|
|
transforms.add_validate(packaging_description_schema)
|
|
|
|
|
|
@transforms.add
|
|
def copy_in_useful_magic(config, jobs):
|
|
"""Copy attributes from upstream task to be used for keyed configuration."""
|
|
for job in jobs:
|
|
dep = get_primary_dependency(config, job)
|
|
assert dep
|
|
|
|
job["build-platform"] = dep.attributes.get("build_platform")
|
|
yield job
|
|
|
|
|
|
@transforms.add
|
|
def handle_keyed_by(config, jobs):
|
|
"""Resolve fields that can be keyed by platform, etc."""
|
|
fields = [
|
|
"mozharness.config",
|
|
"package-formats",
|
|
]
|
|
for job in jobs:
|
|
job = copy.deepcopy(job) # don't overwrite dict values here
|
|
for field in fields:
|
|
resolve_keyed_by(item=job, field=field, item_name="?")
|
|
yield job
|
|
|
|
|
|
@transforms.add
|
|
def make_repackage_description(config, jobs):
|
|
for job in jobs:
|
|
dep_job = get_primary_dependency(config, job)
|
|
assert dep_job
|
|
|
|
label = job.get("label", dep_job.label.replace("signing-", "repackage-"))
|
|
job["label"] = label
|
|
|
|
yield job
|
|
|
|
|
|
@transforms.add
|
|
def make_job_description(config, jobs):
|
|
for job in jobs:
|
|
dep_job = get_primary_dependency(config, job)
|
|
assert dep_job
|
|
|
|
attributes = copy_attributes_from_dependent_job(dep_job)
|
|
build_platform = attributes["build_platform"]
|
|
|
|
if job["build-platform"].startswith("win"):
|
|
if dep_job.kind.endswith("signing"):
|
|
continue
|
|
if job["build-platform"].startswith("macosx"):
|
|
if dep_job.kind.endswith("repack"):
|
|
continue
|
|
dependencies = {dep_job.attributes.get("kind"): dep_job.label}
|
|
dependencies.update(dep_job.dependencies)
|
|
|
|
signing_task = None
|
|
for dependency in dependencies.keys():
|
|
if build_platform.startswith("macosx") and dependency.endswith("signing"):
|
|
signing_task = dependency
|
|
elif build_platform.startswith("win") and dependency.endswith("repack"):
|
|
signing_task = dependency
|
|
|
|
attributes["repackage_type"] = "repackage"
|
|
|
|
repack_id = job["extra"]["repack_id"]
|
|
|
|
partner_config = get_partner_config_by_kind(config, config.kind)
|
|
partner, subpartner, _ = repack_id.split("/")
|
|
repack_stub_installer = partner_config[partner][subpartner].get(
|
|
"repack_stub_installer"
|
|
)
|
|
if build_platform.startswith("win32") and repack_stub_installer:
|
|
job["package-formats"].append("installer-stub")
|
|
|
|
repackage_config = []
|
|
for format in job.get("package-formats"):
|
|
command = copy.deepcopy(PACKAGE_FORMATS[format])
|
|
substs = {
|
|
"archive_format": archive_format(build_platform),
|
|
"executable_extension": executable_extension(build_platform),
|
|
}
|
|
command["inputs"] = {
|
|
name: filename.format(**substs)
|
|
for name, filename in command["inputs"].items()
|
|
}
|
|
repackage_config.append(command)
|
|
|
|
run = job.get("mozharness", {})
|
|
run.update(
|
|
{
|
|
"using": "mozharness",
|
|
"script": "mozharness/scripts/repackage.py",
|
|
"job-script": "taskcluster/scripts/builder/repackage.sh",
|
|
"actions": ["setup", "repackage"],
|
|
"extra-config": {
|
|
"repackage_config": repackage_config,
|
|
},
|
|
}
|
|
)
|
|
|
|
worker = {
|
|
"chain-of-trust": True,
|
|
"max-run-time": 3600,
|
|
"taskcluster-proxy": True if get_artifact_prefix(dep_job) else False,
|
|
"env": {
|
|
"REPACK_ID": repack_id,
|
|
},
|
|
# Don't add generic artifact directory.
|
|
"skip-artifacts": True,
|
|
}
|
|
|
|
worker_type = "b-linux-gcp"
|
|
|
|
worker["artifacts"] = _generate_task_output_files(
|
|
dep_job,
|
|
worker_type_implementation(config.graph_config, config.params, worker_type),
|
|
repackage_config,
|
|
partner=repack_id,
|
|
)
|
|
|
|
description = (
|
|
"Repackaging for repack_id '{repack_id}' for build '"
|
|
"{build_platform}/{build_type}'".format(
|
|
repack_id=job["extra"]["repack_id"],
|
|
build_platform=attributes.get("build_platform"),
|
|
build_type=attributes.get("build_type"),
|
|
)
|
|
)
|
|
|
|
task = {
|
|
"label": job["label"],
|
|
"description": description,
|
|
"worker-type": worker_type,
|
|
"dependencies": dependencies,
|
|
"attributes": attributes,
|
|
"scopes": ["queue:get-artifact:releng/partner/*"],
|
|
"run-on-projects": dep_job.attributes.get("run_on_projects"),
|
|
"routes": job.get("routes", []),
|
|
"extra": job.get("extra", {}),
|
|
"worker": worker,
|
|
"run": run,
|
|
"fetches": _generate_download_config(
|
|
dep_job,
|
|
build_platform,
|
|
signing_task,
|
|
partner=repack_id,
|
|
project=config.params["project"],
|
|
repack_stub_installer=repack_stub_installer,
|
|
),
|
|
}
|
|
|
|
# we may have reduced the priority for partner jobs, otherwise task.py will set it
|
|
if job.get("priority"):
|
|
task["priority"] = job["priority"]
|
|
if build_platform.startswith("macosx"):
|
|
task.setdefault("fetches", {}).setdefault("toolchain", []).extend(
|
|
[
|
|
"linux64-libdmg",
|
|
"linux64-hfsplus",
|
|
"linux64-node",
|
|
]
|
|
)
|
|
yield task
|
|
|
|
|
|
def _generate_download_config(
|
|
task,
|
|
build_platform,
|
|
signing_task,
|
|
partner=None,
|
|
project=None,
|
|
repack_stub_installer=False,
|
|
):
|
|
locale_path = f"{partner}/" if partner else ""
|
|
|
|
if build_platform.startswith("macosx"):
|
|
return {
|
|
signing_task: [
|
|
{
|
|
"artifact": f"{locale_path}target.tar.gz",
|
|
"extract": False,
|
|
},
|
|
],
|
|
}
|
|
if build_platform.startswith("win"):
|
|
download_config = [
|
|
{
|
|
"artifact": f"{locale_path}target.zip",
|
|
"extract": False,
|
|
},
|
|
f"{locale_path}setup.exe",
|
|
]
|
|
if build_platform.startswith("win32") and repack_stub_installer:
|
|
download_config.extend(
|
|
[
|
|
{
|
|
"artifact": f"{locale_path}target-stub.zip",
|
|
"extract": False,
|
|
},
|
|
f"{locale_path}setup-stub.exe",
|
|
]
|
|
)
|
|
return {signing_task: download_config}
|
|
|
|
raise NotImplementedError(f'Unsupported build_platform: "{build_platform}"')
|
|
|
|
|
|
def _generate_task_output_files(task, worker_implementation, repackage_config, partner):
|
|
"""We carefully generate an explicit list here, but there's an artifacts directory
|
|
too, courtesy of generic_worker_add_artifacts() (windows) or docker_worker_add_artifacts().
|
|
Any errors here are likely masked by that.
|
|
"""
|
|
partner_output_path = f"{partner}/"
|
|
artifact_prefix = get_artifact_prefix(task)
|
|
|
|
if worker_implementation == ("docker-worker", "linux"):
|
|
local_prefix = "/builds/worker/workspace/"
|
|
elif worker_implementation == ("generic-worker", "windows"):
|
|
local_prefix = "workspace/"
|
|
else:
|
|
raise NotImplementedError(
|
|
f'Unsupported worker implementation: "{worker_implementation}"'
|
|
)
|
|
|
|
output_files = []
|
|
for config in repackage_config:
|
|
output_files.append(
|
|
{
|
|
"type": "file",
|
|
"path": "{}outputs/{}{}".format(
|
|
local_prefix, partner_output_path, config["output"]
|
|
),
|
|
"name": "{}/{}{}".format(
|
|
artifact_prefix, partner_output_path, config["output"]
|
|
),
|
|
}
|
|
)
|
|
return output_files
|