1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 Transform the repackage task into an actual task description.
8 from taskgraph
.transforms
.base
import TransformSequence
9 from taskgraph
.util
.dependencies
import get_primary_dependency
10 from taskgraph
.util
.schema
import Schema
, optionally_keyed_by
, resolve_keyed_by
11 from taskgraph
.util
.taskcluster
import get_artifact_prefix
12 from voluptuous
import Extra
, Optional
, Required
14 from gecko_taskgraph
.transforms
.job
import job_description_schema
15 from gecko_taskgraph
.util
.attributes
import copy_attributes_from_dependent_job
16 from gecko_taskgraph
.util
.copy_task
import copy_task
17 from gecko_taskgraph
.util
.platforms
import architecture
, archive_format
18 from gecko_taskgraph
.util
.workertypes
import worker_type_implementation
20 packaging_description_schema
= Schema(
22 # unique label to describe this repackaging task
23 Optional("label"): str,
24 Optional("worker-type"): str,
25 Optional("worker"): object,
26 Optional("attributes"): job_description_schema
["attributes"],
27 Optional("dependencies"): job_description_schema
["dependencies"],
28 # treeherder is allowed here to override any defaults we use for repackaging. See
29 # taskcluster/gecko_taskgraph/transforms/task.py for the schema details, and the
30 # below transforms for defaults of various values.
31 Optional("treeherder"): job_description_schema
["treeherder"],
32 # If a l10n task, the corresponding locale
33 Optional("locale"): str,
34 # Routes specific to this task, if defined
35 Optional("routes"): [str],
36 # passed through directly to the job description
37 Optional("extra"): job_description_schema
["extra"],
38 # passed through to job description
39 Optional("fetches"): job_description_schema
["fetches"],
40 Optional("run-on-projects"): job_description_schema
["run-on-projects"],
41 # Shipping product and phase
42 Optional("shipping-product"): job_description_schema
["shipping-product"],
43 Optional("shipping-phase"): job_description_schema
["shipping-phase"],
44 Required("package-formats"): optionally_keyed_by(
45 "build-platform", "release-type", "build-type", [str]
48 Optional("channel"): optionally_keyed_by(
56 Optional("identity-name"): optionally_keyed_by(
64 Optional("publisher"): optionally_keyed_by(
72 Optional("publisher-display-name"): optionally_keyed_by(
80 Optional("vendor"): str,
82 # All l10n jobs use mozharness
83 Required("mozharness"): {
85 # Config files passed to the mozharness script
86 Required("config"): optionally_keyed_by("build-platform", [str]),
87 # Additional paths to look for mozharness configs in. These should be
88 # relative to the base of the source checkout
89 Optional("config-paths"): [str],
90 # if true, perform a checkout of a comm-central based branch inside the
92 Optional("comm-checkout"): bool,
93 Optional("run-as-root"): bool,
94 Optional("use-caches"): bool,
96 Optional("job-from"): job_description_schema
["job-from"],
100 # The configuration passed to the mozharness repackage script. This defines the
101 # arguments passed to `mach repackage`
102 # - `args` is interpolated by mozharness (`{package-name}`, `{installer-tag}`,
103 # `{stub-installer-tag}`, `{sfx-stub}`, `{wsx-stub}`, `{fetch-dir}`), with values
105 # - `inputs` are passed as long-options, with the filename prefixed by
106 # `MOZ_FETCH_DIR`. The filename is interpolated by taskgraph
107 # (`{archive_format}`).
108 # - `output` is passed to `--output`, with the filename prefixed by the output
120 "input": "target{archive_format}",
121 "mar": "mar-tools/mar",
123 "output": "target.complete.mar",
137 "{fetch-dir}/candle.exe",
139 "{fetch-dir}/light.exe",
142 "setupexe": "target.installer.exe",
144 "output": "target.installer.msi",
153 "--publisher-display-name",
154 "{msix-publisher-display-name}",
156 "{msix-identity-name}",
161 # For langpacks. Ignored if directory does not exist.
162 "--distribution-dir",
163 "{fetch-dir}/distribution",
166 "{fetch-dir}/msix-packaging/makemsix",
169 "input": "target{archive_format}",
171 "output": "target.installer.msix",
180 "--publisher-display-name",
181 "{msix-publisher-display-name}",
183 "{msix-identity-name}",
188 # For langpacks. Ignored if directory does not exist.
189 "--distribution-dir",
190 "{fetch-dir}/distribution",
193 "{fetch-dir}/msix-packaging/makemsix",
196 "input": "target{archive_format}",
198 "output": "target.store.msix",
203 "input": "target{archive_format}",
205 "output": "target.dmg",
210 "--attribution_sentinel",
214 "input": "target{archive_format}",
216 "output": "target.dmg",
221 "input": "target{archive_format}",
223 "output": "target.pkg",
236 "package": "target{archive_format}",
237 "setupexe": "setup.exe",
239 "output": "target.installer.exe",
245 "{stub-installer-tag}",
250 "setupexe": "setup-stub.exe",
252 "output": "target.stub-installer.exe",
260 "browser/installer/linux/app/debian",
271 "input": "target{archive_format}",
273 "output": "target.deb",
283 "browser/installer/linux/langpack/debian",
288 "input-xpi-file": "target.langpack.xpi",
289 "input-tar-file": "target{archive_format}",
291 "output": "target.langpack.deb",
294 MOZHARNESS_EXPANSIONS
= [
298 "stub-installer-tag",
303 transforms
= TransformSequence()
307 def remove_name(config
, jobs
):
314 transforms
.add_validate(packaging_description_schema
)
318 def copy_in_useful_magic(config
, jobs
):
319 """Copy attributes from upstream task to be used for keyed configuration."""
321 dep
= get_primary_dependency(config
, job
)
324 job
["build-platform"] = dep
.attributes
.get("build_platform")
325 job
["shipping-product"] = dep
.attributes
.get("shipping_product")
326 job
["build-type"] = dep
.attributes
.get("build_type")
331 def handle_keyed_by(config
, jobs
):
332 """Resolve fields that can be keyed by platform, etc, but not `msix.*` fields
333 that can be keyed by `package-format`. Such fields are handled specially below.
338 "worker.max-run-time",
341 job
= copy_task(job
) # don't overwrite dict values here
348 "release-type": config
.params
["release_type"],
349 "level": config
.params
["level"],
356 def make_repackage_description(config
, jobs
):
358 dep_job
= get_primary_dependency(config
, job
)
361 label
= job
.get("label", dep_job
.label
.replace("signing-", "repackage-"))
368 def make_job_description(config
, jobs
):
370 dep_job
= get_primary_dependency(config
, job
)
373 dependencies
= {dep_job
.kind
: dep_job
.label
}
375 attributes
= copy_attributes_from_dependent_job(dep_job
)
376 attributes
["repackage_type"] = "repackage"
378 locale
= attributes
.get("locale", job
.get("locale"))
380 attributes
["locale"] = locale
383 "Repackaging for locale '{locale}' for build '"
384 "{build_platform}/{build_type}'".format(
385 locale
=attributes
.get("locale", "en-US"),
386 build_platform
=attributes
.get("build_platform"),
387 build_type
=attributes
.get("build_type"),
391 treeherder
= job
.get("treeherder", {})
392 treeherder
.setdefault("symbol", "Rpk")
393 dep_th_platform
= dep_job
.task
.get("extra", {}).get("treeherder-platform")
394 treeherder
.setdefault("platform", dep_th_platform
)
395 treeherder
.setdefault("tier", 1)
396 treeherder
.setdefault("kind", "build")
398 # Search dependencies before adding langpack dependencies.
400 repackage_signing_task
= None
401 for dependency
in dependencies
.keys():
402 if "repackage-signing" in dependency
:
403 repackage_signing_task
= dependency
404 elif "signing" in dependency
or "notarization" in dependency
:
405 signing_task
= dependency
407 if config
.kind
== "repackage-msi":
408 treeherder
["symbol"] = "MSI({})".format(locale
or "N")
410 elif config
.kind
== "repackage-msix":
414 treeherder
["symbol"] = "MSIX({})".format(
415 dep_job
.task
.get("extra", {}).get("treeherder", {}).get("symbol", "B")
418 elif config
.kind
== "repackage-shippable-l10n-msix":
421 if attributes
.get("l10n_chunk") or attributes
.get("chunk_locales"):
422 # We don't want to produce MSIXes for single-locale repack builds.
426 "Repackaging with multiple locales for build '"
427 "{build_platform}/{build_type}'".format(
428 build_platform
=attributes
.get("build_platform"),
429 build_type
=attributes
.get("build_type"),
433 # Like "MSIXs(Bs-multi)".
434 treeherder
["symbol"] = "MSIX({}-multi)".format(
435 dep_job
.task
.get("extra", {}).get("treeherder", {}).get("symbol", "B")
438 fetches
= job
.setdefault("fetches", {})
440 # The keys are unique, like `shippable-l10n-signing-linux64-shippable-1/opt`, so we
441 # can't ask for the tasks directly, we must filter for them.
442 for t
in config
.kind_dependencies_tasks
.values():
443 if t
.kind
!= "shippable-l10n-signing":
445 if t
.attributes
["build_platform"] != "linux64-shippable":
447 if t
.attributes
["build_type"] != "opt":
450 dependencies
.update({t
.label
: t
.label
})
456 "artifact": f
"{loc}/target.langpack.xpi",
458 # Otherwise we can't disambiguate locales!
459 "dest": f
"distribution/extensions/{loc}",
461 for loc
in t
.attributes
["chunk_locales"]
466 elif config
.kind
== "repackage-deb":
467 attributes
["repackage_type"] = "repackage-deb"
469 "Repackaging the '{build_platform}/{build_type}' "
470 "{version} build into a '.deb' package"
472 build_platform
=attributes
.get("build_platform"),
473 build_type
=attributes
.get("build_type"),
474 version
=config
.params
["version"],
477 _fetch_subst_locale
= "en-US"
479 _fetch_subst_locale
= locale
481 worker_type
= job
["worker-type"]
482 build_platform
= attributes
["build_platform"]
484 use_stub
= attributes
.get("stub-installer")
486 repackage_config
= []
487 package_formats
= job
.get("package-formats")
488 if use_stub
and not repackage_signing_task
and "msix" not in package_formats
:
489 # if repackage_signing_task doesn't exists, generate the stub installer
490 package_formats
+= ["installer-stub"]
491 for format
in package_formats
:
492 command
= copy_task(PACKAGE_FORMATS
[format
])
494 "archive_format": archive_format(build_platform
),
495 "_locale": _fetch_subst_locale
,
496 "architecture": architecture(build_platform
),
497 "version_display": config
.params
["version"],
498 "mar-channel-id": attributes
["mar-channel-id"],
499 "build_number": config
.params
["build_number"],
500 "release_product": config
.params
["release_product"],
501 "release_type": config
.params
["release_type"],
503 # Allow us to replace `args` as well, but specifying things expanded in mozharness
504 # without breaking .format and without allowing unknown through.
505 substs
.update({name
: f
"{{{name}}}" for name
in MOZHARNESS_EXPANSIONS
})
507 # We need to resolve `msix.*` values keyed by `package-format` for each format, not
508 # just once, so we update a temporary copy just for extracting these values.
509 temp_job
= copy_task(job
)
514 "publisher-display-name",
519 field
=f
"msix.{msix_key}",
522 "package-format": format
,
523 "release-type": config
.params
["release_type"],
524 "level": config
.params
["level"],
528 # Turn `msix.channel` into `msix-channel`, etc.
529 value
= temp_job
.get("msix", {}).get(msix_key
)
532 {f
"msix-{msix_key}": value
},
535 command
["inputs"] = {
536 name
: filename
.format(**substs
)
537 for name
, filename
in command
["inputs"].items()
539 command
["args"] = [arg
.format(**substs
) for arg
in command
["args"]]
540 if "installer" in format
and "aarch64" not in build_platform
:
541 command
["args"].append("--use-upx")
543 repackage_config
.append(command
)
545 run
= job
.get("mozharness", {})
548 "using": "mozharness",
549 "script": "mozharness/scripts/repackage.py",
550 "job-script": "taskcluster/scripts/builder/repackage.sh",
551 "actions": ["setup", "repackage"],
553 "repackage_config": repackage_config
,
555 "run-as-root": run
.get("run-as-root", False),
556 "use-caches": run
.get("use-caches", True),
560 worker
= job
.get("worker", {})
563 "chain-of-trust": True,
564 # Don't add generic artifact directory.
565 "skip-artifacts": True,
568 worker
.setdefault("max-run-time", 3600)
571 # Make sure we specify the locale-specific upload dir
572 worker
.setdefault("env", {})["LOCALE"] = locale
574 worker
["artifacts"] = _generate_task_output_files(
576 worker_type_implementation(config
.graph_config
, config
.params
, worker_type
),
577 repackage_config
=repackage_config
,
580 attributes
["release_artifacts"] = [
581 artifact
["name"] for artifact
in worker
["artifacts"]
585 "label": job
["label"],
586 "description": description
,
587 "worker-type": worker_type
,
588 "dependencies": dependencies
,
589 "if-dependencies": [dep_job
.kind
],
590 "attributes": attributes
,
591 "run-on-projects": job
.get(
592 "run-on-projects", dep_job
.attributes
.get("run_on_projects")
594 "optimization": dep_job
.optimization
,
595 "treeherder": treeherder
,
596 "routes": job
.get("routes", []),
597 "extra": job
.get("extra", {}),
600 "fetches": _generate_download_config(
605 repackage_signing_task
,
607 existing_fetch
=job
.get("fetches"),
611 if build_platform
.startswith("macosx"):
612 task
.setdefault("fetches", {}).setdefault("toolchain", []).extend(
622 if "shipping-phase" in job
:
623 task
["shipping-phase"] = job
["shipping-phase"]
628 def _generate_download_config(
633 repackage_signing_task
,
637 locale_path
= f
"{locale}/" if locale
else ""
640 fetch
.update(existing_fetch
)
642 if repackage_signing_task
and build_platform
.startswith("win"):
645 repackage_signing_task
: [f
"{locale_path}target.installer.exe"],
648 elif build_platform
.startswith("linux") or build_platform
.startswith("macosx"):
651 "artifact": "{}target{}".format(
652 locale_path
, archive_format(build_platform
)
657 if config
.kind
== "repackage-deb-l10n":
658 signing_fetch
.append(
660 "artifact": f
"{locale_path}target.langpack.xpi",
664 fetch
.update({signing_task
: signing_fetch
})
665 elif build_platform
.startswith("win"):
670 "artifact": f
"{locale_path}target.zip",
673 f
"{locale_path}setup.exe",
678 use_stub
= task
.attributes
.get("stub-installer")
680 fetch
[signing_task
].append(f
"{locale_path}setup-stub.exe")
685 raise NotImplementedError(f
'Unsupported build_platform: "{build_platform}"')
688 def _generate_task_output_files(
689 task
, worker_implementation
, repackage_config
, locale
=None
691 locale_output_path
= f
"{locale}/" if locale
else ""
692 artifact_prefix
= get_artifact_prefix(task
)
694 if worker_implementation
== ("docker-worker", "linux"):
695 local_prefix
= "/builds/worker/workspace/"
696 elif worker_implementation
== ("generic-worker", "windows"):
697 local_prefix
= "workspace/"
699 raise NotImplementedError(
700 f
'Unsupported worker implementation: "{worker_implementation}"'
704 for config
in repackage_config
:
708 "path": "{}outputs/{}{}".format(
709 local_prefix
, locale_output_path
, config
["output"]
711 "name": "{}/{}{}".format(
712 artifact_prefix
, locale_output_path
, config
["output"]