summaryrefslogtreecommitdiffstats
path: root/python/mozbuild/mozbuild/action/test_archive.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/mozbuild/mozbuild/action/test_archive.py')
-rw-r--r--python/mozbuild/mozbuild/action/test_archive.py875
1 files changed, 875 insertions, 0 deletions
diff --git a/python/mozbuild/mozbuild/action/test_archive.py b/python/mozbuild/mozbuild/action/test_archive.py
new file mode 100644
index 0000000000..06fef60f8d
--- /dev/null
+++ b/python/mozbuild/mozbuild/action/test_archive.py
@@ -0,0 +1,875 @@
+# 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/.
+
+# This action is used to produce test archives.
+#
+# Ideally, the data in this file should be defined in moz.build files.
+# It is defined inline because this was easiest to make test archive
+# generation faster.
+
+import argparse
+import itertools
+import os
+import sys
+import time
+
+import buildconfig
+import mozpack.path as mozpath
+from manifestparser import TestManifest
+from mozpack.archive import create_tar_gz_from_files
+from mozpack.copier import FileRegistry
+from mozpack.files import ExistingFile, FileFinder
+from mozpack.manifests import InstallManifest
+from mozpack.mozjar import JarWriter
+from reftest import ReftestManifest
+
+from mozbuild.util import ensureParentDir
+
+STAGE = mozpath.join(buildconfig.topobjdir, "dist", "test-stage")
+
+TEST_HARNESS_BINS = [
+ "BadCertAndPinningServer",
+ "DelegatedCredentialsServer",
+ "EncryptedClientHelloServer",
+ "FaultyServer",
+ "GenerateOCSPResponse",
+ "OCSPStaplingServer",
+ "SanctionsTestServer",
+ "SmokeDMD",
+ "certutil",
+ "crashinject",
+ "geckodriver",
+ "http3server",
+ "minidumpwriter",
+ "pk12util",
+ "screenshot",
+ "screentopng",
+ "ssltunnel",
+ "xpcshell",
+]
+
+TEST_HARNESS_DLLS = ["crashinjectdll", "mozglue"]
+
+GMP_TEST_PLUGIN_DIRS = ["gmp-fake/**", "gmp-fakeopenh264/**"]
+
+# These entries will be used by artifact builds to re-construct an
+# objdir with the appropriate generated support files.
+OBJDIR_TEST_FILES = {
+ "xpcshell": {
+ "source": buildconfig.topobjdir,
+ "base": "_tests/xpcshell",
+ "pattern": "**",
+ "dest": "xpcshell/tests",
+ },
+ "mochitest": {
+ "source": buildconfig.topobjdir,
+ "base": "_tests/testing",
+ "pattern": "mochitest/**",
+ },
+}
+
+
+ARCHIVE_FILES = {
+ "common": [
+ {
+ "source": STAGE,
+ "base": "",
+ "pattern": "**",
+ "ignore": [
+ "cppunittest/**",
+ "condprof/**",
+ "gtest/**",
+ "mochitest/**",
+ "reftest/**",
+ "talos/**",
+ "raptor/**",
+ "awsy/**",
+ "web-platform/**",
+ "xpcshell/**",
+ "updater-dep/**",
+ "jsreftest/**",
+ "jit-test/**",
+ "jittest/**", # To make the ignore checker happy
+ "perftests/**",
+ "fuzztest/**",
+ ],
+ },
+ {"source": buildconfig.topobjdir, "base": "_tests", "pattern": "modules/**"},
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing/marionette",
+ "patterns": ["client/**", "harness/**", "mach_test_package_commands.py"],
+ "dest": "marionette",
+ "ignore": ["client/docs", "harness/marionette_harness/tests"],
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "",
+ "manifests": [
+ "testing/marionette/harness/marionette_harness/tests/unit-tests.ini"
+ ],
+ # We also need the manifests and harness_unit tests
+ "pattern": "testing/marionette/harness/marionette_harness/tests/**",
+ "dest": "marionette/tests",
+ },
+ {"source": buildconfig.topobjdir, "base": "_tests", "pattern": "mozbase/**"},
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing",
+ "pattern": "firefox-ui/**",
+ "ignore": ["firefox-ui/tests"],
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "",
+ "pattern": "testing/firefox-ui/tests",
+ "dest": "firefox-ui/tests",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "toolkit/components/telemetry/tests/marionette",
+ "pattern": "/**",
+ "dest": "telemetry/marionette",
+ },
+ {"source": buildconfig.topsrcdir, "base": "testing", "pattern": "tps/**"},
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "services/sync/",
+ "pattern": "tps/**",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "services/sync/tests/tps",
+ "pattern": "**",
+ "dest": "tps/tests",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing/web-platform/tests/tools/wptserve",
+ "pattern": "**",
+ "dest": "tools/wptserve",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing/web-platform/tests/tools/third_party",
+ "pattern": "**",
+ "dest": "tools/wpt_third_party",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "python/mozterm",
+ "pattern": "**",
+ "dest": "tools/mozterm",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "xpcom/geckoprocesstypes_generator",
+ "pattern": "**",
+ "dest": "tools/geckoprocesstypes_generator",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "third_party/python/six",
+ "pattern": "**",
+ "dest": "tools/six",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "third_party/python/distro",
+ "pattern": "**",
+ "dest": "tools/distro",
+ },
+ {"source": buildconfig.topobjdir, "base": "", "pattern": "mozinfo.json"},
+ {
+ "source": buildconfig.topobjdir,
+ "base": "dist/bin",
+ "patterns": [
+ "%s%s" % (f, buildconfig.substs["BIN_SUFFIX"])
+ for f in TEST_HARNESS_BINS
+ ]
+ + [
+ "%s%s%s"
+ % (
+ buildconfig.substs["DLL_PREFIX"],
+ f,
+ buildconfig.substs["DLL_SUFFIX"],
+ )
+ for f in TEST_HARNESS_DLLS
+ ],
+ "dest": "bin",
+ },
+ {
+ "source": buildconfig.topobjdir,
+ "base": "dist/bin",
+ "patterns": GMP_TEST_PLUGIN_DIRS,
+ "dest": "bin/plugins",
+ },
+ {
+ "source": buildconfig.topobjdir,
+ "base": "dist/bin",
+ "patterns": ["dmd.py", "fix_stacks.py"],
+ "dest": "bin",
+ },
+ {
+ "source": buildconfig.topobjdir,
+ "base": "dist/bin/components",
+ "patterns": ["httpd.js"],
+ "dest": "bin/components",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "build/pgo/certs",
+ "pattern": "**",
+ "dest": "certs",
+ },
+ ],
+ "cppunittest": [
+ {"source": STAGE, "base": "", "pattern": "cppunittest/**"},
+ # We don't ship these files if startup cache is disabled, which is
+ # rare. But it shouldn't matter for test archives.
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "startupcache/test",
+ "pattern": "TestStartupCacheTelemetry.*",
+ "dest": "cppunittest",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing",
+ "pattern": "runcppunittests.py",
+ "dest": "cppunittest",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing",
+ "pattern": "remotecppunittests.py",
+ "dest": "cppunittest",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing",
+ "pattern": "cppunittest.ini",
+ "dest": "cppunittest",
+ },
+ {
+ "source": buildconfig.topobjdir,
+ "base": "",
+ "pattern": "mozinfo.json",
+ "dest": "cppunittest",
+ },
+ ],
+ "gtest": [{"source": STAGE, "base": "", "pattern": "gtest/**"}],
+ "mochitest": [
+ OBJDIR_TEST_FILES["mochitest"],
+ {
+ "source": buildconfig.topobjdir,
+ "base": "_tests/testing",
+ "pattern": "mochitest/**",
+ },
+ {"source": STAGE, "base": "", "pattern": "mochitest/**"},
+ {
+ "source": buildconfig.topobjdir,
+ "base": "",
+ "pattern": "mozinfo.json",
+ "dest": "mochitest",
+ },
+ {
+ "source": buildconfig.topobjdir,
+ "base": "dist/xpi-stage",
+ "pattern": "mochijar/**",
+ "dest": "mochitest",
+ },
+ {
+ "source": buildconfig.topobjdir,
+ "base": "dist/xpi-stage",
+ "pattern": "specialpowers/**",
+ "dest": "mochitest/extensions",
+ },
+ ],
+ "mozharness": [
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing/mozharness",
+ "pattern": "**",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "",
+ "pattern": "third_party/python/_venv/**",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing/mozbase/manifestparser",
+ "pattern": "manifestparser/**",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing/mozbase/mozfile",
+ "pattern": "mozfile/**",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing/mozbase/mozinfo",
+ "pattern": "mozinfo/**",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing/mozbase/mozprocess",
+ "pattern": "mozprocess/**",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "third_party/python/six",
+ "pattern": "six.py",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "third_party/python/distro",
+ "pattern": "distro.py",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "third_party/python/packaging",
+ "pattern": "**",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "python/mozbuild/mozbuild/action",
+ "pattern": "tooltool.py",
+ "dest": "external_tools",
+ },
+ ],
+ "reftest": [
+ {"source": buildconfig.topobjdir, "base": "_tests", "pattern": "reftest/**"},
+ {
+ "source": buildconfig.topobjdir,
+ "base": "",
+ "pattern": "mozinfo.json",
+ "dest": "reftest",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "",
+ "manifests": [
+ "layout/reftests/reftest.list",
+ "layout/reftests/reftest-qr.list",
+ "testing/crashtest/crashtests.list",
+ ],
+ "dest": "reftest/tests",
+ },
+ {
+ "source": buildconfig.topobjdir,
+ "base": "dist/xpi-stage",
+ "pattern": "reftest/**",
+ "dest": "reftest",
+ },
+ {
+ "source": buildconfig.topobjdir,
+ "base": "dist/xpi-stage",
+ "pattern": "specialpowers/**",
+ "dest": "reftest",
+ },
+ ],
+ "talos": [
+ {"source": buildconfig.topsrcdir, "base": "testing", "pattern": "talos/**"},
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing/profiles",
+ "pattern": "**",
+ "dest": "talos/talos/profile_data",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "third_party/webkit/PerformanceTests",
+ "pattern": "**",
+ "dest": "talos/talos/tests/webkit/PerformanceTests/",
+ },
+ ],
+ "perftests": [
+ {"source": buildconfig.topsrcdir, "pattern": "testing/mozbase/**"},
+ {"source": buildconfig.topsrcdir, "pattern": "testing/condprofile/**"},
+ {"source": buildconfig.topsrcdir, "pattern": "testing/performance/**"},
+ {"source": buildconfig.topsrcdir, "pattern": "third_party/python/**"},
+ {"source": buildconfig.topsrcdir, "pattern": "tools/lint/eslint/**"},
+ {"source": buildconfig.topsrcdir, "pattern": "**/perftest_*.js"},
+ {"source": buildconfig.topsrcdir, "pattern": "**/hooks_*py"},
+ {"source": buildconfig.topsrcdir, "pattern": "build/autoconf/**"},
+ {"source": buildconfig.topsrcdir, "pattern": "build/moz.configure/**"},
+ {"source": buildconfig.topsrcdir, "pattern": "python/**"},
+ {"source": buildconfig.topsrcdir, "pattern": "build/mach_initialize.py"},
+ {
+ "source": buildconfig.topsrcdir,
+ "pattern": "python/sites/build.txt",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "pattern": "python/sites/common.txt",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "pattern": "python/sites/mach.txt",
+ },
+ {"source": buildconfig.topsrcdir, "pattern": "mach/**"},
+ {
+ "source": buildconfig.topsrcdir,
+ "pattern": "testing/web-platform/tests/tools/third_party/certifi/**",
+ },
+ {"source": buildconfig.topsrcdir, "pattern": "testing/mozharness/**"},
+ {"source": buildconfig.topsrcdir, "pattern": "browser/config/**"},
+ {
+ "source": buildconfig.topobjdir,
+ "base": "_tests/modules",
+ "pattern": "**",
+ "dest": "bin/modules",
+ },
+ {
+ "source": buildconfig.topobjdir,
+ "base": "dist/bin",
+ "patterns": [
+ "browser/**",
+ "chrome/**",
+ "chrome.manifest",
+ "components/**",
+ "http3server",
+ "*.ini",
+ "localization/**",
+ "modules/**",
+ "update.locale",
+ "greprefs.js",
+ ],
+ "dest": "bin",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "netwerk/test/http3serverDB",
+ "pattern": "**",
+ "dest": "netwerk/test/http3serverDB",
+ },
+ ],
+ "condprof": [
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing",
+ "pattern": "condprofile/**",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing/mozbase/mozfile",
+ "pattern": "**",
+ "dest": "condprofile/mozfile",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing/mozbase/mozprofile",
+ "pattern": "**",
+ "dest": "condprofile/mozprofile",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing/mozbase/mozdevice",
+ "pattern": "**",
+ "dest": "condprofile/mozdevice",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing/mozbase/mozlog",
+ "pattern": "**",
+ "dest": "condprofile/mozlog",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "third_party/python/virtualenv",
+ "pattern": "**",
+ "dest": "condprofile/virtualenv",
+ },
+ ],
+ "raptor": [
+ {"source": buildconfig.topsrcdir, "base": "testing", "pattern": "raptor/**"},
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing/profiles",
+ "pattern": "**",
+ "dest": "raptor/raptor/profile_data",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "third_party/webkit/PerformanceTests",
+ "pattern": "**",
+ "dest": "raptor/raptor/tests/webkit/PerformanceTests/",
+ },
+ ],
+ "awsy": [
+ {"source": buildconfig.topsrcdir, "base": "testing", "pattern": "awsy/**"}
+ ],
+ "web-platform": [
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing",
+ "pattern": "web-platform/meta/**",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing",
+ "pattern": "web-platform/mozilla/**",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing",
+ "pattern": "web-platform/tests/**",
+ "ignore": ["web-platform/tests/tools/wpt_third_party"],
+ },
+ {
+ "source": buildconfig.topobjdir,
+ "base": "_tests",
+ "pattern": "web-platform/**",
+ },
+ {
+ "source": buildconfig.topobjdir,
+ "base": "",
+ "pattern": "mozinfo.json",
+ "dest": "web-platform",
+ },
+ ],
+ "xpcshell": [
+ OBJDIR_TEST_FILES["xpcshell"],
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing/xpcshell",
+ "patterns": [
+ "head.js",
+ "mach_test_package_commands.py",
+ "moz-http2/**",
+ "node-http2/**",
+ "node_ip/**",
+ "node-ws/**",
+ "dns-packet/**",
+ "remotexpcshelltests.py",
+ "runxpcshelltests.py",
+ "selftest.py",
+ "xpcshellcommandline.py",
+ ],
+ "dest": "xpcshell",
+ },
+ {"source": STAGE, "base": "", "pattern": "xpcshell/**"},
+ {
+ "source": buildconfig.topobjdir,
+ "base": "",
+ "pattern": "mozinfo.json",
+ "dest": "xpcshell",
+ },
+ {
+ "source": buildconfig.topobjdir,
+ "base": "build",
+ "pattern": "automation.py",
+ "dest": "xpcshell",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "testing/profiles",
+ "pattern": "**",
+ "dest": "xpcshell/profile_data",
+ },
+ {
+ "source": buildconfig.topobjdir,
+ "base": "dist/bin",
+ "pattern": "http3server%s" % buildconfig.substs["BIN_SUFFIX"],
+ "dest": "xpcshell/http3server",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "netwerk/test/http3serverDB",
+ "pattern": "**",
+ "dest": "xpcshell/http3server/http3serverDB",
+ },
+ ],
+ "updater-dep": [
+ {
+ "source": buildconfig.topobjdir,
+ "base": "_tests/updater-dep",
+ "pattern": "**",
+ "dest": "updater-dep",
+ },
+ # Required by the updater on Linux
+ {
+ "source": buildconfig.topobjdir,
+ "base": "config/external/sqlite",
+ "pattern": "libmozsqlite3.so",
+ "dest": "updater-dep",
+ },
+ ],
+ "jsreftest": [{"source": STAGE, "base": "", "pattern": "jsreftest/**"}],
+ "fuzztest": [
+ {"source": buildconfig.topsrcdir, "pattern": "tools/fuzzing/smoke/**"}
+ ],
+ "jittest": [
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "js/src",
+ "pattern": "jit-test/**",
+ "dest": "jit-test",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "js/src/tests",
+ "pattern": "non262/shell.js",
+ "dest": "jit-test/tests",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "js/src/tests",
+ "pattern": "non262/Math/shell.js",
+ "dest": "jit-test/tests",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "js/src/tests",
+ "pattern": "non262/reflect-parse/Match.js",
+ "dest": "jit-test/tests",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "js/src/tests",
+ "pattern": "lib/**",
+ "dest": "jit-test/tests",
+ },
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "js/src",
+ "pattern": "jsapi.h",
+ "dest": "jit-test",
+ },
+ ],
+}
+
+if buildconfig.substs.get("MOZ_CODE_COVERAGE"):
+ ARCHIVE_FILES["common"].append(
+ {
+ "source": buildconfig.topsrcdir,
+ "base": "python/mozbuild/",
+ "patterns": ["mozpack/**", "mozbuild/codecoverage/**"],
+ }
+ )
+
+
+if buildconfig.substs.get("MOZ_ASAN") and buildconfig.substs.get("CLANG_CL"):
+ asan_dll = {
+ "source": buildconfig.topobjdir,
+ "base": "dist/bin",
+ "pattern": os.path.basename(buildconfig.substs["MOZ_CLANG_RT_ASAN_LIB_PATH"]),
+ "dest": "bin",
+ }
+ ARCHIVE_FILES["common"].append(asan_dll)
+
+
+if buildconfig.substs.get("commtopsrcdir"):
+ commtopsrcdir = buildconfig.substs.get("commtopsrcdir")
+ mozharness_comm = {
+ "source": commtopsrcdir,
+ "base": "testing/mozharness",
+ "pattern": "**",
+ }
+ ARCHIVE_FILES["mozharness"].append(mozharness_comm)
+ marionette_comm = {
+ "source": commtopsrcdir,
+ "base": "",
+ "manifest": "testing/marionette/unit-tests.ini",
+ "dest": "marionette/tests/comm",
+ }
+ ARCHIVE_FILES["common"].append(marionette_comm)
+ thunderbirdinstance = {
+ "source": commtopsrcdir,
+ "base": "testing/marionette",
+ "pattern": "thunderbirdinstance.py",
+ "dest": "marionette/client/marionette_driver",
+ }
+ ARCHIVE_FILES["common"].append(thunderbirdinstance)
+
+
+# "common" is our catch all archive and it ignores things from other archives.
+# Verify nothing sneaks into ARCHIVE_FILES without a corresponding exclusion
+# rule in the "common" archive.
+for k, v in ARCHIVE_FILES.items():
+ # Skip mozharness because it isn't staged.
+ if k in ("common", "mozharness"):
+ continue
+
+ ignores = set(
+ itertools.chain(*(e.get("ignore", []) for e in ARCHIVE_FILES["common"]))
+ )
+
+ if not any(p.startswith("%s/" % k) for p in ignores):
+ raise Exception('"common" ignore list probably should contain %s' % k)
+
+
+def find_generated_harness_files():
+ # TEST_HARNESS_FILES end up in an install manifest at
+ # $topsrcdir/_build_manifests/install/_tests.
+ manifest = InstallManifest(
+ mozpath.join(buildconfig.topobjdir, "_build_manifests", "install", "_tests")
+ )
+ registry = FileRegistry()
+ manifest.populate_registry(registry)
+ # Conveniently, the generated files we care about will already
+ # exist in the objdir, so we can identify relevant files if
+ # they're an `ExistingFile` instance.
+ return [
+ mozpath.join("_tests", p)
+ for p in registry.paths()
+ if isinstance(registry[p], ExistingFile)
+ ]
+
+
+def find_files(archive):
+ extra_entries = []
+ generated_harness_files = find_generated_harness_files()
+
+ if archive == "common":
+ # Construct entries ensuring all our generated harness files are
+ # packaged in the common tests archive.
+ packaged_paths = set()
+ for entry in OBJDIR_TEST_FILES.values():
+ pat = mozpath.join(entry["base"], entry["pattern"])
+ del entry["pattern"]
+ patterns = []
+ for path in generated_harness_files:
+ if mozpath.match(path, pat):
+ patterns.append(path[len(entry["base"]) + 1 :])
+ packaged_paths.add(path)
+ if patterns:
+ entry["patterns"] = patterns
+ extra_entries.append(entry)
+ entry = {"source": buildconfig.topobjdir, "base": "_tests", "patterns": []}
+ for path in set(generated_harness_files) - packaged_paths:
+ entry["patterns"].append(path[len("_tests") + 1 :])
+ extra_entries.append(entry)
+
+ for entry in ARCHIVE_FILES[archive] + extra_entries:
+ source = entry["source"]
+ dest = entry.get("dest")
+ base = entry.get("base", "")
+
+ pattern = entry.get("pattern")
+ patterns = entry.get("patterns", [])
+ if pattern:
+ patterns.append(pattern)
+
+ manifest = entry.get("manifest")
+ manifests = entry.get("manifests", [])
+ if manifest:
+ manifests.append(manifest)
+ if manifests:
+ dirs = find_manifest_dirs(os.path.join(source, base), manifests)
+ patterns.extend({"{}/**".format(d) for d in dirs})
+
+ ignore = list(entry.get("ignore", []))
+ ignore.extend(["**/.flake8", "**/.mkdir.done", "**/*.pyc"])
+
+ if archive not in ("common", "updater-dep") and base.startswith("_tests"):
+ # We may have generated_harness_files to exclude from this entry.
+ for path in generated_harness_files:
+ if path.startswith(base):
+ ignore.append(path[len(base) + 1 :])
+
+ common_kwargs = {"find_dotfiles": True, "ignore": ignore}
+
+ finder = FileFinder(os.path.join(source, base), **common_kwargs)
+
+ for pattern in patterns:
+ for p, f in finder.find(pattern):
+ if dest:
+ p = mozpath.join(dest, p)
+ yield p, f
+
+
+def find_manifest_dirs(topsrcdir, manifests):
+ """Routine to retrieve directories specified in a manifest, relative to topsrcdir.
+
+ It does not recurse into manifests, as we currently have no need for that.
+ """
+ dirs = set()
+
+ for p in manifests:
+ p = os.path.join(topsrcdir, p)
+
+ if p.endswith(".ini"):
+ test_manifest = TestManifest()
+ test_manifest.read(p)
+ dirs |= set([os.path.dirname(m) for m in test_manifest.manifests()])
+
+ elif p.endswith(".list"):
+ m = ReftestManifest()
+ m.load(p)
+ dirs |= m.dirs
+
+ else:
+ raise Exception(
+ '"{}" is not a supported manifest format.'.format(
+ os.path.splitext(p)[1]
+ )
+ )
+
+ dirs = {mozpath.normpath(d[len(topsrcdir) :]).lstrip("/") for d in dirs}
+
+ # Filter out children captured by parent directories because duplicates
+ # will confuse things later on.
+ def parents(p):
+ while True:
+ p = mozpath.dirname(p)
+ if not p:
+ break
+ yield p
+
+ seen = set()
+ for d in sorted(dirs, key=len):
+ if not any(p in seen for p in parents(d)):
+ seen.add(d)
+
+ return sorted(seen)
+
+
+def main(argv):
+ parser = argparse.ArgumentParser(description="Produce test archives")
+ parser.add_argument("archive", help="Which archive to generate")
+ parser.add_argument("outputfile", help="File to write output to")
+
+ args = parser.parse_args(argv)
+
+ out_file = args.outputfile
+ if not out_file.endswith((".tar.gz", ".zip")):
+ raise Exception("expected tar.gz or zip output file")
+
+ file_count = 0
+ t_start = time.monotonic()
+ ensureParentDir(out_file)
+ res = find_files(args.archive)
+ with open(out_file, "wb") as fh:
+ # Experimentation revealed that level 5 is significantly faster and has
+ # marginally larger sizes than higher values and is the sweet spot
+ # for optimal compression. Read the detailed commit message that
+ # introduced this for raw numbers.
+ if out_file.endswith(".tar.gz"):
+ files = dict(res)
+ create_tar_gz_from_files(fh, files, compresslevel=5)
+ file_count = len(files)
+ elif out_file.endswith(".zip"):
+ with JarWriter(fileobj=fh, compress_level=5) as writer:
+ for p, f in res:
+ writer.add(
+ p.encode("utf-8"), f.read(), mode=f.mode, skip_duplicates=True
+ )
+ file_count += 1
+ else:
+ raise Exception("unhandled file extension: %s" % out_file)
+
+ duration = time.monotonic() - t_start
+ zip_size = os.path.getsize(args.outputfile)
+ basename = os.path.basename(args.outputfile)
+ print(
+ "Wrote %d files in %d bytes to %s in %.2fs"
+ % (file_count, zip_size, basename, duration)
+ )
+
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv[1:]))