1 # Copyright 2014 The Chromium Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 """Writes the most recent "Cr-Commit-Position" value on the master branch 6 to a C header file. 7 8 Usage: last_commit_position.py <dir> <outfile> <headerguard> 9 10 <dir> 11 Some directory inside the repo to check. This will be used as the current 12 directory when running git. It's best to pass the repo toplevel directory. 13 14 <outfile> 15 C header file to write. 16 17 <headerguard> 18 String to use as the header guard for the written file. 19 """ 20 21 import os 22 import re 23 import subprocess 24 import sys 25 26 def RunGitCommand(directory, command): 27 """ 28 Launches git subcommand. 29 30 Errors are swallowed. 31 32 Returns: 33 A process object or None. 34 """ 35 command = ['git'] + command 36 # Force shell usage under cygwin. This is a workaround for 37 # mysterious loss of cwd while invoking cygwin's git. 38 # We can't just pass shell=True to Popen, as under win32 this will 39 # cause CMD to be used, while we explicitly want a cygwin shell. 40 if sys.platform == 'cygwin': 41 command = ['sh', '-c', ' '.join(command)] 42 try: 43 proc = subprocess.Popen(command, 44 stdout=subprocess.PIPE, 45 stderr=subprocess.PIPE, 46 cwd=directory, 47 shell=(sys.platform=='win32')) 48 return proc 49 except OSError: 50 return None 51 52 53 def FetchCommitPosition(directory): 54 regex = re.compile(r'\s*Cr-Commit-Position: refs/heads/master@\{#(\d+)\}\s*') 55 56 # Search this far backward in the git log. The commit position should be 57 # close to the top. We allow some slop for long commit messages, and maybe 58 # there were some local commits after the last "official" one. Having this 59 # max prevents us from searching all history in the case of an error. 60 max_lines = 2048 61 62 proc = RunGitCommand(directory, ['log']) 63 for i in range(max_lines): 64 line = proc.stdout.readline() 65 if not line: 66 return None 67 68 match = regex.match(line) 69 if match: 70 return match.group(1) 71 72 return None 73 74 75 def WriteHeader(header_file, header_guard, value): 76 with open(header_file, 'w') as f: 77 f.write('''/* Generated by last_commit_position.py. */ 78 79 #ifndef %(guard)s 80 #define %(guard)s 81 82 #define LAST_COMMIT_POSITION "%(value)s" 83 84 #endif 85 ''' % {'guard': header_guard, 'value': value}) 86 87 88 if len(sys.argv) != 4: 89 print "Wrong number of arguments" 90 sys.exit(1) 91 92 git_directory = sys.argv[1] 93 output_file = sys.argv[2] 94 header_guard = sys.argv[3] 95 96 value = FetchCommitPosition(git_directory) 97 if not value: 98 print "Could not get last commit position." 99 sys.exit(1) 100 101 WriteHeader(output_file, header_guard, value) 102