1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*6777b538SAndroid Build Coastguard Worker# Copyright 2012 The Chromium Authors 3*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file. 5*6777b538SAndroid Build Coastguard Worker 6*6777b538SAndroid Build Coastguard Worker""" 7*6777b538SAndroid Build Coastguard Workerlastchange.py -- Chromium revision fetching utility. 8*6777b538SAndroid Build Coastguard Worker""" 9*6777b538SAndroid Build Coastguard Worker 10*6777b538SAndroid Build Coastguard Workerimport argparse 11*6777b538SAndroid Build Coastguard Workerimport collections 12*6777b538SAndroid Build Coastguard Workerimport datetime 13*6777b538SAndroid Build Coastguard Workerimport logging 14*6777b538SAndroid Build Coastguard Workerimport os 15*6777b538SAndroid Build Coastguard Workerimport subprocess 16*6777b538SAndroid Build Coastguard Workerimport sys 17*6777b538SAndroid Build Coastguard Worker 18*6777b538SAndroid Build Coastguard WorkerVersionInfo = collections.namedtuple("VersionInfo", 19*6777b538SAndroid Build Coastguard Worker ("revision_id", "revision", "timestamp")) 20*6777b538SAndroid Build Coastguard Worker 21*6777b538SAndroid Build Coastguard Workerclass GitError(Exception): 22*6777b538SAndroid Build Coastguard Worker pass 23*6777b538SAndroid Build Coastguard Worker 24*6777b538SAndroid Build Coastguard Worker# This function exists for compatibility with logic outside this 25*6777b538SAndroid Build Coastguard Worker# repository that uses this file as a library. 26*6777b538SAndroid Build Coastguard Worker# TODO(eliribble) remove this function after it has been ported into 27*6777b538SAndroid Build Coastguard Worker# the repositories that depend on it 28*6777b538SAndroid Build Coastguard Workerdef RunGitCommand(directory, command): 29*6777b538SAndroid Build Coastguard Worker """ 30*6777b538SAndroid Build Coastguard Worker Launches git subcommand. 31*6777b538SAndroid Build Coastguard Worker 32*6777b538SAndroid Build Coastguard Worker Errors are swallowed. 33*6777b538SAndroid Build Coastguard Worker 34*6777b538SAndroid Build Coastguard Worker Returns: 35*6777b538SAndroid Build Coastguard Worker A process object or None. 36*6777b538SAndroid Build Coastguard Worker """ 37*6777b538SAndroid Build Coastguard Worker command = ['git'] + command 38*6777b538SAndroid Build Coastguard Worker # Force shell usage under cygwin. This is a workaround for 39*6777b538SAndroid Build Coastguard Worker # mysterious loss of cwd while invoking cygwin's git. 40*6777b538SAndroid Build Coastguard Worker # We can't just pass shell=True to Popen, as under win32 this will 41*6777b538SAndroid Build Coastguard Worker # cause CMD to be used, while we explicitly want a cygwin shell. 42*6777b538SAndroid Build Coastguard Worker if sys.platform == 'cygwin': 43*6777b538SAndroid Build Coastguard Worker command = ['sh', '-c', ' '.join(command)] 44*6777b538SAndroid Build Coastguard Worker try: 45*6777b538SAndroid Build Coastguard Worker proc = subprocess.Popen(command, 46*6777b538SAndroid Build Coastguard Worker stdout=subprocess.PIPE, 47*6777b538SAndroid Build Coastguard Worker stderr=subprocess.PIPE, 48*6777b538SAndroid Build Coastguard Worker cwd=directory, 49*6777b538SAndroid Build Coastguard Worker shell=(sys.platform=='win32')) 50*6777b538SAndroid Build Coastguard Worker return proc 51*6777b538SAndroid Build Coastguard Worker except OSError as e: 52*6777b538SAndroid Build Coastguard Worker logging.error('Command %r failed: %s' % (' '.join(command), e)) 53*6777b538SAndroid Build Coastguard Worker return None 54*6777b538SAndroid Build Coastguard Worker 55*6777b538SAndroid Build Coastguard Worker 56*6777b538SAndroid Build Coastguard Workerdef _RunGitCommand(directory, command): 57*6777b538SAndroid Build Coastguard Worker """Launches git subcommand. 58*6777b538SAndroid Build Coastguard Worker 59*6777b538SAndroid Build Coastguard Worker Returns: 60*6777b538SAndroid Build Coastguard Worker The stripped stdout of the git command. 61*6777b538SAndroid Build Coastguard Worker Raises: 62*6777b538SAndroid Build Coastguard Worker GitError on failure, including a nonzero return code. 63*6777b538SAndroid Build Coastguard Worker """ 64*6777b538SAndroid Build Coastguard Worker command = ['git'] + command 65*6777b538SAndroid Build Coastguard Worker # Force shell usage under cygwin. This is a workaround for 66*6777b538SAndroid Build Coastguard Worker # mysterious loss of cwd while invoking cygwin's git. 67*6777b538SAndroid Build Coastguard Worker # We can't just pass shell=True to Popen, as under win32 this will 68*6777b538SAndroid Build Coastguard Worker # cause CMD to be used, while we explicitly want a cygwin shell. 69*6777b538SAndroid Build Coastguard Worker if sys.platform == 'cygwin': 70*6777b538SAndroid Build Coastguard Worker command = ['sh', '-c', ' '.join(command)] 71*6777b538SAndroid Build Coastguard Worker try: 72*6777b538SAndroid Build Coastguard Worker logging.info("Executing '%s' in %s", ' '.join(command), directory) 73*6777b538SAndroid Build Coastguard Worker proc = subprocess.Popen(command, 74*6777b538SAndroid Build Coastguard Worker stdout=subprocess.PIPE, 75*6777b538SAndroid Build Coastguard Worker stderr=subprocess.PIPE, 76*6777b538SAndroid Build Coastguard Worker cwd=directory, 77*6777b538SAndroid Build Coastguard Worker shell=(sys.platform=='win32')) 78*6777b538SAndroid Build Coastguard Worker stdout, stderr = tuple(x.decode(encoding='utf_8') 79*6777b538SAndroid Build Coastguard Worker for x in proc.communicate()) 80*6777b538SAndroid Build Coastguard Worker stdout = stdout.strip() 81*6777b538SAndroid Build Coastguard Worker stderr = stderr.strip() 82*6777b538SAndroid Build Coastguard Worker logging.debug("returncode: %d", proc.returncode) 83*6777b538SAndroid Build Coastguard Worker logging.debug("stdout: %s", stdout) 84*6777b538SAndroid Build Coastguard Worker logging.debug("stderr: %s", stderr) 85*6777b538SAndroid Build Coastguard Worker if proc.returncode != 0 or not stdout: 86*6777b538SAndroid Build Coastguard Worker raise GitError(( 87*6777b538SAndroid Build Coastguard Worker "Git command '{}' in {} failed: " 88*6777b538SAndroid Build Coastguard Worker "rc={}, stdout='{}' stderr='{}'").format( 89*6777b538SAndroid Build Coastguard Worker " ".join(command), directory, proc.returncode, stdout, stderr)) 90*6777b538SAndroid Build Coastguard Worker return stdout 91*6777b538SAndroid Build Coastguard Worker except OSError as e: 92*6777b538SAndroid Build Coastguard Worker raise GitError("Git command 'git {}' in {} failed: {}".format( 93*6777b538SAndroid Build Coastguard Worker " ".join(command), directory, e)) 94*6777b538SAndroid Build Coastguard Worker 95*6777b538SAndroid Build Coastguard Worker 96*6777b538SAndroid Build Coastguard Workerdef GetMergeBase(directory, ref): 97*6777b538SAndroid Build Coastguard Worker """ 98*6777b538SAndroid Build Coastguard Worker Return the merge-base of HEAD and ref. 99*6777b538SAndroid Build Coastguard Worker 100*6777b538SAndroid Build Coastguard Worker Args: 101*6777b538SAndroid Build Coastguard Worker directory: The directory containing the .git directory. 102*6777b538SAndroid Build Coastguard Worker ref: The ref to use to find the merge base. 103*6777b538SAndroid Build Coastguard Worker Returns: 104*6777b538SAndroid Build Coastguard Worker The git commit SHA of the merge-base as a string. 105*6777b538SAndroid Build Coastguard Worker """ 106*6777b538SAndroid Build Coastguard Worker logging.debug("Calculating merge base between HEAD and %s in %s", 107*6777b538SAndroid Build Coastguard Worker ref, directory) 108*6777b538SAndroid Build Coastguard Worker command = ['merge-base', 'HEAD', ref] 109*6777b538SAndroid Build Coastguard Worker return _RunGitCommand(directory, command) 110*6777b538SAndroid Build Coastguard Worker 111*6777b538SAndroid Build Coastguard Worker 112*6777b538SAndroid Build Coastguard Workerdef FetchGitRevision(directory, commit_filter, start_commit="HEAD"): 113*6777b538SAndroid Build Coastguard Worker """ 114*6777b538SAndroid Build Coastguard Worker Fetch the Git hash (and Cr-Commit-Position if any) for a given directory. 115*6777b538SAndroid Build Coastguard Worker 116*6777b538SAndroid Build Coastguard Worker Args: 117*6777b538SAndroid Build Coastguard Worker directory: The directory containing the .git directory. 118*6777b538SAndroid Build Coastguard Worker commit_filter: A filter to supply to grep to filter commits 119*6777b538SAndroid Build Coastguard Worker start_commit: A commit identifier. The result of this function 120*6777b538SAndroid Build Coastguard Worker will be limited to only consider commits before the provided 121*6777b538SAndroid Build Coastguard Worker commit. 122*6777b538SAndroid Build Coastguard Worker Returns: 123*6777b538SAndroid Build Coastguard Worker A VersionInfo object. On error all values will be 0. 124*6777b538SAndroid Build Coastguard Worker """ 125*6777b538SAndroid Build Coastguard Worker hash_ = '' 126*6777b538SAndroid Build Coastguard Worker 127*6777b538SAndroid Build Coastguard Worker git_args = ['log', '-1', '--format=%H %ct'] 128*6777b538SAndroid Build Coastguard Worker if commit_filter is not None: 129*6777b538SAndroid Build Coastguard Worker git_args.append('--grep=' + commit_filter) 130*6777b538SAndroid Build Coastguard Worker 131*6777b538SAndroid Build Coastguard Worker git_args.append(start_commit) 132*6777b538SAndroid Build Coastguard Worker 133*6777b538SAndroid Build Coastguard Worker output = _RunGitCommand(directory, git_args) 134*6777b538SAndroid Build Coastguard Worker hash_, commit_timestamp = output.split() 135*6777b538SAndroid Build Coastguard Worker if not hash_: 136*6777b538SAndroid Build Coastguard Worker return VersionInfo('0', '0', 0) 137*6777b538SAndroid Build Coastguard Worker 138*6777b538SAndroid Build Coastguard Worker revision = hash_ 139*6777b538SAndroid Build Coastguard Worker output = _RunGitCommand(directory, ['cat-file', 'commit', hash_]) 140*6777b538SAndroid Build Coastguard Worker for line in reversed(output.splitlines()): 141*6777b538SAndroid Build Coastguard Worker if line.startswith('Cr-Commit-Position:'): 142*6777b538SAndroid Build Coastguard Worker pos = line.rsplit()[-1].strip() 143*6777b538SAndroid Build Coastguard Worker logging.debug("Found Cr-Commit-Position '%s'", pos) 144*6777b538SAndroid Build Coastguard Worker revision = "{}-{}".format(hash_, pos) 145*6777b538SAndroid Build Coastguard Worker break 146*6777b538SAndroid Build Coastguard Worker return VersionInfo(hash_, revision, int(commit_timestamp)) 147*6777b538SAndroid Build Coastguard Worker 148*6777b538SAndroid Build Coastguard Worker 149*6777b538SAndroid Build Coastguard Workerdef GetHeaderGuard(path): 150*6777b538SAndroid Build Coastguard Worker """ 151*6777b538SAndroid Build Coastguard Worker Returns the header #define guard for the given file path. 152*6777b538SAndroid Build Coastguard Worker This treats everything after the last instance of "src/" as being a 153*6777b538SAndroid Build Coastguard Worker relevant part of the guard. If there is no "src/", then the entire path 154*6777b538SAndroid Build Coastguard Worker is used. 155*6777b538SAndroid Build Coastguard Worker """ 156*6777b538SAndroid Build Coastguard Worker src_index = path.rfind('src/') 157*6777b538SAndroid Build Coastguard Worker if src_index != -1: 158*6777b538SAndroid Build Coastguard Worker guard = path[src_index + 4:] 159*6777b538SAndroid Build Coastguard Worker else: 160*6777b538SAndroid Build Coastguard Worker guard = path 161*6777b538SAndroid Build Coastguard Worker guard = guard.upper() 162*6777b538SAndroid Build Coastguard Worker return guard.replace('/', '_').replace('.', '_').replace('\\', '_') + '_' 163*6777b538SAndroid Build Coastguard Worker 164*6777b538SAndroid Build Coastguard Worker 165*6777b538SAndroid Build Coastguard Workerdef GetHeaderContents(path, define, version): 166*6777b538SAndroid Build Coastguard Worker """ 167*6777b538SAndroid Build Coastguard Worker Returns what the contents of the header file should be that indicate the given 168*6777b538SAndroid Build Coastguard Worker revision. 169*6777b538SAndroid Build Coastguard Worker """ 170*6777b538SAndroid Build Coastguard Worker header_guard = GetHeaderGuard(path) 171*6777b538SAndroid Build Coastguard Worker 172*6777b538SAndroid Build Coastguard Worker header_contents = """/* Generated by lastchange.py, do not edit.*/ 173*6777b538SAndroid Build Coastguard Worker 174*6777b538SAndroid Build Coastguard Worker#ifndef %(header_guard)s 175*6777b538SAndroid Build Coastguard Worker#define %(header_guard)s 176*6777b538SAndroid Build Coastguard Worker 177*6777b538SAndroid Build Coastguard Worker#define %(define)s "%(version)s" 178*6777b538SAndroid Build Coastguard Worker 179*6777b538SAndroid Build Coastguard Worker#endif // %(header_guard)s 180*6777b538SAndroid Build Coastguard Worker""" 181*6777b538SAndroid Build Coastguard Worker header_contents = header_contents % { 'header_guard': header_guard, 182*6777b538SAndroid Build Coastguard Worker 'define': define, 183*6777b538SAndroid Build Coastguard Worker 'version': version } 184*6777b538SAndroid Build Coastguard Worker return header_contents 185*6777b538SAndroid Build Coastguard Worker 186*6777b538SAndroid Build Coastguard Worker 187*6777b538SAndroid Build Coastguard Workerdef GetGitTopDirectory(source_dir): 188*6777b538SAndroid Build Coastguard Worker """Get the top git directory - the directory that contains the .git directory. 189*6777b538SAndroid Build Coastguard Worker 190*6777b538SAndroid Build Coastguard Worker Args: 191*6777b538SAndroid Build Coastguard Worker source_dir: The directory to search. 192*6777b538SAndroid Build Coastguard Worker Returns: 193*6777b538SAndroid Build Coastguard Worker The output of "git rev-parse --show-toplevel" as a string 194*6777b538SAndroid Build Coastguard Worker """ 195*6777b538SAndroid Build Coastguard Worker return _RunGitCommand(source_dir, ['rev-parse', '--show-toplevel']) 196*6777b538SAndroid Build Coastguard Worker 197*6777b538SAndroid Build Coastguard Worker 198*6777b538SAndroid Build Coastguard Workerdef WriteIfChanged(file_name, contents): 199*6777b538SAndroid Build Coastguard Worker """ 200*6777b538SAndroid Build Coastguard Worker Writes the specified contents to the specified file_name 201*6777b538SAndroid Build Coastguard Worker iff the contents are different than the current contents. 202*6777b538SAndroid Build Coastguard Worker Returns if new data was written. 203*6777b538SAndroid Build Coastguard Worker """ 204*6777b538SAndroid Build Coastguard Worker try: 205*6777b538SAndroid Build Coastguard Worker old_contents = open(file_name, 'r').read() 206*6777b538SAndroid Build Coastguard Worker except EnvironmentError: 207*6777b538SAndroid Build Coastguard Worker pass 208*6777b538SAndroid Build Coastguard Worker else: 209*6777b538SAndroid Build Coastguard Worker if contents == old_contents: 210*6777b538SAndroid Build Coastguard Worker return False 211*6777b538SAndroid Build Coastguard Worker os.unlink(file_name) 212*6777b538SAndroid Build Coastguard Worker open(file_name, 'w').write(contents) 213*6777b538SAndroid Build Coastguard Worker return True 214*6777b538SAndroid Build Coastguard Worker 215*6777b538SAndroid Build Coastguard Worker 216*6777b538SAndroid Build Coastguard Workerdef main(argv=None): 217*6777b538SAndroid Build Coastguard Worker if argv is None: 218*6777b538SAndroid Build Coastguard Worker argv = sys.argv 219*6777b538SAndroid Build Coastguard Worker 220*6777b538SAndroid Build Coastguard Worker parser = argparse.ArgumentParser(usage="lastchange.py [options]") 221*6777b538SAndroid Build Coastguard Worker parser.add_argument("-m", "--version-macro", 222*6777b538SAndroid Build Coastguard Worker help=("Name of C #define when using --header. Defaults to " 223*6777b538SAndroid Build Coastguard Worker "LAST_CHANGE.")) 224*6777b538SAndroid Build Coastguard Worker parser.add_argument("-o", 225*6777b538SAndroid Build Coastguard Worker "--output", 226*6777b538SAndroid Build Coastguard Worker metavar="FILE", 227*6777b538SAndroid Build Coastguard Worker help=("Write last change to FILE. " 228*6777b538SAndroid Build Coastguard Worker "Can be combined with other file-output-related " 229*6777b538SAndroid Build Coastguard Worker "options to write multiple files.")) 230*6777b538SAndroid Build Coastguard Worker parser.add_argument("--header", 231*6777b538SAndroid Build Coastguard Worker metavar="FILE", 232*6777b538SAndroid Build Coastguard Worker help=("Write last change to FILE as a C/C++ header. " 233*6777b538SAndroid Build Coastguard Worker "Can be combined with other file-output-related " 234*6777b538SAndroid Build Coastguard Worker "options to write multiple files.")) 235*6777b538SAndroid Build Coastguard Worker parser.add_argument("--revision", 236*6777b538SAndroid Build Coastguard Worker metavar="FILE", 237*6777b538SAndroid Build Coastguard Worker help=("Write last change to FILE as a one-line revision. " 238*6777b538SAndroid Build Coastguard Worker "Can be combined with other file-output-related " 239*6777b538SAndroid Build Coastguard Worker "options to write multiple files.")) 240*6777b538SAndroid Build Coastguard Worker parser.add_argument("--merge-base-ref", 241*6777b538SAndroid Build Coastguard Worker default=None, 242*6777b538SAndroid Build Coastguard Worker help=("Only consider changes since the merge " 243*6777b538SAndroid Build Coastguard Worker "base between HEAD and the provided ref")) 244*6777b538SAndroid Build Coastguard Worker parser.add_argument("--revision-id-only", action='store_true', 245*6777b538SAndroid Build Coastguard Worker help=("Output the revision as a VCS revision ID only (in " 246*6777b538SAndroid Build Coastguard Worker "Git, a 40-character commit hash, excluding the " 247*6777b538SAndroid Build Coastguard Worker "Cr-Commit-Position).")) 248*6777b538SAndroid Build Coastguard Worker parser.add_argument("--revision-id-prefix", 249*6777b538SAndroid Build Coastguard Worker metavar="PREFIX", 250*6777b538SAndroid Build Coastguard Worker help=("Adds a string prefix to the VCS revision ID.")) 251*6777b538SAndroid Build Coastguard Worker parser.add_argument("--print-only", action="store_true", 252*6777b538SAndroid Build Coastguard Worker help=("Just print the revision string. Overrides any " 253*6777b538SAndroid Build Coastguard Worker "file-output-related options.")) 254*6777b538SAndroid Build Coastguard Worker parser.add_argument("-s", "--source-dir", metavar="DIR", 255*6777b538SAndroid Build Coastguard Worker help="Use repository in the given directory.") 256*6777b538SAndroid Build Coastguard Worker parser.add_argument("--filter", metavar="REGEX", 257*6777b538SAndroid Build Coastguard Worker help=("Only use log entries where the commit message " 258*6777b538SAndroid Build Coastguard Worker "matches the supplied filter regex. Defaults to " 259*6777b538SAndroid Build Coastguard Worker "'^Change-Id:' to suppress local commits."), 260*6777b538SAndroid Build Coastguard Worker default='^Change-Id:') 261*6777b538SAndroid Build Coastguard Worker 262*6777b538SAndroid Build Coastguard Worker args, extras = parser.parse_known_args(argv[1:]) 263*6777b538SAndroid Build Coastguard Worker 264*6777b538SAndroid Build Coastguard Worker logging.basicConfig(level=logging.WARNING) 265*6777b538SAndroid Build Coastguard Worker 266*6777b538SAndroid Build Coastguard Worker out_file = args.output 267*6777b538SAndroid Build Coastguard Worker header = args.header 268*6777b538SAndroid Build Coastguard Worker revision = args.revision 269*6777b538SAndroid Build Coastguard Worker commit_filter=args.filter 270*6777b538SAndroid Build Coastguard Worker 271*6777b538SAndroid Build Coastguard Worker while len(extras) and out_file is None: 272*6777b538SAndroid Build Coastguard Worker if out_file is None: 273*6777b538SAndroid Build Coastguard Worker out_file = extras.pop(0) 274*6777b538SAndroid Build Coastguard Worker if extras: 275*6777b538SAndroid Build Coastguard Worker sys.stderr.write('Unexpected arguments: %r\n\n' % extras) 276*6777b538SAndroid Build Coastguard Worker parser.print_help() 277*6777b538SAndroid Build Coastguard Worker sys.exit(2) 278*6777b538SAndroid Build Coastguard Worker 279*6777b538SAndroid Build Coastguard Worker source_dir = args.source_dir or os.path.dirname(os.path.abspath(__file__)) 280*6777b538SAndroid Build Coastguard Worker 281*6777b538SAndroid Build Coastguard Worker git_top_dir = None 282*6777b538SAndroid Build Coastguard Worker try: 283*6777b538SAndroid Build Coastguard Worker git_top_dir = GetGitTopDirectory(source_dir) 284*6777b538SAndroid Build Coastguard Worker except GitError as e: 285*6777b538SAndroid Build Coastguard Worker logging.warning("Failed to get git top directory from '%s': %s", source_dir, 286*6777b538SAndroid Build Coastguard Worker e) 287*6777b538SAndroid Build Coastguard Worker 288*6777b538SAndroid Build Coastguard Worker merge_base_sha = 'HEAD' 289*6777b538SAndroid Build Coastguard Worker if git_top_dir and args.merge_base_ref: 290*6777b538SAndroid Build Coastguard Worker try: 291*6777b538SAndroid Build Coastguard Worker merge_base_sha = GetMergeBase(git_top_dir, args.merge_base_ref) 292*6777b538SAndroid Build Coastguard Worker except GitError as e: 293*6777b538SAndroid Build Coastguard Worker logging.error("You requested a --merge-base-ref value of '%s' but no " 294*6777b538SAndroid Build Coastguard Worker "merge base could be found between it and HEAD. Git " 295*6777b538SAndroid Build Coastguard Worker "reports: %s", args.merge_base_ref, e) 296*6777b538SAndroid Build Coastguard Worker return 3 297*6777b538SAndroid Build Coastguard Worker 298*6777b538SAndroid Build Coastguard Worker version_info = None 299*6777b538SAndroid Build Coastguard Worker if git_top_dir: 300*6777b538SAndroid Build Coastguard Worker try: 301*6777b538SAndroid Build Coastguard Worker version_info = FetchGitRevision(git_top_dir, commit_filter, 302*6777b538SAndroid Build Coastguard Worker merge_base_sha) 303*6777b538SAndroid Build Coastguard Worker except GitError as e: 304*6777b538SAndroid Build Coastguard Worker logging.error("Failed to get version info: %s", e) 305*6777b538SAndroid Build Coastguard Worker 306*6777b538SAndroid Build Coastguard Worker if not version_info: 307*6777b538SAndroid Build Coastguard Worker logging.warning( 308*6777b538SAndroid Build Coastguard Worker "Falling back to a version of 0.0.0 to allow script to " 309*6777b538SAndroid Build Coastguard Worker "finish. This is normal if you are bootstrapping a new environment " 310*6777b538SAndroid Build Coastguard Worker "or do not have a git repository for any other reason. If not, this " 311*6777b538SAndroid Build Coastguard Worker "could represent a serious error.") 312*6777b538SAndroid Build Coastguard Worker # Use a dummy revision that has the same length as a Git commit hash, 313*6777b538SAndroid Build Coastguard Worker # same as what we use in build/util/LASTCHANGE.dummy. 314*6777b538SAndroid Build Coastguard Worker version_info = VersionInfo('0' * 40, '0' * 40, 0) 315*6777b538SAndroid Build Coastguard Worker 316*6777b538SAndroid Build Coastguard Worker revision_string = version_info.revision 317*6777b538SAndroid Build Coastguard Worker if args.revision_id_only: 318*6777b538SAndroid Build Coastguard Worker revision_string = version_info.revision_id 319*6777b538SAndroid Build Coastguard Worker 320*6777b538SAndroid Build Coastguard Worker if args.revision_id_prefix: 321*6777b538SAndroid Build Coastguard Worker revision_string = args.revision_id_prefix + revision_string 322*6777b538SAndroid Build Coastguard Worker 323*6777b538SAndroid Build Coastguard Worker if args.print_only: 324*6777b538SAndroid Build Coastguard Worker print(revision_string) 325*6777b538SAndroid Build Coastguard Worker else: 326*6777b538SAndroid Build Coastguard Worker lastchange_year = datetime.datetime.fromtimestamp( 327*6777b538SAndroid Build Coastguard Worker version_info.timestamp, datetime.timezone.utc).year 328*6777b538SAndroid Build Coastguard Worker contents_lines = [ 329*6777b538SAndroid Build Coastguard Worker "LASTCHANGE=%s" % revision_string, 330*6777b538SAndroid Build Coastguard Worker "LASTCHANGE_YEAR=%s" % lastchange_year, 331*6777b538SAndroid Build Coastguard Worker ] 332*6777b538SAndroid Build Coastguard Worker contents = '\n'.join(contents_lines) + '\n' 333*6777b538SAndroid Build Coastguard Worker if not out_file and not header and not revision: 334*6777b538SAndroid Build Coastguard Worker sys.stdout.write(contents) 335*6777b538SAndroid Build Coastguard Worker else: 336*6777b538SAndroid Build Coastguard Worker if out_file: 337*6777b538SAndroid Build Coastguard Worker committime_file = out_file + '.committime' 338*6777b538SAndroid Build Coastguard Worker out_changed = WriteIfChanged(out_file, contents) 339*6777b538SAndroid Build Coastguard Worker if out_changed or not os.path.exists(committime_file): 340*6777b538SAndroid Build Coastguard Worker with open(committime_file, 'w') as timefile: 341*6777b538SAndroid Build Coastguard Worker timefile.write(str(version_info.timestamp)) 342*6777b538SAndroid Build Coastguard Worker if header: 343*6777b538SAndroid Build Coastguard Worker WriteIfChanged(header, 344*6777b538SAndroid Build Coastguard Worker GetHeaderContents(header, args.version_macro, 345*6777b538SAndroid Build Coastguard Worker revision_string)) 346*6777b538SAndroid Build Coastguard Worker if revision: 347*6777b538SAndroid Build Coastguard Worker WriteIfChanged(revision, revision_string) 348*6777b538SAndroid Build Coastguard Worker 349*6777b538SAndroid Build Coastguard Worker return 0 350*6777b538SAndroid Build Coastguard Worker 351*6777b538SAndroid Build Coastguard Worker 352*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__': 353*6777b538SAndroid Build Coastguard Worker sys.exit(main()) 354