summaryrefslogtreecommitdiffstats
path: root/testing/tools/mach_test_package_bootstrap.py
diff options
context:
space:
mode:
Diffstat (limited to 'testing/tools/mach_test_package_bootstrap.py')
-rw-r--r--testing/tools/mach_test_package_bootstrap.py194
1 files changed, 194 insertions, 0 deletions
diff --git a/testing/tools/mach_test_package_bootstrap.py b/testing/tools/mach_test_package_bootstrap.py
new file mode 100644
index 000000000..f7a8fb397
--- /dev/null
+++ b/testing/tools/mach_test_package_bootstrap.py
@@ -0,0 +1,194 @@
+# 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/.
+
+from __future__ import print_function, unicode_literals
+
+import json
+import os
+import platform
+import sys
+import types
+
+
+SEARCH_PATHS = [
+ 'marionette',
+ 'marionette/marionette/runner/mixins/browsermob-proxy-py',
+ 'marionette/client',
+ 'mochitest',
+ 'mozbase/manifestparser',
+ 'mozbase/mozcrash',
+ 'mozbase/mozdebug',
+ 'mozbase/mozdevice',
+ 'mozbase/mozfile',
+ 'mozbase/mozhttpd',
+ 'mozbase/mozinfo',
+ 'mozbase/mozinstall',
+ 'mozbase/mozleak',
+ 'mozbase/mozlog',
+ 'mozbase/moznetwork',
+ 'mozbase/mozprocess',
+ 'mozbase/mozprofile',
+ 'mozbase/mozrunner',
+ 'mozbase/mozscreenshot',
+ 'mozbase/mozsystemmonitor',
+ 'mozbase/moztest',
+ 'mozbase/mozversion',
+ 'reftest',
+ 'tools/mach',
+ 'tools/wptserve',
+ 'xpcshell',
+]
+
+# Individual files providing mach commands.
+MACH_MODULES = [
+ 'marionette/mach_test_package_commands.py',
+ 'mochitest/mach_test_package_commands.py',
+ 'reftest/mach_test_package_commands.py',
+ 'tools/mach/mach/commands/commandinfo.py',
+ 'xpcshell/mach_test_package_commands.py',
+]
+
+
+CATEGORIES = {
+ 'testing': {
+ 'short': 'Testing',
+ 'long': 'Run tests.',
+ 'priority': 30,
+ },
+ 'devenv': {
+ 'short': 'Development Environment',
+ 'long': 'Set up and configure your development environment.',
+ 'priority': 20,
+ },
+ 'misc': {
+ 'short': 'Potpourri',
+ 'long': 'Potent potables and assorted snacks.',
+ 'priority': 10,
+ },
+ 'disabled': {
+ 'short': 'Disabled',
+ 'long': 'The disabled commands are hidden by default. Use -v to display them. '
+ 'These commands are unavailable for your current context, '
+ 'run "mach <command>" to see why.',
+ 'priority': 0,
+ }
+}
+
+
+def ancestors(path, depth=0):
+ """Emit the parent directories of a path."""
+ count = 1
+ while path and count != depth:
+ yield path
+ newpath = os.path.dirname(path)
+ if newpath == path:
+ break
+ path = newpath
+ count += 1
+
+
+def find_firefox(context):
+ """Try to automagically find the firefox binary."""
+ import mozinstall
+ search_paths = []
+
+ # Check for a mozharness setup
+ config = context.mozharness_config
+ if config and 'binary_path' in config:
+ return config['binary_path']
+ elif config:
+ search_paths.append(os.path.join(context.mozharness_workdir, 'application'))
+
+ # Check for test-stage setup
+ dist_bin = os.path.join(os.path.dirname(context.package_root), 'bin')
+ if os.path.isdir(dist_bin):
+ search_paths.append(dist_bin)
+
+ for path in search_paths:
+ try:
+ return mozinstall.get_binary(path, 'firefox')
+ except mozinstall.InvalidBinary:
+ continue
+
+
+def find_hostutils(context):
+ workdir = context.mozharness_workdir
+ hostutils = os.path.join(workdir, 'hostutils')
+ for fname in os.listdir(hostutils):
+ fpath = os.path.join(hostutils, fname)
+ if os.path.isdir(fpath) and fname.startswith('host-utils'):
+ return fpath
+
+
+def normalize_test_path(test_root, path):
+ if os.path.isabs(path) or os.path.exists(path):
+ return os.path.normpath(os.path.abspath(path))
+
+ for parent in ancestors(test_root):
+ test_path = os.path.join(parent, path)
+ if os.path.exists(test_path):
+ return os.path.normpath(os.path.abspath(test_path))
+
+
+def bootstrap(test_package_root):
+ test_package_root = os.path.abspath(test_package_root)
+
+ # Ensure we are running Python 2.7+. We put this check here so we generate a
+ # user-friendly error message rather than a cryptic stack trace on module
+ # import.
+ if sys.version_info[0] != 2 or sys.version_info[1] < 7:
+ print('Python 2.7 or above (but not Python 3) is required to run mach.')
+ print('You are running Python', platform.python_version())
+ sys.exit(1)
+
+ sys.path[0:0] = [os.path.join(test_package_root, path) for path in SEARCH_PATHS]
+ import mach.main
+
+ def populate_context(context, key=None):
+ if key is None:
+ context.package_root = test_package_root
+ context.bin_dir = os.path.join(test_package_root, 'bin')
+ context.certs_dir = os.path.join(test_package_root, 'certs')
+ context.module_dir = os.path.join(test_package_root, 'modules')
+ context.ancestors = ancestors
+ context.normalize_test_path = normalize_test_path
+ return
+
+ # The values for the following 'key's will be set lazily, and cached
+ # after first being invoked.
+ if key == 'firefox_bin':
+ return find_firefox(context)
+
+ if key == 'hostutils':
+ return find_hostutils(context)
+
+ if key == 'mozharness_config':
+ for dir_path in ancestors(context.package_root):
+ mozharness_config = os.path.join(dir_path, 'logs', 'localconfig.json')
+ if os.path.isfile(mozharness_config):
+ with open(mozharness_config, 'rb') as f:
+ return json.load(f)
+ return {}
+
+ if key == 'mozharness_workdir':
+ config = context.mozharness_config
+ if config:
+ return os.path.join(config['base_work_dir'], config['work_dir'])
+
+ mach = mach.main.Mach(os.getcwd())
+ mach.populate_context_handler = populate_context
+
+ for category, meta in CATEGORIES.items():
+ mach.define_category(category, meta['short'], meta['long'],
+ meta['priority'])
+
+ for path in MACH_MODULES:
+ cmdfile = os.path.join(test_package_root, path)
+
+ # Depending on which test zips were extracted,
+ # the command module might not exist
+ if os.path.isfile(cmdfile):
+ mach.load_commands_from_file(cmdfile)
+
+ return mach