diff options
Diffstat (limited to 'testing/tools/mach_test_package_bootstrap.py')
-rw-r--r-- | testing/tools/mach_test_package_bootstrap.py | 194 |
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 |