Bug 1208320 - Produce mozharness test archive via mozpack; r?glandium
Test archive generation currently copies a bunch of files into a staging
area then runs `zip` to produce ZIP files. There are 2 concerns with
this approach:
1) We incur a lot of extra I/O to copy files so everything is
rooted in a single tree so the `zip` invocation and paths are
simple.
2) ZIP files inherit properties from the local filesystem (including
mtime), making ZIP files non-deterministic.
This commit introduces a new mozbuild action for producing test
archives. It does so using the mozpack file finder and JAR writer,
which are used throughout the build to deterministically
produce ZIP/JAR files from files in multiple source directories.
We implement support for producing the mozharness archive. This archive
does not involve files that are staged, so no I/O is saved. In fact,
the switch from `zip` to Python likely makes this slightly slower.
However, we do have deterministic archives now.
Additional archives will be ported over in subsequent commits.
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/action/test_archive.py
@@ -0,0 +1,66 @@
+# 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.
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+import argparse
+import os
+import sys
+
+from mozpack.files import FileFinder
+from mozpack.mozjar import JarWriter
+
+import buildconfig
+
+
+ARCHIVE_FILES = {
+ 'mozharness': [
+ {
+ 'source': buildconfig.topsrcdir,
+ 'base': 'testing',
+ 'pattern': 'mozharness/**',
+ },
+ ],
+}
+
+
+def find_files(archive):
+ for entry in ARCHIVE_FILES[archive]:
+ source = entry['source']
+ base = entry['base']
+ pattern = entry['pattern']
+
+ finder = FileFinder(os.path.join(source, base),
+ find_executables=False,
+ find_dotfiles=True)
+
+ for f in finder.find(pattern):
+ yield f
+
+
+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)
+
+ if not args.outputfile.endswith('.zip'):
+ raise Exception('expected zip output file')
+
+ with open(args.outputfile, 'wb') as fh:
+ with JarWriter(fileobj=fh, optimize=False) as writer:
+ for p, f in find_files(args.archive):
+ writer.add(p.encode('utf-8'), f.read(), mode=f.mode)
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))
--- a/testing/testsuite-targets.mk
+++ b/testing/testsuite-targets.mk
@@ -423,19 +423,18 @@ test-packages-manifest:
--dest-file $(MOZ_TEST_PACKAGES_FILE) \
$(call PKG_ARG,common) \
$(foreach pkg,$(TEST_PKGS),$(call PKG_ARG,$(pkg)))
package-tests-prepare-dest:
@rm -f '$(DIST)/$(PKG_PATH)$(TEST_PACKAGE)'
$(NSINSTALL) -D $(DIST)/$(PKG_PATH)
-package-tests-mozharness: stage-all package-tests-prepare-dest
- cd $(topsrcdir)/testing/ && \
- zip -rq9D $(abspath $(DIST))/$(PKG_PATH)mozharness.zip mozharness
+package-tests-mozharness: package-tests-prepare-dest
+ $(call py_action,test_archive,mozharness $(abspath $(DIST))/$(PKG_PATH)/mozharness.zip)
package-tests: package-tests-mozharness
package-tests-common: stage-all package-tests-prepare-dest
cd $(abspath $(PKG_STAGE)) && \
zip -rq9D '$(abspath $(DIST))/$(PKG_PATH)$(TEST_PACKAGE)' \
* -x \*/.mkdir.done \*.pyc $(foreach name,$(TEST_PKGS),$(name)\*)
package-tests: package-tests-common