Bug 1216817 - Part 5: Run |mach artifact install| automatically when asked. r=glandium
authorNick Alexander <nalexander@mozilla.com>
Wed, 23 Dec 2015 14:25:37 -0800
changeset 300195 e9e84784daf92455a07a563864284ed6047eb50b
parent 300194 90b7e77b7f67f1ae0c9394d9e6db7c869a39011b
child 300196 b1a1e53f1112e2e25f14d3f2f0f602b015fe7f48
push id8978
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 14:05:32 +0000
treeherdermozilla-aurora@b9a803752a2c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium
bugs1216817
milestone46.0a1
Bug 1216817 - Part 5: Run |mach artifact install| automatically when asked. r=glandium It turns out to be much easier to hook |mach artifact install| into config.status and |mach build| than to hook into client.mk. The additional virtualenv package avoids an import error when running |mach artifact install|.
build/virtualenv_packages.txt
python/mozbuild/mozbuild/base.py
python/mozbuild/mozbuild/config_status.py
python/mozbuild/mozbuild/mach_commands.py
--- a/build/virtualenv_packages.txt
+++ b/build/virtualenv_packages.txt
@@ -28,8 +28,9 @@ gyp.pth:media/webrtc/trunk/tools/gyp/pyl
 pyasn1.pth:python/pyasn1
 pyasn1_modules.pth:python/pyasn1-modules
 bitstring.pth:python/bitstring
 redo.pth:python/redo
 requests.pth:python/requests
 rsa.pth:python/rsa
 futures.pth:python/futures
 ecc.pth:python/PyECC
+xpcshell.pth:testing/xpcshell
--- a/python/mozbuild/mozbuild/base.py
+++ b/python/mozbuild/mozbuild/base.py
@@ -252,17 +252,17 @@ class MozbuildObject(ProcessExecutionMix
         If configure's output is not available, this will raise.
         """
         if self._config_environment:
             return self._config_environment
 
         config_status = os.path.join(self.topobjdir, 'config.status')
 
         if not os.path.exists(config_status):
-            raise Exception('config.status not available. Run configure.')
+            raise BuildEnvironmentNotFoundException('config.status not available. Run configure.')
 
         self._config_environment = \
             ConfigEnvironment.from_config_status(config_status)
 
         return self._config_environment
 
     @property
     def defines(self):
--- a/python/mozbuild/mozbuild/config_status.py
+++ b/python/mozbuild/mozbuild/config_status.py
@@ -5,16 +5,17 @@
 # Combined with build/autoconf/config.status.m4, ConfigStatus is an almost
 # drop-in replacement for autoconf 2.13's config.status, with features
 # borrowed from autoconf > 2.5, and additional features.
 
 from __future__ import absolute_import, print_function
 
 import logging
 import os
+import subprocess
 import sys
 import time
 
 from argparse import ArgumentParser
 
 from mach.logging import LoggingManager
 from mozbuild.backend.configenvironment import ConfigEnvironment
 from mozbuild.backend.recursivemake import RecursiveMakeBackend
@@ -204,8 +205,13 @@ def config_status(topobjdir='.', topsrcd
     # Advertise Visual Studio if appropriate.
     if os.name == 'nt' and 'VisualStudio' not in options.backend:
         print(VISUAL_STUDIO_ADVERTISEMENT)
 
     # Advertise Eclipse if it is appropriate.
     if MachCommandConditions.is_android(env):
         if 'AndroidEclipse' not in options.backend:
             print(ANDROID_IDE_ADVERTISEMENT)
+
+    if env.substs['MOZ_ARTIFACT_BUILDS']:
+        # Execute |mach artifact install| from the top source directory.
+        os.chdir(topsrcdir)
+        return subprocess.check_call([sys.executable, os.path.join(topsrcdir, 'mach'), 'artifact', 'install'])
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -20,16 +20,17 @@ from mach.decorators import (
     CommandArgumentGroup,
     CommandProvider,
     Command,
 )
 
 from mach.mixin.logging import LoggingMixin
 
 from mozbuild.base import (
+    BuildEnvironmentNotFoundException,
     MachCommandBase,
     MachCommandConditions as conditions,
     MozbuildObject,
     MozconfigFindException,
     MozconfigLoadException,
     ObjdirMismatchException,
 )
 
@@ -376,30 +377,46 @@ class Build(MachCommandBase):
                 # backend. But that involves make reinvoking itself and there
                 # are undesired side-effects of this. See bug 877308 for a
                 # comprehensive history lesson.
                 self._run_make(directory=self.topobjdir,
                     target='backend.RecursiveMakeBackend',
                     line_handler=output.on_line, log=False,
                     print_directory=False)
 
+                if self.substs['MOZ_ARTIFACT_BUILDS']:
+                    self._run_mach_artifact_install()
+
                 # Build target pairs.
                 for make_dir, make_target in target_pairs:
                     # We don't display build status messages during partial
                     # tree builds because they aren't reliable there. This
                     # could potentially be fixed if the build monitor were more
                     # intelligent about encountering undefined state.
                     status = self._run_make(directory=make_dir, target=make_target,
                         line_handler=output.on_line, log=False, print_directory=False,
                         ensure_exit_code=False, num_jobs=jobs, silent=not verbose,
                         append_env={b'NO_BUILDSTATUS_MESSAGES': b'1'})
 
                     if status != 0:
                         break
             else:
+                try:
+                    if self.substs['MOZ_ARTIFACT_BUILDS']:
+                        self._run_mach_artifact_install()
+                except BuildEnvironmentNotFoundException:
+                    # Can't read self.substs from config.status?  That means we
+                    # need to run configure.  The client.mk invocation below
+                    # will configure, which will run config.status, which will
+                    # invoke |mach artifact install| itself before continuing
+                    # the build.  Therefore, we needn't install artifacts
+                    # ourselves.
+                    self.log(logging.DEBUG, 'artifact',
+                             {}, "Not running |mach artifact install| -- it will be run by client.mk.")
+
                 monitor.start_resource_recording()
                 status = self._run_make(srcdir=True, filename='client.mk',
                     line_handler=output.on_line, log=False, print_directory=False,
                     allow_parallel=False, ensure_exit_code=False, num_jobs=jobs,
                     silent=not verbose)
 
                 make_extra = self.mozconfig['make_extra'] or []
                 make_extra = dict(m.split('=', 1) for m in make_extra)
@@ -597,16 +614,28 @@ class Build(MachCommandBase):
             args.append('--backend')
             args.extend(backend)
         if diff:
             args.append('--diff')
 
         return self._run_command_in_objdir(args=args, pass_thru=True,
             ensure_exit_code=False)
 
+    def _run_mach_artifact_install(self):
+        # We'd like to launch artifact using
+        # self._mach_context.commands.dispatch.  However, artifact activates
+        # the virtualenv, which plays badly with the rest of this code.
+        # Therefore, we run |mach artifact install| in a new process (and
+        # throw an exception if it fails).
+        self.log(logging.INFO, 'artifact',
+                 {}, "Running |mach artifact install|.")
+        args = [os.path.join(self.topsrcdir, 'mach'), 'artifact', 'install']
+        self._run_command_in_srcdir(args=args,
+            pass_thru=True, ensure_exit_code=True)
+
 @CommandProvider
 class Doctor(MachCommandBase):
     """Provide commands for diagnosing common build environment problems"""
     @Command('doctor', category='devenv',
         description='')
     @CommandArgument('--fix', default=None, action='store_true',
         help='Attempt to fix found problems.')
     def doctor(self, fix=None):