Bug 1966470 - Part 1: Add mach artifact install --unfiltered-project-package command. r=firefox-build-system-reviewers,glandium
Getting artifacts from other locations when building is a solved problem. But single-locale repacks do something very different that is very hard to arrange locally. This commit will be used to make single-locale repacks easier to work with. This commit adds a new "unfiltered project package" mode that uses the artifact build mode fetching code to download (and minimally process) just the main package from a build. The processing is convenient on macOS, where DMG files are onerous to work with and the application bundle name varies. Differential Revision: https://phabricator.services.mozilla.com/D249447
This commit is contained in:
committed by
nalexander@mozilla.com
parent
f4d2d352e2
commit
a8d08169d9
@@ -89,6 +89,7 @@ def _make_artifacts(
|
|||||||
download_symbols=False,
|
download_symbols=False,
|
||||||
download_maven_zip=False,
|
download_maven_zip=False,
|
||||||
no_process=False,
|
no_process=False,
|
||||||
|
unfiltered_project_package=False,
|
||||||
):
|
):
|
||||||
state_dir = command_context._mach_context.state_dir
|
state_dir = command_context._mach_context.state_dir
|
||||||
cache_dir = os.path.join(state_dir, "package-frontend")
|
cache_dir = os.path.join(state_dir, "package-frontend")
|
||||||
@@ -129,6 +130,7 @@ def _make_artifacts(
|
|||||||
download_symbols=download_symbols,
|
download_symbols=download_symbols,
|
||||||
download_maven_zip=download_maven_zip,
|
download_maven_zip=download_maven_zip,
|
||||||
no_process=no_process,
|
no_process=no_process,
|
||||||
|
unfiltered_project_package=unfiltered_project_package,
|
||||||
mozbuild=command_context,
|
mozbuild=command_context,
|
||||||
)
|
)
|
||||||
return artifacts
|
return artifacts
|
||||||
@@ -163,6 +165,11 @@ def _make_artifacts(
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Don't process (unpack) artifact packages, just download them.",
|
help="Don't process (unpack) artifact packages, just download them.",
|
||||||
)
|
)
|
||||||
|
@CommandArgument(
|
||||||
|
"--unfiltered-project-package",
|
||||||
|
action="store_true",
|
||||||
|
help="Minimally process (only) main project package artifact, unpacking it to the given `--distdir`.",
|
||||||
|
)
|
||||||
@CommandArgument(
|
@CommandArgument(
|
||||||
"--maven-zip", action="store_true", help="Download Maven zip (Android-only)."
|
"--maven-zip", action="store_true", help="Download Maven zip (Android-only)."
|
||||||
)
|
)
|
||||||
@@ -177,6 +184,7 @@ def artifact_install(
|
|||||||
symbols=False,
|
symbols=False,
|
||||||
distdir=None,
|
distdir=None,
|
||||||
no_process=False,
|
no_process=False,
|
||||||
|
unfiltered_project_package=False,
|
||||||
maven_zip=False,
|
maven_zip=False,
|
||||||
):
|
):
|
||||||
command_context._set_log_level(verbose)
|
command_context._set_log_level(verbose)
|
||||||
@@ -189,6 +197,7 @@ def artifact_install(
|
|||||||
download_symbols=symbols,
|
download_symbols=symbols,
|
||||||
download_maven_zip=maven_zip,
|
download_maven_zip=maven_zip,
|
||||||
no_process=no_process,
|
no_process=no_process,
|
||||||
|
unfiltered_project_package=unfiltered_project_package,
|
||||||
)
|
)
|
||||||
|
|
||||||
return artifacts.install_from(source, distdir or command_context.distdir)
|
return artifacts.install_from(source, distdir or command_context.distdir)
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ import pylru
|
|||||||
import requests
|
import requests
|
||||||
from mach.util import UserError
|
from mach.util import UserError
|
||||||
from mozpack import executables
|
from mozpack import executables
|
||||||
from mozpack.files import JarFinder, TarFinder
|
from mozpack.files import FileFinder, JarFinder, TarFinder
|
||||||
from mozpack.mozjar import JarReader, JarWriter
|
from mozpack.mozjar import JarReader, JarWriter
|
||||||
from mozpack.packager.unpack import UnpackFinder
|
from mozpack.packager.unpack import UnpackFinder
|
||||||
from taskgraph.util.taskcluster import find_task_id, get_artifact_url, list_artifacts
|
from taskgraph.util.taskcluster import find_task_id, get_artifact_url, list_artifacts
|
||||||
@@ -84,6 +84,9 @@ MAX_CACHED_TASKS = 400 # Number of pushheads to cache Task Cluster task data fo
|
|||||||
# copying from DMG files is very slow, we extract the desired binaries to a
|
# copying from DMG files is very slow, we extract the desired binaries to a
|
||||||
# separate archive for fast re-installation.
|
# separate archive for fast re-installation.
|
||||||
PROCESSED_SUFFIX = ".processed.jar"
|
PROCESSED_SUFFIX = ".processed.jar"
|
||||||
|
UNFILTERED_PROJECT_PACKAGE_PROCESSED_SUFFIX = (
|
||||||
|
".unfiltered_project_package.processed.jar"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ArtifactJob:
|
class ArtifactJob:
|
||||||
@@ -861,6 +864,80 @@ class WinThunderbirdArtifactJob(ThunderbirdMixin, WinArtifactJob):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UnfilteredProjectPackageArtifactJob(ArtifactJob):
|
||||||
|
"""An `ArtifactJob` that processes only the main project package and is
|
||||||
|
unfiltered, i.e., does not change the internal structure of the main
|
||||||
|
package. For use in repackaging, where the artifact build mode VCS and
|
||||||
|
Taskcluster integration is convenient but the whole package is needed (and
|
||||||
|
DMGs are slow to work with locally).
|
||||||
|
|
||||||
|
Desktop-only at this time.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Can't yet handle `AndroidArtifactJob` uniformly, since the `product` is "mobile".
|
||||||
|
package_re = "|".join(
|
||||||
|
[
|
||||||
|
f"({cls.package_re})"
|
||||||
|
for cls in (LinuxArtifactJob, MacArtifactJob, WinArtifactJob)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
product = "firefox"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _extra_archives(self):
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def process_package_artifact(self, filename, processed_filename):
|
||||||
|
tempdir = tempfile.mkdtemp()
|
||||||
|
try:
|
||||||
|
self.log(
|
||||||
|
logging.DEBUG,
|
||||||
|
"artifact",
|
||||||
|
{"tempdir": tempdir},
|
||||||
|
"Unpacking into {tempdir}",
|
||||||
|
)
|
||||||
|
mozinstall.install(filename, tempdir)
|
||||||
|
|
||||||
|
# Avoid mismatches between local packages (Nightly.app) and CI artifacts
|
||||||
|
# (Firefox Nightly.app).
|
||||||
|
if filename.endswith(".dmg"):
|
||||||
|
bundle_dirs = glob.glob(mozpath.join(tempdir, "*.app"))
|
||||||
|
else:
|
||||||
|
bundle_dirs = glob.glob(
|
||||||
|
mozpath.join(tempdir, self._substs["MOZ_APP_NAME"])
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(bundle_dirs) != 1:
|
||||||
|
raise ValueError(f"Expected one source bundle, found: {bundle_dirs}")
|
||||||
|
(source,) = bundle_dirs
|
||||||
|
|
||||||
|
with self.get_writer(file=processed_filename, compress_level=5) as writer:
|
||||||
|
finder = FileFinder(source)
|
||||||
|
for p, f in finder.find("*"):
|
||||||
|
q = p
|
||||||
|
if filename.endswith(".dmg"):
|
||||||
|
q = mozpath.join(self._substs["MOZ_MACBUNDLE_NAME"], q)
|
||||||
|
self.log(
|
||||||
|
logging.DEBUG,
|
||||||
|
"artifact",
|
||||||
|
{"path": q},
|
||||||
|
"Adding {path} to unfiltered project package archive",
|
||||||
|
)
|
||||||
|
writer.add(q.encode("utf-8"), f.open(), mode=f.mode)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
shutil.rmtree(tempdir)
|
||||||
|
except OSError:
|
||||||
|
self.log(
|
||||||
|
logging.WARN,
|
||||||
|
"artifact",
|
||||||
|
{"tempdir": tempdir},
|
||||||
|
"Unable to delete {tempdir}",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def startswithwhich(s, prefixes):
|
def startswithwhich(s, prefixes):
|
||||||
for prefix in prefixes:
|
for prefix in prefixes:
|
||||||
if s.startswith(prefix):
|
if s.startswith(prefix):
|
||||||
@@ -1097,11 +1174,17 @@ class Artifacts:
|
|||||||
download_symbols=False,
|
download_symbols=False,
|
||||||
download_maven_zip=False,
|
download_maven_zip=False,
|
||||||
no_process=False,
|
no_process=False,
|
||||||
|
unfiltered_project_package=False,
|
||||||
mozbuild=None,
|
mozbuild=None,
|
||||||
):
|
):
|
||||||
if (hg and git) or (not hg and not git):
|
if (hg and git) or (not hg and not git):
|
||||||
raise ValueError("Must provide path to exactly one of hg and git")
|
raise ValueError("Must provide path to exactly one of hg and git")
|
||||||
|
|
||||||
|
if no_process and unfiltered_project_package:
|
||||||
|
raise ValueError(
|
||||||
|
"Must provide only one of no_process and unfiltered_project_package"
|
||||||
|
)
|
||||||
|
|
||||||
self._substs = substs
|
self._substs = substs
|
||||||
self._defines = defines
|
self._defines = defines
|
||||||
self._tree = tree
|
self._tree = tree
|
||||||
@@ -1113,10 +1196,12 @@ class Artifacts:
|
|||||||
self._skip_cache = skip_cache
|
self._skip_cache = skip_cache
|
||||||
self._topsrcdir = topsrcdir
|
self._topsrcdir = topsrcdir
|
||||||
self._no_process = no_process
|
self._no_process = no_process
|
||||||
|
self._unfiltered_project_package = unfiltered_project_package
|
||||||
|
|
||||||
app = self._substs.get("MOZ_BUILD_APP")
|
app = self._substs.get("MOZ_BUILD_APP")
|
||||||
job_details = COMM_JOB_DETAILS if app == "comm/mail" else MOZ_JOB_DETAILS
|
job_details = COMM_JOB_DETAILS if app == "comm/mail" else MOZ_JOB_DETAILS
|
||||||
|
|
||||||
|
if not self._unfiltered_project_package:
|
||||||
try:
|
try:
|
||||||
cls = job_details[self._job]
|
cls = job_details[self._job]
|
||||||
self._artifact_job = cls(
|
self._artifact_job = cls(
|
||||||
@@ -1128,8 +1213,19 @@ class Artifacts:
|
|||||||
mozbuild=mozbuild,
|
mozbuild=mozbuild,
|
||||||
)
|
)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
self.log(logging.INFO, "artifact", {"job": self._job}, "Unknown job {job}")
|
self.log(
|
||||||
|
logging.INFO, "artifact", {"job": self._job}, "Unknown job {job}"
|
||||||
|
)
|
||||||
raise KeyError("Unknown job")
|
raise KeyError("Unknown job")
|
||||||
|
else:
|
||||||
|
self._artifact_job = UnfilteredProjectPackageArtifactJob(
|
||||||
|
log=self._log,
|
||||||
|
download_tests=False,
|
||||||
|
download_symbols=False,
|
||||||
|
download_maven_zip=False,
|
||||||
|
substs=self._substs,
|
||||||
|
mozbuild=mozbuild,
|
||||||
|
)
|
||||||
|
|
||||||
self._task_cache = TaskCache(
|
self._task_cache = TaskCache(
|
||||||
self._cache_dir, log=self._log, skip_cache=self._skip_cache
|
self._cache_dir, log=self._log, skip_cache=self._skip_cache
|
||||||
@@ -1482,6 +1578,8 @@ https://firefox-source-docs.mozilla.org/contributing/vcs/mercurial_bundles.html
|
|||||||
|
|
||||||
# Do we need to post-process?
|
# Do we need to post-process?
|
||||||
processed_filename = filename + PROCESSED_SUFFIX
|
processed_filename = filename + PROCESSED_SUFFIX
|
||||||
|
if self._unfiltered_project_package:
|
||||||
|
processed_filename = filename + UNFILTERED_PROJECT_PACKAGE_PROCESSED_SUFFIX
|
||||||
|
|
||||||
if self._skip_cache and os.path.exists(processed_filename):
|
if self._skip_cache and os.path.exists(processed_filename):
|
||||||
self.log(
|
self.log(
|
||||||
|
|||||||
Reference in New Issue
Block a user