Bug 1392886 - Ignore missing mach_commands.py when checkout is sparse; r=mshal
authorGregory Szorc <gps@mozilla.com>
Wed, 23 Aug 2017 08:41:01 -0700
changeset 376355 fe3097dc8f81e6ac1a00468cc09a9e08f1e0db87
parent 376354 912e5862f90b11346d4c3b2203696c1831cab9c9
child 376356 4f88a4a7e8fb88eb0446b8336d81bc2c001237b3
push id32382
push userkwierso@gmail.com
push dateWed, 23 Aug 2017 23:07:08 +0000
treeherdermozilla-central@f0abd25e1f4a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
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 1392886 - Ignore missing mach_commands.py when checkout is sparse; r=mshal Sparse checkouts may not have all mach_commands.py files. mach raises an error when a mach_commands.py file is missing. So, we teach the mach driver to ignore missing file errors when a sparse checkout is present. The added code is optimized to avoid an import of mozversioncontrol and some I/O as part of resolving the repo and VCS binaries because this file is in the critical path of all mach commands and avoiding I/O is worthwhile. Since we aren't using sparse checkouts in the common case, this effectively makes the new code 0 cost. MozReview-Commit-ID: C6itJga31t5
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -149,22 +149,38 @@ def bootstrap(topsrcdir, mozilla_dir=Non
     # existing) and notify the user that it will be created. The logic for
     # creation is much simpler for the "advanced" environment variable use
     # case. For default behavior, we educate users and give them an opportunity
     # to react. We always exit after creating the directory because users don't
     # like surprises.
     sys.path[0:0] = [os.path.join(mozilla_dir, path)
                      for path in search_path(mozilla_dir,
+    import mach.base
     import mach.main
     from mozboot.util import get_state_dir
     from mozbuild.util import patch_main
+    def resolve_repository():
+        import mozversioncontrol
+        try:
+            # This API doesn't respect the vcs binary choices from configure.
+            # If we ever need to use the VCS binary here, consider something
+            # more robust.
+            return mozversioncontrol.get_repository_object(path=mozilla_dir)
+        except mozversioncontrol.InvalidRepoPath:
+            return None
+        # This is mainly to catch failures resolving the VCS binary path.
+        # TODO Change mozversioncontrol to raise non-generic exception.
+        except Exception:
+            return None
     def telemetry_handler(context, data):
         # We have not opted-in to telemetry
         if 'BUILD_SYSTEM_TELEMETRY' not in os.environ:
         telemetry_dir = os.path.join(get_state_dir()[0], 'telemetry')
@@ -277,33 +293,44 @@ def bootstrap(topsrcdir, mozilla_dir=Non
             return topsrcdir
         if key == 'telemetry_handler':
             return telemetry_handler
         if key == 'post_dispatch_handler':
             return post_dispatch_handler
+        if key == 'repository':
+            return resolve_repository()
         raise AttributeError(key)
     driver = mach.main.Mach(os.getcwd())
     driver.populate_context_handler = populate_context
     if not driver.settings_paths:
         # default global machrc location
     # always load local repository configuration
     for category, meta in CATEGORIES.items():
         driver.define_category(category, meta['short'], meta['long'],
+    repo = resolve_repository()
     for path in MACH_MODULES:
-        driver.load_commands_from_file(os.path.join(mozilla_dir, path))
+        # Sparse checkouts may not have all mach_commands.py files. Ignore
+        # errors from missing files.
+        try:
+            driver.load_commands_from_file(os.path.join(mozilla_dir, path))
+        except mach.base.MissingFileError:
+            if not repo or not repo.sparse_checkout_present():
+                raise
     return driver
 # Hook import such that .pyc/.pyo files without a corresponding .py file in
 # the source directory are essentially ignored. See further below for details
 # and caveats.
 # Objdirs outside the source directory are ignored because in most cases, if