--- 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())