Home | History | Annotate | Download | only in build
      1 #!/usr/bin/env python
      2 # Copyright (c) 2009 The Chromium Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 """
      7 version.py -- Chromium version string substitution utility.
      8 """
      9 
     10 import getopt
     11 import os
     12 import sys
     13 
     14 
     15 class Usage(Exception):
     16   def __init__(self, msg):
     17     self.msg = msg
     18 
     19 
     20 def fetch_values_from_file(values_dict, file_name):
     21   """
     22   Fetches KEYWORD=VALUE settings from the specified file.
     23 
     24   Everything to the left of the first '=' is the keyword,
     25   everything to the right is the value.  No stripping of
     26   white space, so beware.
     27 
     28   The file must exist, otherwise you get the Python exception from open().
     29   """
     30   for line in open(file_name, 'r').readlines():
     31     key, val = line.rstrip('\r\n').split('=', 1)
     32     values_dict[key] = val
     33 
     34 
     35 def fetch_values(file_list):
     36   """
     37   Returns a dictionary of values to be used for substitution, populating
     38   the dictionary with KEYWORD=VALUE settings from the files in 'file_list'.
     39 
     40   Explicitly adds the following value from internal calculations:
     41 
     42     OFFICIAL_BUILD
     43   """
     44   CHROME_BUILD_TYPE = os.environ.get('CHROME_BUILD_TYPE')
     45   if CHROME_BUILD_TYPE == '_official':
     46     official_build = '1'
     47   else:
     48     official_build = '0'
     49 
     50   values = dict(
     51     OFFICIAL_BUILD = official_build,
     52   )
     53 
     54   for file_name in file_list:
     55     fetch_values_from_file(values, file_name)
     56 
     57   return values
     58 
     59 
     60 def subst_template(contents, values):
     61   """
     62   Returns the template with substituted values from the specified dictionary.
     63 
     64   Keywords to be substituted are surrounded by '@':  @KEYWORD@.
     65 
     66   No attempt is made to avoid recursive substitution.  The order
     67   of evaluation is random based on the order of the keywords returned
     68   by the Python dictionary.  So do NOT substitute a value that
     69   contains any @KEYWORD@ strings expecting them to be recursively
     70   substituted, okay?
     71   """
     72   for key, val in values.iteritems():
     73     try:
     74       contents = contents.replace('@' + key + '@', val)
     75     except TypeError:
     76       print repr(key), repr(val)
     77   return contents
     78 
     79 
     80 def subst_file(file_name, values):
     81   """
     82   Returns the contents of the specified file_name with substited
     83   values from the specified dictionary.
     84 
     85   This is like subst_template, except it operates on a file.
     86   """
     87   template = open(file_name, 'r').read()
     88   return subst_template(template, values);
     89 
     90 
     91 def write_if_changed(file_name, contents):
     92   """
     93   Writes the specified contents to the specified file_name
     94   iff the contents are different than the current contents.
     95   """
     96   try:
     97     old_contents = open(file_name, 'r').read()
     98   except EnvironmentError:
     99     pass
    100   else:
    101     if contents == old_contents:
    102       return
    103     os.unlink(file_name)
    104   open(file_name, 'w').write(contents)
    105 
    106 
    107 def main(argv=None):
    108   if argv is None:
    109     argv = sys.argv
    110 
    111   short_options = 'e:f:i:o:t:h'
    112   long_options = ['eval=', 'file=', 'help']
    113 
    114   helpstr = """\
    115 Usage:  version.py [-h] [-f FILE] ([[-i] FILE] | -t TEMPLATE) [[-o] FILE]
    116 
    117   -f FILE, --file=FILE              Read variables from FILE.
    118   -i FILE, --input=FILE             Read strings to substitute from FILE.
    119   -o FILE, --output=FILE            Write substituted strings to FILE.
    120   -t TEMPLATE, --template=TEMPLATE  Use TEMPLATE as the strings to substitute.
    121   -e VAR=VAL, --eval=VAR=VAL        Evaluate VAL after reading variables. Can
    122                                     be used to synthesize variables. e.g.
    123                                     -e 'PATCH_HI=int(PATCH)/256'.
    124   -h, --help                        Print this help and exit.
    125 """
    126 
    127   evals = {}
    128   variable_files = []
    129   in_file = None
    130   out_file = None
    131   template = None
    132 
    133   try:
    134     try:
    135       opts, args = getopt.getopt(argv[1:], short_options, long_options)
    136     except getopt.error, msg:
    137       raise Usage(msg)
    138     for o, a in opts:
    139       if o in ('-e', '--eval'):
    140         try:
    141           evals.update(dict([a.split('=',1)]))
    142         except ValueError:
    143           raise Usage("-e requires VAR=VAL")
    144       elif o in ('-f', '--file'):
    145         variable_files.append(a)
    146       elif o in ('-i', '--input'):
    147         in_file = a
    148       elif o in ('-o', '--output'):
    149         out_file = a
    150       elif o in ('-t', '--template'):
    151         template = a
    152       elif o in ('-h', '--help'):
    153         print helpstr
    154         return 0
    155     while len(args) and (in_file is None or out_file is None or
    156                          template is None):
    157       if in_file is None:
    158         in_file = args.pop(0)
    159       elif out_file is None:
    160         out_file = args.pop(0)
    161     if args:
    162       msg = 'Unexpected arguments: %r' % args
    163       raise Usage(msg)
    164   except Usage, err:
    165     sys.stderr.write(err.msg)
    166     sys.stderr.write('; Use -h to get help.\n')
    167     return 2
    168 
    169   values = fetch_values(variable_files)
    170   for key, val in evals.iteritems():
    171     values[key] = str(eval(val, globals(), values))
    172 
    173   if template is not None:
    174     contents = subst_template(template, values)
    175   elif in_file:
    176     contents = subst_file(in_file, values)
    177   else:
    178     # Generate a default set of version information.
    179     contents = """MAJOR=%(MAJOR)s
    180 MINOR=%(MINOR)s
    181 BUILD=%(BUILD)s
    182 PATCH=%(PATCH)s
    183 LASTCHANGE=%(LASTCHANGE)s
    184 OFFICIAL_BUILD=%(OFFICIAL_BUILD)s
    185 """ % values
    186 
    187 
    188   if out_file:
    189     write_if_changed(out_file, contents)
    190   else:
    191     print contents
    192 
    193   return 0
    194 
    195 
    196 if __name__ == '__main__':
    197   sys.exit(main())
    198