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 6to a C header file. 7 8Usage: 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 21import os 22import re 23import subprocess 24import sys 25 26def 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 53def 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 75def 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 88if len(sys.argv) != 4: 89 print "Wrong number of arguments" 90 sys.exit(1) 91 92git_directory = sys.argv[1] 93output_file = sys.argv[2] 94header_guard = sys.argv[3] 95 96value = FetchCommitPosition(git_directory) 97if not value: 98 print "Could not get last commit position." 99 sys.exit(1) 100 101WriteHeader(output_file, header_guard, value) 102