Bug 1300163 - Lazy load certain mach context attributes using the 'key' mechanism, r=armenzg
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Fri, 02 Sep 2016 14:35:14 -0400
changeset 312854 7d4b9b9df5d2d537f1710ed6642810d99df12277
parent 312853 574003ffca89a1f5e0b6bd07bcf6050b12f4f731
child 312855 e786511a99e16ae8b861ef0ef12c94c63306fa80
push id30663
push usercbook@mozilla.com
push dateWed, 07 Sep 2016 15:12:31 +0000
treeherdermozilla-central@3d0b41fdd93b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarmenzg
bugs1300163
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1300163 - Lazy load certain mach context attributes using the 'key' mechanism, r=armenzg You can set attributes on a mach context by using the 'key' argument to the context_handler. Basically, whatever gets returned by the handler when <key> is passed in, will get set (i.e cached) on the context object for fast retrieval next time. This is a way to lazy load these attributes. Previously I was setting functions like 'find_firefox()' on the context object, and then having the mach_commands call that directly. But this way is much cleaner. Now, the loaded 'mozharness_config' can be stored as an attribute on the context. Also 'find_firefox()' is now an attribute called 'firefox_bin'. MozReview-Commit-ID: 4lsKGpizfH7
layout/tools/reftest/mach_test_package_commands.py
testing/marionette/mach_test_package_commands.py
testing/mochitest/mach_test_package_commands.py
testing/tools/mach_test_package_bootstrap.py
testing/xpcshell/mach_test_package_commands.py
--- a/layout/tools/reftest/mach_test_package_commands.py
+++ b/layout/tools/reftest/mach_test_package_commands.py
@@ -9,25 +9,21 @@ from functools import partial
 
 from mach.decorators import (
     CommandProvider,
     Command,
 )
 
 
 def run_reftest(context, **kwargs):
+    kwargs['app'] = kwargs['app'] or context.firefox_bin
     kwargs['certPath'] = context.certs_dir
     kwargs['utilityPath'] = context.bin_dir
     kwargs['extraProfileFiles'].append(os.path.join(context.bin_dir, 'plugins'))
 
-    if not kwargs['app']:
-        # This could still return None in which case --appname must be used
-        # to specify the firefox binary.
-        kwargs['app'] = context.find_firefox()
-
     if not kwargs['tests']:
         kwargs['tests'] = [os.path.join('layout', 'reftests', 'reftest.list')]
 
     test_root = os.path.join(context.package_root, 'reftest', 'tests')
     normalize = partial(context.normalize_test_path, test_root)
     kwargs['tests'] = map(normalize, kwargs['tests'])
 
     from runreftest import run as run_test_harness
--- a/testing/marionette/mach_test_package_commands.py
+++ b/testing/marionette/mach_test_package_commands.py
@@ -19,19 +19,17 @@ def run_marionette(context, **kwargs):
     from marionette.runtests import (
         MarionetteTestRunner,
         MarionetteHarness
     )
     from mozlog.structured import commandline
 
 
     args = argparse.Namespace(**kwargs)
-
-    if not args.binary:
-        args.binary = context.find_firefox()
+    args.binary = args.binary or context.firefox_bin
 
     test_root = os.path.join(context.package_root, 'marionette', 'tests')
     if not args.tests:
         args.tests = [os.path.join(test_root, 'testing', 'marionette', 'harness',
                                    'marionette', 'tests', 'unit-tests.ini')]
 
     normalize = partial(context.normalize_test_path, test_root)
     args.tests = map(normalize, args.tests)
--- a/testing/mochitest/mach_test_package_commands.py
+++ b/testing/mochitest/mach_test_package_commands.py
@@ -14,27 +14,30 @@ from mach.decorators import (
 )
 
 parser = None
 
 
 def run_mochitest(context, **kwargs):
     args = Namespace(**kwargs)
     args.certPath = context.certs_dir
-    args.utilityPath = context.bin_dir
-    args.extraProfileFiles.append(os.path.join(context.bin_dir, 'plugins'))
-
-    if not args.app:
-        args.app = context.find_firefox()
 
     if args.test_paths:
         test_root = os.path.join(context.package_root, 'mochitest', 'tests')
         normalize = partial(context.normalize_test_path, test_root)
         args.test_paths = map(normalize, args.test_paths)
 
+    return run_mochitest_desktop(context, args)
+
+
+def run_mochitest_desktop(context, args):
+    args.app = args.app or context.firefox_bin
+    args.utilityPath = context.bin_dir
+    args.extraProfileFiles.append(os.path.join(context.bin_dir, 'plugins'))
+
     from runtests import run_test_harness
     return run_test_harness(parser, args)
 
 
 def setup_argument_parser():
     from mochitest_options import MochitestArgumentParser
     global parser
     parser = MochitestArgumentParser(app='generic')
--- a/testing/tools/mach_test_package_bootstrap.py
+++ b/testing/tools/mach_test_package_bootstrap.py
@@ -89,21 +89,21 @@ def ancestors(path, depth=0):
 
 
 def find_firefox(context):
     """Try to automagically find the firefox binary."""
     import mozinstall
     search_paths = []
 
     # Check for a mozharness setup
-    if context.mozharness_config:
-        with open(context.mozharness_config, 'r') as f:
-            config = json.load(f)
-        workdir = os.path.join(config['base_work_dir'], config['work_dir'])
-        search_paths.append(os.path.join(workdir, 'application'))
+    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:
@@ -132,35 +132,43 @@ def bootstrap(test_package_root):
         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 not 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
 
-        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.modules_dir = os.path.join(test_package_root, 'modules')
+        # 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)
+
 
-        context.ancestors = ancestors
-        context.find_firefox = types.MethodType(find_firefox, context)
-        context.normalize_test_path = normalize_test_path
+        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 {}
 
-        # Search for a mozharness localconfig.json
-        context.mozharness_config = None
-        for dir_path in ancestors(test_package_root):
-            mozharness_config = os.path.join(dir_path, 'logs', 'localconfig.json')
-            if os.path.isfile(mozharness_config):
-                context.mozharness_config = mozharness_config
-                break
+        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'])
 
--- a/testing/xpcshell/mach_test_package_commands.py
+++ b/testing/xpcshell/mach_test_package_commands.py
@@ -16,22 +16,20 @@ from xpcshellcommandline import parser_d
 from mach.decorators import (
     CommandProvider,
     Command,
 )
 
 
 def run_xpcshell(context, **kwargs):
     args = Namespace(**kwargs)
+    args.appPath = args.appPath or os.path.dirname(context.firefox_bin)
     args.utility_path = context.bin_dir
     args.testingModulesDir = context.modules_dir
 
-    if not args.appPath:
-        args.appPath = os.path.dirname(context.find_firefox())
-
     if not args.xpcshell:
         args.xpcshell = os.path.join(args.appPath, 'xpcshell')
 
     if not args.pluginsPath:
         for path in context.ancestors(args.appPath, depth=2):
             test = os.path.join(path, 'plugins')
             if os.path.isdir(test):
                 args.pluginsPath = test