Bug 1377216 - Use configure-derived VCS info to find repository; r=glandium
☠☠ backed out by b31c56eb6317 ☠ ☠
authorGregory Szorc <gps@mozilla.com>
Tue, 18 Jul 2017 15:46:47 -0700
changeset 418505 b5701f3ce50613dc6c88f76e177631676ddbe2a9
parent 418504 1f37aebe0f438dc0a8d05708d407c43046812bdc
child 418506 60d2ef10e6ff8cf65950b760ffcd39792c16d9ec
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium
bugs1377216
milestone56.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 1377216 - Use configure-derived VCS info to find repository; r=glandium For reasons I can't explain, Windows builds are failing intermittently because they are unable to locate the `hg` binary when running some SpiderMonkey test processes. These processes use mozversioncontrol.get_repository_from_env() to locate the current repository. We now store VCS info in configure. This makes it available to anything running in a build system context. This commit teaches mozversioncontrol.get_repository_from_env() to import the "buildconfig" module to locate VCS info. If the module can be imported, it is the sole source of VCS info. Otherwise, we fall back to the existing detection mechanisms. This should get rid of the intermittent failure. If it doesn't, it is still a step in the right direction because it will allow build system processes to consistently use a well-defined VCS binary. MozReview-Commit-ID: DMxXheJLRqH
python/mozversioncontrol/mozversioncontrol/__init__.py
--- a/python/mozversioncontrol/mozversioncontrol/__init__.py
+++ b/python/mozversioncontrol/mozversioncontrol/__init__.py
@@ -8,16 +8,19 @@ import os
 import re
 import subprocess
 import which
 
 from distutils.version import LooseVersion
 
 def get_tool_path(tool):
     """Obtain the path of `tool`."""
+    if os.path.isabs(tool) and os.path.exists(tool):
+        return tool
+
     # We use subprocess in places, which expects a Win32 executable or
     # batch script. On some versions of MozillaBuild, we have "hg.exe",
     # "hg.bat," and "hg" (a Python script). "which" will happily return the
     # Python script, which will cause subprocess to choke. Explicitly favor
     # the Windows version over the plain script.
     try:
         return which.which(tool + '.exe')
     except which.WhichError:
@@ -78,18 +81,18 @@ class Repository(object):
 
     def get_files_in_working_directory(self):
         """Obtain a list of managed files in the working directory."""
         raise NotImplementedError
 
 
 class HgRepository(Repository):
     '''An implementation of `Repository` for Mercurial repositories.'''
-    def __init__(self, path):
-        super(HgRepository, self).__init__(path, 'hg')
+    def __init__(self, path, hg='hg'):
+        super(HgRepository, self).__init__(path, tool=hg)
         self._env[b'HGPLAIN'] = b'1'
 
     def get_modified_files(self):
         # Use --no-status to print just the filename.
         return self._run('status', '--modified', '--no-status').splitlines()
 
     def get_added_files(self):
         # Use --no-status to print just the filename.
@@ -107,18 +110,18 @@ class HgRepository(Repository):
     def get_files_in_working_directory(self):
         # Can return backslashes on Windows. Normalize to forward slashes.
         return list(p.replace('\\', '/') for p in
                     self._run('files', '-0').split('\0'))
 
 
 class GitRepository(Repository):
     '''An implementation of `Repository` for Git repositories.'''
-    def __init__(self, path):
-        super(GitRepository, self).__init__(path, 'git')
+    def __init__(self, path, git='git'):
+        super(GitRepository, self).__init__(path, tool=git)
 
     def get_modified_files(self):
         return self._run('diff', '--diff-filter=M', '--name-only').splitlines()
 
     def get_added_files(self):
         return self._run('diff', '--diff-filter=A', '--name-only').splitlines()
 
     def add_remove_files(self, path):
@@ -143,25 +146,64 @@ def get_repository_object(path):
         return HgRepository(path)
     elif os.path.exists(os.path.join(path, '.git')):
         return GitRepository(path)
     else:
         raise InvalidRepoPath('Unknown VCS, or not a source checkout: %s' %
                               path)
 
 
+class MissingVCSInfo(Exception):
+    """Represents a general failure to resolve a VCS interface."""
+
+
+class MissingConfigureInfo(MissingVCSInfo):
+    """Represents error finding VCS info from configure data."""
+
+
 def get_repository_from_env():
-    """Obtain a repository object by looking at the environment."""
+    """Obtain a repository object by looking at the environment.
+
+    If inside a build environment (denoted by presence of a ``buildconfig``
+    module), VCS info is obtained from it, as found via configure. This allows
+    us to respect what was passed into configure. Otherwise, we fall back to
+    scanning the filesystem.
+    """
+    try:
+        import buildconfig
+
+        flavor = buildconfig.substs.get('VCS_CHECKOUT_TYPE')
+
+        # If in build mode, only use what configure found. That way we ensure
+        # that everything in the build system can be controlled via configure.
+        if not flavor:
+            raise MissingConfigureInfo('could not find VCS_CHECKOUT_TYPE '
+                                       'in build config; check configure '
+                                       'output and verify it could find a '
+                                       'VCS binary')
+
+        if flavor == 'hg':
+            return HgRepository(buildconfig.topsrcdir,
+                                hg=buildconfig.substs['HG'])
+        elif flavor == 'git':
+            return GitRepository(buildconfig.topsrcdir,
+                                 git=buildconfig.subst['GIT'])
+        else:
+            raise MissingVCSInfo('unknown VCS_CHECKOUT_TYPE value: %s' % flavor)
+
+    except ImportError:
+        pass
+
     def ancestors(path):
         while path:
             yield path
             path, child = os.path.split(path)
             if child == '':
                 break
 
     for path in ancestors(os.getcwd()):
         try:
             return get_repository_object(path)
         except InvalidRepoPath:
             continue
 
-    raise Exception('Could not find Mercurial or Git checkout for %s' %
-                    os.getcwd())
+    raise MissingVCSInfo('Could not find Mercurial or Git checkout for %s' %
+                         os.getcwd())