|  | # Copyright 2014 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. | 
|  |  | 
|  | """Writes the most recent "Cr-Commit-Position" value on the master branch | 
|  | to a C header file. | 
|  |  | 
|  | Usage: last_commit_position.py <dir> <outfile> <headerguard> | 
|  |  | 
|  | <dir> | 
|  | Some directory inside the repo to check. This will be used as the current | 
|  | directory when running git. It's best to pass the repo toplevel directory. | 
|  |  | 
|  | <outfile> | 
|  | C header file to write. | 
|  |  | 
|  | <headerguard> | 
|  | String to use as the header guard for the written file. | 
|  | """ | 
|  |  | 
|  | import os | 
|  | import re | 
|  | import subprocess | 
|  | import sys | 
|  |  | 
|  | def RunGitCommand(directory, command): | 
|  | """ | 
|  | Launches git subcommand. | 
|  |  | 
|  | Errors are swallowed. | 
|  |  | 
|  | Returns: | 
|  | A process object or None. | 
|  | """ | 
|  | command = ['git'] + command | 
|  | # Force shell usage under cygwin. 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 == 'cygwin': | 
|  | command = ['sh', '-c', ' '.join(command)] | 
|  | try: | 
|  | proc = subprocess.Popen(command, | 
|  | stdout=subprocess.PIPE, | 
|  | stderr=subprocess.PIPE, | 
|  | cwd=directory, | 
|  | shell=(sys.platform=='win32')) | 
|  | return proc | 
|  | except OSError: | 
|  | return None | 
|  |  | 
|  |  | 
|  | def FetchCommitPosition(directory): | 
|  | regex = re.compile(r'\s*Cr-Commit-Position: refs/heads/master@\{#(\d+)\}\s*') | 
|  |  | 
|  | # Search this far backward in the git log. The commit position should be | 
|  | # close to the top. We allow some slop for long commit messages, and maybe | 
|  | # there were some local commits after the last "official" one. Having this | 
|  | # max prevents us from searching all history in the case of an error. | 
|  | max_lines = 2048 | 
|  |  | 
|  | proc = RunGitCommand(directory, ['log']) | 
|  | for i in range(max_lines): | 
|  | line = proc.stdout.readline() | 
|  | if not line: | 
|  | return None | 
|  |  | 
|  | match = regex.match(line) | 
|  | if match: | 
|  | return match.group(1) | 
|  |  | 
|  | return None | 
|  |  | 
|  |  | 
|  | def WriteHeader(header_file, header_guard, value): | 
|  | with open(header_file, 'w') as f: | 
|  | f.write('''/* Generated by last_commit_position.py. */ | 
|  |  | 
|  | #ifndef %(guard)s | 
|  | #define %(guard)s | 
|  |  | 
|  | #define LAST_COMMIT_POSITION "%(value)s" | 
|  |  | 
|  | #endif | 
|  | ''' % {'guard': header_guard, 'value': value}) | 
|  |  | 
|  |  | 
|  | if len(sys.argv) != 4: | 
|  | print "Wrong number of arguments" | 
|  | sys.exit(1) | 
|  |  | 
|  | git_directory = sys.argv[1] | 
|  | output_file = sys.argv[2] | 
|  | header_guard = sys.argv[3] | 
|  |  | 
|  | value = FetchCommitPosition(git_directory) | 
|  | if not value: | 
|  | value = 'UNKNOWN' | 
|  |  | 
|  | WriteHeader(output_file, header_guard, value) |