xref: /aosp_15_r20/external/cronet/build/util/version.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*6777b538SAndroid Build Coastguard Worker# Copyright 2014 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 Workerversion.py -- Chromium version string substitution utility.
8*6777b538SAndroid Build Coastguard Worker"""
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker
11*6777b538SAndroid Build Coastguard Workerimport argparse
12*6777b538SAndroid Build Coastguard Workerimport os
13*6777b538SAndroid Build Coastguard Workerimport stat
14*6777b538SAndroid Build Coastguard Workerimport sys
15*6777b538SAndroid Build Coastguard Worker
16*6777b538SAndroid Build Coastguard Workerimport android_chrome_version
17*6777b538SAndroid Build Coastguard Worker
18*6777b538SAndroid Build Coastguard Worker
19*6777b538SAndroid Build Coastguard Workerdef FetchValuesFromFile(values_dict, file_name):
20*6777b538SAndroid Build Coastguard Worker  """
21*6777b538SAndroid Build Coastguard Worker  Fetches KEYWORD=VALUE settings from the specified file.
22*6777b538SAndroid Build Coastguard Worker
23*6777b538SAndroid Build Coastguard Worker  Everything to the left of the first '=' is the keyword,
24*6777b538SAndroid Build Coastguard Worker  everything to the right is the value.  No stripping of
25*6777b538SAndroid Build Coastguard Worker  white space, so beware.
26*6777b538SAndroid Build Coastguard Worker
27*6777b538SAndroid Build Coastguard Worker  The file must exist, otherwise you get the Python exception from open().
28*6777b538SAndroid Build Coastguard Worker  """
29*6777b538SAndroid Build Coastguard Worker  with open(file_name, 'r') as f:
30*6777b538SAndroid Build Coastguard Worker    for line in f.readlines():
31*6777b538SAndroid Build Coastguard Worker      key, val = line.rstrip('\r\n').split('=', 1)
32*6777b538SAndroid Build Coastguard Worker      values_dict[key] = val
33*6777b538SAndroid Build Coastguard Worker
34*6777b538SAndroid Build Coastguard Worker
35*6777b538SAndroid Build Coastguard Workerdef FetchValues(file_list, is_official_build=None):
36*6777b538SAndroid Build Coastguard Worker  """
37*6777b538SAndroid Build Coastguard Worker  Returns a dictionary of values to be used for substitution.
38*6777b538SAndroid Build Coastguard Worker
39*6777b538SAndroid Build Coastguard Worker  Populates the dictionary with KEYWORD=VALUE settings from the files in
40*6777b538SAndroid Build Coastguard Worker  'file_list'.
41*6777b538SAndroid Build Coastguard Worker
42*6777b538SAndroid Build Coastguard Worker  Explicitly adds the following value from internal calculations:
43*6777b538SAndroid Build Coastguard Worker
44*6777b538SAndroid Build Coastguard Worker    OFFICIAL_BUILD
45*6777b538SAndroid Build Coastguard Worker  """
46*6777b538SAndroid Build Coastguard Worker  CHROME_BUILD_TYPE = os.environ.get('CHROME_BUILD_TYPE')
47*6777b538SAndroid Build Coastguard Worker  if CHROME_BUILD_TYPE == '_official' or is_official_build:
48*6777b538SAndroid Build Coastguard Worker    official_build = '1'
49*6777b538SAndroid Build Coastguard Worker  else:
50*6777b538SAndroid Build Coastguard Worker    official_build = '0'
51*6777b538SAndroid Build Coastguard Worker
52*6777b538SAndroid Build Coastguard Worker  values = dict(
53*6777b538SAndroid Build Coastguard Worker    OFFICIAL_BUILD = official_build,
54*6777b538SAndroid Build Coastguard Worker  )
55*6777b538SAndroid Build Coastguard Worker
56*6777b538SAndroid Build Coastguard Worker  for file_name in file_list:
57*6777b538SAndroid Build Coastguard Worker    FetchValuesFromFile(values, file_name)
58*6777b538SAndroid Build Coastguard Worker
59*6777b538SAndroid Build Coastguard Worker  script_dirname = os.path.dirname(os.path.realpath(__file__))
60*6777b538SAndroid Build Coastguard Worker  lastchange_filename = os.path.join(script_dirname, "LASTCHANGE")
61*6777b538SAndroid Build Coastguard Worker  lastchange_values = {}
62*6777b538SAndroid Build Coastguard Worker  FetchValuesFromFile(lastchange_values, lastchange_filename)
63*6777b538SAndroid Build Coastguard Worker
64*6777b538SAndroid Build Coastguard Worker  for placeholder_key, placeholder_value in values.items():
65*6777b538SAndroid Build Coastguard Worker    values[placeholder_key] = SubstTemplate(placeholder_value,
66*6777b538SAndroid Build Coastguard Worker                                            lastchange_values)
67*6777b538SAndroid Build Coastguard Worker
68*6777b538SAndroid Build Coastguard Worker  return values
69*6777b538SAndroid Build Coastguard Worker
70*6777b538SAndroid Build Coastguard Worker
71*6777b538SAndroid Build Coastguard Workerdef SubstTemplate(contents, values):
72*6777b538SAndroid Build Coastguard Worker  """
73*6777b538SAndroid Build Coastguard Worker  Returns the template with substituted values from the specified dictionary.
74*6777b538SAndroid Build Coastguard Worker
75*6777b538SAndroid Build Coastguard Worker  Keywords to be substituted are surrounded by '@':  @KEYWORD@.
76*6777b538SAndroid Build Coastguard Worker
77*6777b538SAndroid Build Coastguard Worker  No attempt is made to avoid recursive substitution.  The order
78*6777b538SAndroid Build Coastguard Worker  of evaluation is random based on the order of the keywords returned
79*6777b538SAndroid Build Coastguard Worker  by the Python dictionary.  So do NOT substitute a value that
80*6777b538SAndroid Build Coastguard Worker  contains any @KEYWORD@ strings expecting them to be recursively
81*6777b538SAndroid Build Coastguard Worker  substituted, okay?
82*6777b538SAndroid Build Coastguard Worker  """
83*6777b538SAndroid Build Coastguard Worker  for key, val in values.items():
84*6777b538SAndroid Build Coastguard Worker    try:
85*6777b538SAndroid Build Coastguard Worker      contents = contents.replace('@' + key + '@', val)
86*6777b538SAndroid Build Coastguard Worker    except TypeError:
87*6777b538SAndroid Build Coastguard Worker      print(repr(key), repr(val))
88*6777b538SAndroid Build Coastguard Worker  return contents
89*6777b538SAndroid Build Coastguard Worker
90*6777b538SAndroid Build Coastguard Worker
91*6777b538SAndroid Build Coastguard Workerdef SubstFile(file_name, values):
92*6777b538SAndroid Build Coastguard Worker  """
93*6777b538SAndroid Build Coastguard Worker  Returns the contents of the specified file_name with substituted values.
94*6777b538SAndroid Build Coastguard Worker
95*6777b538SAndroid Build Coastguard Worker  Substituted values come from the specified dictionary.
96*6777b538SAndroid Build Coastguard Worker
97*6777b538SAndroid Build Coastguard Worker  This is like SubstTemplate, except it operates on a file.
98*6777b538SAndroid Build Coastguard Worker  """
99*6777b538SAndroid Build Coastguard Worker  with open(file_name, 'r') as f:
100*6777b538SAndroid Build Coastguard Worker    template = f.read()
101*6777b538SAndroid Build Coastguard Worker  return SubstTemplate(template, values)
102*6777b538SAndroid Build Coastguard Worker
103*6777b538SAndroid Build Coastguard Worker
104*6777b538SAndroid Build Coastguard Workerdef WriteIfChanged(file_name, contents, mode):
105*6777b538SAndroid Build Coastguard Worker  """
106*6777b538SAndroid Build Coastguard Worker  Writes the specified contents to the specified file_name.
107*6777b538SAndroid Build Coastguard Worker
108*6777b538SAndroid Build Coastguard Worker  Does nothing if the contents aren't different than the current contents.
109*6777b538SAndroid Build Coastguard Worker  """
110*6777b538SAndroid Build Coastguard Worker  try:
111*6777b538SAndroid Build Coastguard Worker    with open(file_name, 'r') as f:
112*6777b538SAndroid Build Coastguard Worker      old_contents = f.read()
113*6777b538SAndroid Build Coastguard Worker  except EnvironmentError:
114*6777b538SAndroid Build Coastguard Worker    pass
115*6777b538SAndroid Build Coastguard Worker  else:
116*6777b538SAndroid Build Coastguard Worker    if contents == old_contents and mode == stat.S_IMODE(
117*6777b538SAndroid Build Coastguard Worker        os.lstat(file_name).st_mode):
118*6777b538SAndroid Build Coastguard Worker      return
119*6777b538SAndroid Build Coastguard Worker    os.unlink(file_name)
120*6777b538SAndroid Build Coastguard Worker  with open(file_name, 'w') as f:
121*6777b538SAndroid Build Coastguard Worker    f.write(contents)
122*6777b538SAndroid Build Coastguard Worker  os.chmod(file_name, mode)
123*6777b538SAndroid Build Coastguard Worker
124*6777b538SAndroid Build Coastguard Worker
125*6777b538SAndroid Build Coastguard Workerdef BuildParser():
126*6777b538SAndroid Build Coastguard Worker  """Build argparse parser, with added arguments."""
127*6777b538SAndroid Build Coastguard Worker  parser = argparse.ArgumentParser()
128*6777b538SAndroid Build Coastguard Worker  parser.add_argument('-f', '--file', action='append', default=[],
129*6777b538SAndroid Build Coastguard Worker                      help='Read variables from FILE.')
130*6777b538SAndroid Build Coastguard Worker  parser.add_argument('-i', '--input', default=None,
131*6777b538SAndroid Build Coastguard Worker                      help='Read strings to substitute from FILE.')
132*6777b538SAndroid Build Coastguard Worker  parser.add_argument('-o', '--output', default=None,
133*6777b538SAndroid Build Coastguard Worker                      help='Write substituted strings to FILE.')
134*6777b538SAndroid Build Coastguard Worker  parser.add_argument('-t', '--template', default=None,
135*6777b538SAndroid Build Coastguard Worker                      help='Use TEMPLATE as the strings to substitute.')
136*6777b538SAndroid Build Coastguard Worker  parser.add_argument('-x',
137*6777b538SAndroid Build Coastguard Worker                      '--executable',
138*6777b538SAndroid Build Coastguard Worker                      default=False,
139*6777b538SAndroid Build Coastguard Worker                      action='store_true',
140*6777b538SAndroid Build Coastguard Worker                      help='Set the executable bit on the output (on POSIX).')
141*6777b538SAndroid Build Coastguard Worker  parser.add_argument(
142*6777b538SAndroid Build Coastguard Worker      '-e',
143*6777b538SAndroid Build Coastguard Worker      '--eval',
144*6777b538SAndroid Build Coastguard Worker      action='append',
145*6777b538SAndroid Build Coastguard Worker      default=[],
146*6777b538SAndroid Build Coastguard Worker      help='Evaluate VAL after reading variables. Can be used '
147*6777b538SAndroid Build Coastguard Worker      'to synthesize variables. e.g. -e \'PATCH_HI=int('
148*6777b538SAndroid Build Coastguard Worker      'PATCH)//256.')
149*6777b538SAndroid Build Coastguard Worker  parser.add_argument(
150*6777b538SAndroid Build Coastguard Worker      '-a',
151*6777b538SAndroid Build Coastguard Worker      '--arch',
152*6777b538SAndroid Build Coastguard Worker      default=None,
153*6777b538SAndroid Build Coastguard Worker      choices=android_chrome_version.ARCH_CHOICES,
154*6777b538SAndroid Build Coastguard Worker      help='Set which cpu architecture the build is for.')
155*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--os', default=None, help='Set the target os.')
156*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--official', action='store_true',
157*6777b538SAndroid Build Coastguard Worker                      help='Whether the current build should be an official '
158*6777b538SAndroid Build Coastguard Worker                           'build, used in addition to the environment '
159*6777b538SAndroid Build Coastguard Worker                           'variable.')
160*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--next',
161*6777b538SAndroid Build Coastguard Worker                      action='store_true',
162*6777b538SAndroid Build Coastguard Worker                      help='Whether the current build should be a "next" '
163*6777b538SAndroid Build Coastguard Worker                      'build, which targets pre-release versions of Android.')
164*6777b538SAndroid Build Coastguard Worker  parser.add_argument('args', nargs=argparse.REMAINDER,
165*6777b538SAndroid Build Coastguard Worker                      help='For compatibility: INPUT and OUTPUT can be '
166*6777b538SAndroid Build Coastguard Worker                           'passed as positional arguments.')
167*6777b538SAndroid Build Coastguard Worker  return parser
168*6777b538SAndroid Build Coastguard Worker
169*6777b538SAndroid Build Coastguard Worker
170*6777b538SAndroid Build Coastguard Workerdef BuildEvals(options, parser):
171*6777b538SAndroid Build Coastguard Worker  """Construct a dict of passed '-e' arguments for evaluating."""
172*6777b538SAndroid Build Coastguard Worker  evals = {}
173*6777b538SAndroid Build Coastguard Worker  for expression in options.eval:
174*6777b538SAndroid Build Coastguard Worker    try:
175*6777b538SAndroid Build Coastguard Worker      evals.update(dict([expression.split('=', 1)]))
176*6777b538SAndroid Build Coastguard Worker    except ValueError:
177*6777b538SAndroid Build Coastguard Worker      parser.error('-e requires VAR=VAL')
178*6777b538SAndroid Build Coastguard Worker  return evals
179*6777b538SAndroid Build Coastguard Worker
180*6777b538SAndroid Build Coastguard Worker
181*6777b538SAndroid Build Coastguard Workerdef ModifyOptionsCompat(options, parser):
182*6777b538SAndroid Build Coastguard Worker  """Support compatibility with old versions.
183*6777b538SAndroid Build Coastguard Worker
184*6777b538SAndroid Build Coastguard Worker  Specifically, for old versions that considered the first two
185*6777b538SAndroid Build Coastguard Worker  positional arguments shorthands for --input and --output.
186*6777b538SAndroid Build Coastguard Worker  """
187*6777b538SAndroid Build Coastguard Worker  while len(options.args) and (options.input is None or options.output is None):
188*6777b538SAndroid Build Coastguard Worker    if options.input is None:
189*6777b538SAndroid Build Coastguard Worker      options.input = options.args.pop(0)
190*6777b538SAndroid Build Coastguard Worker    elif options.output is None:
191*6777b538SAndroid Build Coastguard Worker      options.output = options.args.pop(0)
192*6777b538SAndroid Build Coastguard Worker  if options.args:
193*6777b538SAndroid Build Coastguard Worker    parser.error('Unexpected arguments: %r' % options.args)
194*6777b538SAndroid Build Coastguard Worker
195*6777b538SAndroid Build Coastguard Worker
196*6777b538SAndroid Build Coastguard Workerdef GenerateValues(options, evals):
197*6777b538SAndroid Build Coastguard Worker  """Construct a dict of raw values used to generate output.
198*6777b538SAndroid Build Coastguard Worker
199*6777b538SAndroid Build Coastguard Worker  e.g. this could return a dict like
200*6777b538SAndroid Build Coastguard Worker  {
201*6777b538SAndroid Build Coastguard Worker    'BUILD': 74,
202*6777b538SAndroid Build Coastguard Worker  }
203*6777b538SAndroid Build Coastguard Worker
204*6777b538SAndroid Build Coastguard Worker  which would be used to resolve a template like
205*6777b538SAndroid Build Coastguard Worker  'build = "@BUILD@"' into 'build = "74"'
206*6777b538SAndroid Build Coastguard Worker
207*6777b538SAndroid Build Coastguard Worker  """
208*6777b538SAndroid Build Coastguard Worker  values = FetchValues(options.file, options.official)
209*6777b538SAndroid Build Coastguard Worker
210*6777b538SAndroid Build Coastguard Worker  for key, val in evals.items():
211*6777b538SAndroid Build Coastguard Worker    values[key] = str(eval(val, globals(), values))
212*6777b538SAndroid Build Coastguard Worker
213*6777b538SAndroid Build Coastguard Worker  if options.os == 'android':
214*6777b538SAndroid Build Coastguard Worker    android_chrome_version_codes = android_chrome_version.GenerateVersionCodes(
215*6777b538SAndroid Build Coastguard Worker        int(values['BUILD']), int(values['PATCH']), options.arch, options.next)
216*6777b538SAndroid Build Coastguard Worker    values.update(android_chrome_version_codes)
217*6777b538SAndroid Build Coastguard Worker
218*6777b538SAndroid Build Coastguard Worker  return values
219*6777b538SAndroid Build Coastguard Worker
220*6777b538SAndroid Build Coastguard Worker
221*6777b538SAndroid Build Coastguard Workerdef GenerateOutputContents(options, values):
222*6777b538SAndroid Build Coastguard Worker  """Construct output string (e.g. from template).
223*6777b538SAndroid Build Coastguard Worker
224*6777b538SAndroid Build Coastguard Worker  Arguments:
225*6777b538SAndroid Build Coastguard Worker  options -- argparse parsed arguments
226*6777b538SAndroid Build Coastguard Worker  values -- dict with raw values used to resolve the keywords in a template
227*6777b538SAndroid Build Coastguard Worker    string
228*6777b538SAndroid Build Coastguard Worker  """
229*6777b538SAndroid Build Coastguard Worker
230*6777b538SAndroid Build Coastguard Worker  if options.template is not None:
231*6777b538SAndroid Build Coastguard Worker    return SubstTemplate(options.template, values)
232*6777b538SAndroid Build Coastguard Worker  elif options.input:
233*6777b538SAndroid Build Coastguard Worker    return SubstFile(options.input, values)
234*6777b538SAndroid Build Coastguard Worker  else:
235*6777b538SAndroid Build Coastguard Worker    # Generate a default set of version information.
236*6777b538SAndroid Build Coastguard Worker    return """MAJOR=%(MAJOR)s
237*6777b538SAndroid Build Coastguard WorkerMINOR=%(MINOR)s
238*6777b538SAndroid Build Coastguard WorkerBUILD=%(BUILD)s
239*6777b538SAndroid Build Coastguard WorkerPATCH=%(PATCH)s
240*6777b538SAndroid Build Coastguard WorkerLASTCHANGE=%(LASTCHANGE)s
241*6777b538SAndroid Build Coastguard WorkerOFFICIAL_BUILD=%(OFFICIAL_BUILD)s
242*6777b538SAndroid Build Coastguard Worker""" % values
243*6777b538SAndroid Build Coastguard Worker
244*6777b538SAndroid Build Coastguard Worker
245*6777b538SAndroid Build Coastguard Workerdef GenerateOutputMode(options):
246*6777b538SAndroid Build Coastguard Worker  """Construct output mode (e.g. from template).
247*6777b538SAndroid Build Coastguard Worker
248*6777b538SAndroid Build Coastguard Worker  Arguments:
249*6777b538SAndroid Build Coastguard Worker  options -- argparse parsed arguments
250*6777b538SAndroid Build Coastguard Worker  """
251*6777b538SAndroid Build Coastguard Worker  if options.executable:
252*6777b538SAndroid Build Coastguard Worker    return 0o755
253*6777b538SAndroid Build Coastguard Worker  else:
254*6777b538SAndroid Build Coastguard Worker    return 0o644
255*6777b538SAndroid Build Coastguard Worker
256*6777b538SAndroid Build Coastguard Worker
257*6777b538SAndroid Build Coastguard Workerdef BuildOutput(args):
258*6777b538SAndroid Build Coastguard Worker  """Gets all input and output values needed for writing output."""
259*6777b538SAndroid Build Coastguard Worker  # Build argparse parser with arguments
260*6777b538SAndroid Build Coastguard Worker  parser = BuildParser()
261*6777b538SAndroid Build Coastguard Worker  options = parser.parse_args(args)
262*6777b538SAndroid Build Coastguard Worker
263*6777b538SAndroid Build Coastguard Worker  # Get dict of passed '-e' arguments for evaluating
264*6777b538SAndroid Build Coastguard Worker  evals = BuildEvals(options, parser)
265*6777b538SAndroid Build Coastguard Worker  # For compatibility with interface that considered first two positional
266*6777b538SAndroid Build Coastguard Worker  # arguments shorthands for --input and --output.
267*6777b538SAndroid Build Coastguard Worker  ModifyOptionsCompat(options, parser)
268*6777b538SAndroid Build Coastguard Worker
269*6777b538SAndroid Build Coastguard Worker  # Get the raw values that will be used the generate the output
270*6777b538SAndroid Build Coastguard Worker  values = GenerateValues(options, evals)
271*6777b538SAndroid Build Coastguard Worker  # Get the output string and mode
272*6777b538SAndroid Build Coastguard Worker  contents = GenerateOutputContents(options, values)
273*6777b538SAndroid Build Coastguard Worker  mode = GenerateOutputMode(options)
274*6777b538SAndroid Build Coastguard Worker
275*6777b538SAndroid Build Coastguard Worker  return {'options': options, 'contents': contents, 'mode': mode}
276*6777b538SAndroid Build Coastguard Worker
277*6777b538SAndroid Build Coastguard Worker
278*6777b538SAndroid Build Coastguard Workerdef main(args):
279*6777b538SAndroid Build Coastguard Worker  output = BuildOutput(args)
280*6777b538SAndroid Build Coastguard Worker
281*6777b538SAndroid Build Coastguard Worker  if output['options'].output is not None:
282*6777b538SAndroid Build Coastguard Worker    WriteIfChanged(output['options'].output, output['contents'], output['mode'])
283*6777b538SAndroid Build Coastguard Worker  else:
284*6777b538SAndroid Build Coastguard Worker    print(output['contents'])
285*6777b538SAndroid Build Coastguard Worker
286*6777b538SAndroid Build Coastguard Worker  return 0
287*6777b538SAndroid Build Coastguard Worker
288*6777b538SAndroid Build Coastguard Worker
289*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__':
290*6777b538SAndroid Build Coastguard Worker  sys.exit(main(sys.argv[1:]))
291