1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/webrtc/trunk/build/util/lastchange.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,230 @@ 1.4 +#!/usr/bin/env python 1.5 +# Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.6 +# Use of this source code is governed by a BSD-style license that can be 1.7 +# found in the LICENSE file. 1.8 + 1.9 +""" 1.10 +lastchange.py -- Chromium revision fetching utility. 1.11 +""" 1.12 + 1.13 +import re 1.14 +import optparse 1.15 +import os 1.16 +import subprocess 1.17 +import sys 1.18 + 1.19 +_GIT_SVN_ID_REGEX = re.compile(r'.*git-svn-id:\s*([^@]*)@([0-9]+)', re.DOTALL) 1.20 + 1.21 +class VersionInfo(object): 1.22 + def __init__(self, url, revision): 1.23 + self.url = url 1.24 + self.revision = revision 1.25 + 1.26 + 1.27 +def FetchSVNRevision(directory, svn_url_regex): 1.28 + """ 1.29 + Fetch the Subversion branch and revision for a given directory. 1.30 + 1.31 + Errors are swallowed. 1.32 + 1.33 + Returns: 1.34 + A VersionInfo object or None on error. 1.35 + """ 1.36 + try: 1.37 + proc = subprocess.Popen(['svn', 'info'], 1.38 + stdout=subprocess.PIPE, 1.39 + stderr=subprocess.PIPE, 1.40 + cwd=directory, 1.41 + shell=(sys.platform=='win32')) 1.42 + except OSError: 1.43 + # command is apparently either not installed or not executable. 1.44 + return None 1.45 + if not proc: 1.46 + return None 1.47 + 1.48 + attrs = {} 1.49 + for line in proc.stdout: 1.50 + line = line.strip() 1.51 + if not line: 1.52 + continue 1.53 + key, val = line.split(': ', 1) 1.54 + attrs[key] = val 1.55 + 1.56 + try: 1.57 + match = svn_url_regex.search(attrs['URL']) 1.58 + if match: 1.59 + url = match.group(2) 1.60 + else: 1.61 + url = '' 1.62 + revision = attrs['Revision'] 1.63 + except KeyError: 1.64 + return None 1.65 + 1.66 + return VersionInfo(url, revision) 1.67 + 1.68 + 1.69 +def RunGitCommand(directory, command): 1.70 + """ 1.71 + Launches git subcommand. 1.72 + 1.73 + Errors are swallowed. 1.74 + 1.75 + Returns: 1.76 + A process object or None. 1.77 + """ 1.78 + command = ['git'] + command 1.79 + # Force shell usage under cygwin. This is a workaround for 1.80 + # mysterious loss of cwd while invoking cygwin's git. 1.81 + # We can't just pass shell=True to Popen, as under win32 this will 1.82 + # cause CMD to be used, while we explicitly want a cygwin shell. 1.83 + if sys.platform == 'cygwin': 1.84 + command = ['sh', '-c', ' '.join(command)] 1.85 + try: 1.86 + proc = subprocess.Popen(command, 1.87 + stdout=subprocess.PIPE, 1.88 + stderr=subprocess.PIPE, 1.89 + cwd=directory, 1.90 + shell=(sys.platform=='win32')) 1.91 + return proc 1.92 + except OSError: 1.93 + return None 1.94 + 1.95 + 1.96 +def FetchGitRevision(directory): 1.97 + """ 1.98 + Fetch the Git hash for a given directory. 1.99 + 1.100 + Errors are swallowed. 1.101 + 1.102 + Returns: 1.103 + A VersionInfo object or None on error. 1.104 + """ 1.105 + proc = RunGitCommand(directory, ['rev-parse', 'HEAD']) 1.106 + if proc: 1.107 + output = proc.communicate()[0].strip() 1.108 + if proc.returncode == 0 and output: 1.109 + return VersionInfo('git', output[:7]) 1.110 + return None 1.111 + 1.112 + 1.113 +def FetchGitSVNURLAndRevision(directory, svn_url_regex): 1.114 + """ 1.115 + Fetch the Subversion URL and revision through Git. 1.116 + 1.117 + Errors are swallowed. 1.118 + 1.119 + Returns: 1.120 + A tuple containing the Subversion URL and revision. 1.121 + """ 1.122 + proc = RunGitCommand(directory, ['log', '-1', 1.123 + '--grep=git-svn-id', '--format=%b']) 1.124 + if proc: 1.125 + output = proc.communicate()[0].strip() 1.126 + if proc.returncode == 0 and output: 1.127 + # Extract the latest SVN revision and the SVN URL. 1.128 + # The target line is the last "git-svn-id: ..." line like this: 1.129 + # git-svn-id: svn://svn.chromium.org/chrome/trunk/src@85528 0039d316.... 1.130 + match = _GIT_SVN_ID_REGEX.search(output) 1.131 + if match: 1.132 + revision = match.group(2) 1.133 + url_match = svn_url_regex.search(match.group(1)) 1.134 + if url_match: 1.135 + url = url_match.group(2) 1.136 + else: 1.137 + url = '' 1.138 + return url, revision 1.139 + return None, None 1.140 + 1.141 + 1.142 +def FetchGitSVNRevision(directory, svn_url_regex): 1.143 + """ 1.144 + Fetch the Git-SVN identifier for the local tree. 1.145 + 1.146 + Errors are swallowed. 1.147 + """ 1.148 + url, revision = FetchGitSVNURLAndRevision(directory, svn_url_regex) 1.149 + if url and revision: 1.150 + return VersionInfo(url, revision) 1.151 + return None 1.152 + 1.153 + 1.154 +def FetchVersionInfo(default_lastchange, directory=None, 1.155 + directory_regex_prior_to_src_url='chrome|svn'): 1.156 + """ 1.157 + Returns the last change (in the form of a branch, revision tuple), 1.158 + from some appropriate revision control system. 1.159 + """ 1.160 + svn_url_regex = re.compile( 1.161 + r'.*/(' + directory_regex_prior_to_src_url + r')(/.*)') 1.162 + 1.163 + version_info = (FetchSVNRevision(directory, svn_url_regex) or 1.164 + FetchGitSVNRevision(directory, svn_url_regex) or 1.165 + FetchGitRevision(directory)) 1.166 + if not version_info: 1.167 + if default_lastchange and os.path.exists(default_lastchange): 1.168 + revision = open(default_lastchange, 'r').read().strip() 1.169 + version_info = VersionInfo(None, revision) 1.170 + else: 1.171 + version_info = VersionInfo(None, None) 1.172 + return version_info 1.173 + 1.174 + 1.175 +def WriteIfChanged(file_name, contents): 1.176 + """ 1.177 + Writes the specified contents to the specified file_name 1.178 + iff the contents are different than the current contents. 1.179 + """ 1.180 + try: 1.181 + old_contents = open(file_name, 'r').read() 1.182 + except EnvironmentError: 1.183 + pass 1.184 + else: 1.185 + if contents == old_contents: 1.186 + return 1.187 + os.unlink(file_name) 1.188 + open(file_name, 'w').write(contents) 1.189 + 1.190 + 1.191 +def main(argv=None): 1.192 + if argv is None: 1.193 + argv = sys.argv 1.194 + 1.195 + parser = optparse.OptionParser(usage="lastchange.py [options]") 1.196 + parser.add_option("-d", "--default-lastchange", metavar="FILE", 1.197 + help="default last change input FILE") 1.198 + parser.add_option("-o", "--output", metavar="FILE", 1.199 + help="write last change to FILE") 1.200 + parser.add_option("--revision-only", action='store_true', 1.201 + help="just print the SVN revision number") 1.202 + opts, args = parser.parse_args(argv[1:]) 1.203 + 1.204 + out_file = opts.output 1.205 + 1.206 + while len(args) and out_file is None: 1.207 + if out_file is None: 1.208 + out_file = args.pop(0) 1.209 + if args: 1.210 + sys.stderr.write('Unexpected arguments: %r\n\n' % args) 1.211 + parser.print_help() 1.212 + sys.exit(2) 1.213 + 1.214 + version_info = FetchVersionInfo(opts.default_lastchange, 1.215 + os.path.dirname(sys.argv[0])) 1.216 + 1.217 + if version_info.revision == None: 1.218 + version_info.revision = '0' 1.219 + 1.220 + if opts.revision_only: 1.221 + print version_info.revision 1.222 + else: 1.223 + contents = "LASTCHANGE=%s\n" % version_info.revision 1.224 + if out_file: 1.225 + WriteIfChanged(out_file, contents) 1.226 + else: 1.227 + sys.stdout.write(contents) 1.228 + 1.229 + return 0 1.230 + 1.231 + 1.232 +if __name__ == '__main__': 1.233 + sys.exit(main())