Index: build/util/lastchange.py |
diff --git a/build/util/lastchange.py b/build/util/lastchange.py |
index 4d7a1fe808d4a2707c0378ddef54d3f41a267144..870bf07459da14c7a69b591a2aa2cc59b8740932 100755 |
--- a/build/util/lastchange.py |
+++ b/build/util/lastchange.py |
@@ -13,21 +13,22 @@ import os |
import subprocess |
import sys |
+_GIT_SVN_ID_REGEX = re.compile(r'.*git-svn-id:\s*([^@]*)@([0-9]+)', re.DOTALL) |
+ |
class VersionInfo(object): |
- def __init__(self, url, root, revision): |
+ def __init__(self, url, revision): |
self.url = url |
- self.root = root |
self.revision = revision |
-def FetchSVNRevision(directory): |
+def FetchSVNRevision(directory, svn_url_regex): |
""" |
Fetch the Subversion branch and revision for a given directory. |
Errors are swallowed. |
Returns: |
- a VersionInfo object or None on error. |
+ A VersionInfo object or None on error. |
""" |
try: |
proc = subprocess.Popen(['svn', 'info'], |
@@ -50,13 +51,16 @@ def FetchSVNRevision(directory): |
attrs[key] = val |
try: |
- url = attrs['URL'] |
- root = attrs['Repository Root'] |
+ match = svn_url_regex.search(attrs['URL']) |
+ if match: |
+ url = match.group(2) |
+ else: |
+ url = '' |
revision = attrs['Revision'] |
except KeyError: |
return None |
- return VersionInfo(url, root, revision) |
+ return VersionInfo(url, revision) |
def RunGitCommand(directory, command): |
@@ -66,7 +70,7 @@ def RunGitCommand(directory, command): |
Errors are swallowed. |
Returns: |
- process object or None. |
+ A process object or None. |
""" |
command = ['git'] + command |
# Force shell usage under cygwin & win32. This is a workaround for |
@@ -92,140 +96,101 @@ def FetchGitRevision(directory): |
Errors are swallowed. |
Returns: |
- a VersionInfo object or None on error. |
+ A VersionInfo object or None on error. |
""" |
proc = RunGitCommand(directory, ['rev-parse', 'HEAD']) |
if proc: |
output = proc.communicate()[0].strip() |
if proc.returncode == 0 and output: |
- return VersionInfo('git', 'git', output[:7]) |
+ return VersionInfo('git', output[:7]) |
return None |
-def IsGitSVN(directory): |
- """ |
- Checks whether git-svn has been set up. |
- |
- Errors are swallowed. |
- |
- Returns: |
- whether git-svn has been set up. |
- """ |
- # To test whether git-svn has been set up, query the config for any |
- # svn-related configuration. This command exits with an error code |
- # if there aren't any matches, so ignore its output. |
- proc = RunGitCommand(directory, ['config', '--get-regexp', '^svn']) |
- if proc: |
- return (proc.wait() == 0) |
- return False |
- |
- |
-def FetchGitSVNURL(directory): |
- """ |
- Fetch URL of SVN repository bound to git. |
- |
- Errors are swallowed. |
- |
- Returns: |
- SVN URL. |
- """ |
- if IsGitSVN(directory): |
- proc = RunGitCommand(directory, ['svn', 'info', '--url']) |
- if proc: |
- output = proc.communicate()[0].strip() |
- if proc.returncode == 0: |
- match = re.search(r'^\w+://.*$', output, re.M) |
- if match: |
- return match.group(0) |
- return '' |
- |
- |
-def FetchGitSVNRoot(directory): |
+def FetchGitSVNURLAndRevision(directory, svn_url_regex): |
""" |
- Fetch root of SVN repository bound to git. |
+ Fetch the Subversion URL and revision through Git. |
Errors are swallowed. |
Returns: |
- SVN root repository. |
+ A tuple containing the Subversion URL and revision. |
""" |
- if IsGitSVN(directory): |
- git_command = ['config', '--get-regexp', '^svn-remote.svn.url$'] |
- proc = RunGitCommand(directory, git_command) |
- if proc: |
- output = proc.communicate()[0].strip() |
- if proc.returncode == 0: |
- # Zero return code implies presence of requested configuration variable. |
- # Its value is second (last) field of output. |
- match = re.search(r'\S+$', output) |
- if match: |
- return match.group(0) |
- return '' |
- |
- |
-def LookupGitSVNRevision(directory, depth): |
- """ |
- Fetch the Git-SVN identifier for the local tree. |
- Parses first |depth| commit messages. |
- |
- Errors are swallowed. |
- """ |
- if not IsGitSVN(directory): |
- return None |
- git_re = re.compile(r'^\s*git-svn-id:\s+(\S+)@(\d+)') |
- proc = RunGitCommand(directory, ['log', '-' + str(depth)]) |
+ proc = RunGitCommand(directory, ['log', '-1', |
+ '--grep=git-svn-id', '--format=%b']) |
if proc: |
- for line in proc.stdout: |
- match = git_re.match(line) |
+ output = proc.communicate()[0].strip() |
+ if proc.returncode == 0 and output: |
+ # Extract the latest SVN revision and the SVN URL. |
+ # The target line is the last "git-svn-id: ..." line like this: |
+ # git-svn-id: svn://svn.chromium.org/chrome/trunk/src@85528 0039d316.... |
+ match = _GIT_SVN_ID_REGEX.search(output) |
if match: |
- id = match.group(2) |
- if id: |
- proc.stdout.close() # Cut pipe for fast exit. |
- return id |
- return None |
+ revision = match.group(2) |
+ url_match = svn_url_regex.search(match.group(1)) |
+ if url_match: |
+ url = url_match.group(2) |
+ else: |
+ url = '' |
+ return url, revision |
+ return None, None |
def IsGitSVNDirty(directory): |
""" |
- Checks whether our git-svn tree contains clean trunk or some branch. |
+ Checks whether our git-svn tree contains clean trunk or any local changes. |
Errors are swallowed. |
""" |
- # For git branches the last commit message is either |
- # some local commit or a merge. |
- return LookupGitSVNRevision(directory, 1) is None |
+ proc = RunGitCommand(directory, ['log', '-1']) |
+ if proc: |
+ output = proc.communicate()[0].strip() |
+ if proc.returncode == 0 and output: |
+ # Extract the latest SVN revision and the SVN URL. |
+ # The target line is the last "git-svn-id: ..." line like this: |
+ # git-svn-id: svn://svn.chromium.org/chrome/trunk/src@85528 0039d316.... |
+ match = _GIT_SVN_ID_REGEX.search(output) |
+ if match: |
+ # Check if there are any local uncommitted changes. |
+ proc = RunGitCommand(directory, ['checkout']) |
+ if proc: |
+ output = proc.communicate()[0].strip() |
+ if proc.returncode == 0 and not output: |
+ return False |
+ return True |
-def FetchGitSVNRevision(directory): |
+def FetchGitSVNRevision(directory, svn_url_regex): |
""" |
Fetch the Git-SVN identifier for the local tree. |
Errors are swallowed. |
""" |
- # We assume that at least first 999 commit messages contain svn evidence. |
- revision = LookupGitSVNRevision(directory, 999) |
- if not revision: |
- return None |
- if IsGitSVNDirty(directory): |
- revision = revision + '-dirty' |
- url = FetchGitSVNURL(directory) |
- root = FetchGitSVNRoot(directory) |
- return VersionInfo(url, root, revision) |
+ url, revision = FetchGitSVNURLAndRevision(directory, svn_url_regex) |
+ if url and revision: |
+ if IsGitSVNDirty(directory): |
+ revision = revision + '-dirty' |
+ return VersionInfo(url, revision) |
+ return None |
-def FetchVersionInfo(default_lastchange, directory=None): |
+def FetchVersionInfo(default_lastchange, directory=None, |
+ directory_regex_prior_to_src_url='chrome|svn'): |
""" |
Returns the last change (in the form of a branch, revision tuple), |
from some appropriate revision control system. |
""" |
- version_info = (FetchSVNRevision(directory) or |
- FetchGitSVNRevision(directory) or FetchGitRevision(directory)) |
+ svn_url_regex = re.compile( |
+ r'.*/(' + directory_regex_prior_to_src_url + r')(/.*)') |
+ |
+ version_info = (FetchSVNRevision(directory, svn_url_regex) or |
+ FetchGitSVNRevision(directory, svn_url_regex) or |
+ FetchGitRevision(directory)) |
if not version_info: |
if default_lastchange and os.path.exists(default_lastchange): |
revision = open(default_lastchange, 'r').read().strip() |
- version_info = VersionInfo(None, None, revision) |
+ version_info = VersionInfo(None, revision) |
else: |
- version_info = VersionInfo('unknown', '', '0') |
+ version_info = VersionInfo(None, None) |
return version_info |
@@ -270,6 +235,9 @@ def main(argv=None): |
version_info = FetchVersionInfo(opts.default_lastchange) |
+ if version_info.revision == None: |
+ version_info.revision = '0' |
+ |
if opts.revision_only: |
print version_info.revision |
else: |