Index: build/util/lastchange.py |
diff --git a/build/util/lastchange.py b/build/util/lastchange.py |
index c7200f1e25165494192e35bd6bdeaffc03067175..e213d8b292fd00b3ccd4304349e445a1eeda3e7d 100755 |
--- a/build/util/lastchange.py |
+++ b/build/util/lastchange.py |
@@ -1,5 +1,5 @@ |
#!/usr/bin/env python |
-# Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+# Copyright (c) 2011 The Chromium Authors. All rights reserved. |
# Use of this source code is governed by a BSD-style license that can be |
# found in the LICENSE file. |
@@ -7,6 +7,7 @@ |
lastchange.py -- Chromium revision fetching utility. |
""" |
+import re |
import optparse |
import os |
import subprocess |
@@ -18,38 +19,10 @@ class VersionInfo(object): |
self.root = root |
self.revision = revision |
-def FetchGitRevision(directory): |
- """ |
- Fetch the Git hash for the a given directory. |
- |
- Errors are swallowed. |
- |
- Returns: |
- a VersionInfo object or None on error. |
- """ |
- # Force shell usage under cygwin & win32. This is a workaround for |
- # mysterious loss of cwd while invoking cygwin's git. |
- # We can't just pass shell=True to Popen, as under win32 this will |
- # cause CMD to be used, while we explicitly want a cygwin shell. |
- command = ['git', 'rev-parse', 'HEAD'] |
- if sys.platform in ('cygwin', 'win32'): |
- command = ['sh', '-c', ' '.join(command)] |
- try: |
- proc = subprocess.Popen(command, |
- stdout=subprocess.PIPE, |
- stderr=subprocess.PIPE, |
- cwd=directory) |
- except OSError: |
- return None |
- output = proc.communicate()[0].strip() |
- if proc.returncode == 0 and output: |
- return VersionInfo('git', 'git', output[:7]) |
- return None |
- |
def FetchSVNRevision(directory): |
""" |
- Fetch the Subversion branch and revision for the a given directory. |
+ Fetch the Subversion branch and revision for a given directory. |
Errors are swallowed. |
@@ -86,12 +59,139 @@ def FetchSVNRevision(directory): |
return VersionInfo(url, root, revision) |
+def RunGitCommand(directory, command): |
+ """ |
+ Launches git subcommand. |
+ |
+ Errors are swallowed. |
+ |
+ Returns: |
+ process object or None. |
+ """ |
+ command = ['git'] + command |
+ # Force shell usage under cygwin & win32. This is a workaround for |
+ # mysterious loss of cwd while invoking cygwin's git. |
+ # We can't just pass shell=True to Popen, as under win32 this will |
+ # cause CMD to be used, while we explicitly want a cygwin shell. |
+ if sys.platform in ('cygwin', 'win32'): |
+ command = ['sh', '-c', ' '.join(command)] |
+ try: |
+ proc = subprocess.Popen(command, |
+ stdout=subprocess.PIPE, |
+ stderr=subprocess.PIPE, |
+ cwd=directory) |
+ return proc |
+ except OSError: |
+ return None |
+ |
+ |
+def FetchGitRevision(directory): |
+ """ |
+ Fetch the Git hash for a given directory. |
+ |
+ Errors are swallowed. |
+ |
+ Returns: |
+ 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 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']) |
+ return (proc.wait() == 0) |
+ |
+ |
+def FetchGitSVNURL(directory): |
+ """ |
+ Fetch URL of SVN repository bound to git. |
+ |
+ Errors are swallowed. |
+ |
+ Returns: |
+ SVN URL. |
+ """ |
+ if not IsGitSVN(directory): |
+ return None |
+ proc = RunGitCommand(directory, ['svn', 'info', '--url']) |
+ if proc: |
+ output = proc.communicate()[0].strip() |
+ if proc.returncode == 0: |
+ return output |
+ return None |
+ |
+ |
+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('^\s*git-svn-id:\s+(\S+)@(\d+)', re.M) |
+ proc = RunGitCommand(directory, ['log', '-' + str(depth)]) |
+ if proc: |
+ for line in proc.stdout: |
+ match = git_re.search(line) |
+ if match: |
+ id = match.group(2) |
+ if id: |
+ proc.stdout.close() # Cut pipe for fast exit. |
+ return id |
+ return None |
+ |
+ |
+def IsGitSVNDirty(directory): |
+ """ |
+ Checks whether our git-svn tree contains clean trunk or some branch. |
+ |
+ Errors are swallowed. |
+ """ |
+ # For git branches the last commit message is either |
+ # some local commit or a merge. |
+ return LookupGitSVNRevision(directory, 1) is None |
Evan Martin
2011/03/02 00:03:59
I guess elsewhere people call local changes "dirty
Denis Lagno
2011/03/02 13:16:19
Current code should mark any local changes as "dir
|
+ |
+ |
+def FetchGitSVNRevision(directory): |
+ """ |
+ 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' |
+ return VersionInfo(FetchGitSVNURL(directory), 'git-svn', revision) |
+ |
+ |
def FetchVersionInfo(default_lastchange, directory=None): |
""" |
Returns the last change (in the form of a branch, revision tuple), |
from some appropriate revision control system. |
""" |
- version_info = FetchSVNRevision(directory) or FetchGitRevision(directory) |
+ version_info = (FetchSVNRevision(directory) or |
+ FetchGitSVNRevision(directory) or FetchGitRevision(directory)) |
if not version_info: |
if default_lastchange and os.path.exists(default_lastchange): |
revision = open(default_lastchange, 'r').read().strip() |