15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python 2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)# Copyright 2014 The Chromium Authors. All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)version.py -- Chromium version string substitution utility. 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)import argparse 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def fetch_values_from_file(values_dict, file_name): 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Fetches KEYWORD=VALUE settings from the specified file. 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Everything to the left of the first '=' is the keyword, 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) everything to the right is the value. No stripping of 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) white space, so beware. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The file must exist, otherwise you get the Python exception from open(). 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for line in open(file_name, 'r').readlines(): 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key, val = line.rstrip('\r\n').split('=', 1) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) values_dict[key] = val 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def fetch_values(file_list): 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns a dictionary of values to be used for substitution, populating 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) the dictionary with KEYWORD=VALUE settings from the files in 'file_list'. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Explicitly adds the following value from internal calculations: 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OFFICIAL_BUILD 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHROME_BUILD_TYPE = os.environ.get('CHROME_BUILD_TYPE') 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if CHROME_BUILD_TYPE == '_official': 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) official_build = '1' 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) official_build = '0' 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) values = dict( 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OFFICIAL_BUILD = official_build, 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for file_name in file_list: 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetch_values_from_file(values, file_name) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return values 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def subst_template(contents, values): 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns the template with substituted values from the specified dictionary. 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Keywords to be substituted are surrounded by '@': @KEYWORD@. 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) No attempt is made to avoid recursive substitution. The order 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) of evaluation is random based on the order of the keywords returned 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) by the Python dictionary. So do NOT substitute a value that 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contains any @KEYWORD@ strings expecting them to be recursively 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) substituted, okay? 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for key, val in values.iteritems(): 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contents = contents.replace('@' + key + '@', val) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except TypeError: 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print repr(key), repr(val) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return contents 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def subst_file(file_name, values): 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Returns the contents of the specified file_name with substituted 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) values from the specified dictionary. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This is like subst_template, except it operates on a file. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) template = open(file_name, 'r').read() 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return subst_template(template, values); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def write_if_changed(file_name, contents): 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Writes the specified contents to the specified file_name 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iff the contents are different than the current contents. 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_contents = open(file_name, 'r').read() 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except EnvironmentError: 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if contents == old_contents: 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.unlink(file_name) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) open(file_name, 'w').write(contents) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)def main(): 103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) parser = argparse.ArgumentParser() 104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) parser.add_argument('-f', '--file', action='append', default=[], 105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) help='Read variables from FILE.') 106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) parser.add_argument('-i', '--input', default=None, 107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) help='Read strings to substitute from FILE.') 108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) parser.add_argument('-o', '--output', default=None, 109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) help='Write substituted strings to FILE.') 110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) parser.add_argument('-t', '--template', default=None, 111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) help='Use TEMPLATE as the strings to substitute.') 112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) parser.add_argument('-e', '--eval', action='append', default=[], 113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) help='Evaluate VAL after reading variables. Can be used ' 114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 'to synthesize variables. e.g. -e \'PATCH_HI=int(' 115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 'PATCH)/256.') 116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) parser.add_argument('args', nargs=argparse.REMAINDER, 117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) help='For compatibility: INPUT and OUTPUT can be ' 118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 'passed as positional arguments.') 119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) options = parser.parse_args() 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) evals = {} 122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for expression in options.eval: 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) evals.update(dict([expression.split('=', 1)])) 125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) except ValueError: 126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) parser.error('-e requires VAR=VAL') 127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) # Compatibility with old versions that considered the first two positional 129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) # arguments shorthands for --input and --output. 130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) while len(options.args) and (options.input is None or \ 131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) options.output is None): 132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if options.input is None: 133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) options.input = options.args.pop(0) 134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) elif options.output is None: 135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) options.output = options.args.pop(0) 136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if options.args: 137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) parser.error('Unexpected arguments: %r' % options.args) 138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) values = fetch_values(options.file) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for key, val in evals.iteritems(): 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) values[key] = str(eval(val, globals(), values)) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if options.template is not None: 144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) contents = subst_template(options.template, values) 145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) elif options.input: 146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) contents = subst_file(options.input, values) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Generate a default set of version information. 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contents = """MAJOR=%(MAJOR)s 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MINOR=%(MINOR)s 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BUILD=%(BUILD)s 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PATCH=%(PATCH)s 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LASTCHANGE=%(LASTCHANGE)s 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OFFICIAL_BUILD=%(OFFICIAL_BUILD)s 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" % values 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 157f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if options.output is not None: 158f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) write_if_changed(options.output, contents) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print contents 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__': 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sys.exit(main()) 167