Bug 1278890 - Search for a firefox binary in the test package mach bootstrap, r=armenzg
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Wed, 13 Jul 2016 10:50:13 -0400
changeset 304956 06ca3f2b883b2eaeea2e37841dba283d0acfa0f2
parent 304955 d5cf90154e6710b1fcb748c9f934bbdf9dc93a0a
child 304957 45d6a990dd2877b9c8f265f13fc565a96f6667bf
push id30603
push userahalberstadt@mozilla.com
push dateThu, 14 Jul 2016 15:53:42 +0000
treeherderautoland@683bf5d3c1cd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarmenzg
bugs1278890
milestone50.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 1278890 - Search for a firefox binary in the test package mach bootstrap, r=armenzg When running test harnesses from the test package, the firefox binary will live somewhere outside of the mach context. There are two common situations where a developer might be running from a test package: 1) From a mozharness context 2) From an objdir context This patch will attempt to detect either of those situations and automagically find the firefox binary. MozReview-Commit-ID: fBAbfuG5XQ
testing/tools/mach_test_package_bootstrap.py
--- a/testing/tools/mach_test_package_bootstrap.py
+++ b/testing/tools/mach_test_package_bootstrap.py
@@ -1,41 +1,44 @@
 # 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/mozinfo',
-    'mozbase/mozscreenshot',
     'mozbase/moztest',
     'mozbase/mozversion',
-    'mozbase/manifestparser',
     'tools/mach',
     'tools/wptserve',
 ]
 
 # Individual files providing mach commands.
 MACH_MODULES = [
     'mochitest/mach_test_package_commands.py',
     'tools/mach/mach/commands/commandinfo.py',
@@ -55,22 +58,60 @@ CATEGORIES = {
     },
     '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.',
+        '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
+    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'))
+
+    # 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 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.')
@@ -80,20 +121,31 @@ def bootstrap(test_package_root):
     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:
             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.bin_dir = os.path.join(test_package_root, 'bin')
         context.modules_dir = os.path.join(test_package_root, 'modules')
 
+        context.ancestors = ancestors
+        context.find_firefox = types.MethodType(find_firefox, context)
+
+        # 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
+
     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: