195640e3a20adea634b4df4ccf8c93f411184c438joi@chromium.org#!/usr/bin/env python
295640e3a20adea634b4df4ccf8c93f411184c438joi@chromium.org# Copyright (c) 2012 The Chromium Authors. All rights reserved.
301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# Use of this source code is governed by a BSD-style license that can be
401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# found in the LICENSE file.
501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org'''Tool to determine inputs and outputs of a grit file.
701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org'''
801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgimport optparse
1001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgimport os
1101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgimport posixpath
1201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgimport sys
1301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
1401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgfrom grit import grd_reader
1501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgfrom grit import util
1601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
1701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgclass WrongNumberOfArguments(Exception):
1801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  pass
1901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
2001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
2111e589a0b4a958ad1b5411692ee576cbee9f6ca5flackr@chromium.orgdef Outputs(filename, defines, ids_file, target_platform=None):
2201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  grd = grd_reader.Parse(
230dc1eef9854b5a4102aee7b7acae978eec2e4df9joi@chromium.org      filename, defines=defines, tags_to_ignore=set(['messages']),
24f505a00e3988cb05335debb4f1803447541e7b15joi@chromium.org      first_ids_file=ids_file, target_platform=target_platform)
2501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
2601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  target = []
2701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  lang_folders = {}
2801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  # Add all explicitly-specified output files
2901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  for output in grd.GetOutputFiles():
3001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    path = output.GetFilename()
3101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    target.append(path)
3201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
3301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    if path.endswith('.h'):
3401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org      path, filename = os.path.split(path)
3501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    if output.attrs['lang']:
3601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org      lang_folders[output.attrs['lang']] = os.path.dirname(path)
3701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
3801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  # Add all generated files, once for each output language.
3901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  for node in grd:
4001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    if node.name == 'structure':
41ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org      with node:
42ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org        # TODO(joi) Should remove the "if sconsdep is true" thing as it is a
43ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org        # hack - see grit/node/structure.py
44ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org        if node.HasFileForLanguage() and node.attrs['sconsdep'] == 'true':
45ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org          for lang in lang_folders:
46ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org            path = node.FileForLanguage(lang, lang_folders[lang],
47ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org                                        create_file=False,
48ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org                                        return_if_not_generated=False)
49ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org            if path:
50ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org              target.append(path)
5101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
5201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  return [t.replace('\\', '/') for t in target]
5301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
5401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
5501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgdef GritSourceFiles():
5601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  files = []
5795640e3a20adea634b4df4ccf8c93f411184c438joi@chromium.org  grit_root_dir = os.path.relpath(os.path.dirname(__file__), os.getcwd())
5801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  for root, dirs, filenames in os.walk(grit_root_dir):
5901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    grit_src = [os.path.join(root, f) for f in filenames
606e5c2fedbf2e45c1f609cbed84732bfba8fb0f63thakis@chromium.org                if f.endswith('.py') and not f.endswith('_unittest.py')]
6101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    files.extend(grit_src)
622de007ecdc529c1019a90e12e47bdb6694f0a01cjoi@chromium.org  return sorted(files)
6301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
6401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
6511e589a0b4a958ad1b5411692ee576cbee9f6ca5flackr@chromium.orgdef Inputs(filename, defines, ids_file, target_platform=None):
6601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  grd = grd_reader.Parse(
67d484c661401bbc7618f359574851d1fb058f3e6fbenrg@chromium.org      filename, debug=False, defines=defines, tags_to_ignore=set(['message']),
68de71a379bc5150da5b063e0de1bc92fe4d87d195joi@chromium.org      first_ids_file=ids_file, target_platform=target_platform)
69ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org  files = set()
70ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org  for lang, ctx in grd.GetConfigurations():
71ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org    grd.SetOutputLanguage(lang or grd.GetSourceLanguage())
72ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org    grd.SetOutputContext(ctx)
73ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org    for node in grd.ActiveDescendants():
74ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org      with node:
75ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org        if (node.name == 'structure' or node.name == 'skeleton' or
76ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org            (node.name == 'file' and node.parent and
77ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org             node.parent.name == 'translations')):
78ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org          files.add(grd.ToRealPath(node.GetInputPath()))
79ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org          # If it's a flattened node, grab inlined resources too.
80ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org          if node.name == 'structure' and node.attrs['flattenhtml'] == 'true':
81ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org            node.RunPreSubstitutionGatherer()
82ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org            files.update(node.GetHtmlResourceFilenames())
83ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org        elif node.name == 'grit':
84ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org          first_ids_file = node.GetFirstIdsFile()
85ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org          if first_ids_file:
86ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org            files.add(first_ids_file)
87ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org        elif node.name == 'include':
88ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org          files.add(grd.ToRealPath(node.GetInputPath()))
89ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org          # If it's a flattened node, grab inlined resources too.
90ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org          if node.attrs['flattenhtml'] == 'true':
91ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org            files.update(node.GetHtmlResourceFilenames())
92ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org        elif node.name == 'part':
93ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org          files.add(util.normpath(os.path.join(os.path.dirname(filename),
94ccda47032903a6550dac2921f88c51b4da55aa36benrg@chromium.org                                               node.GetInputPath())))
9501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
96272e5d33bed17bded9f1997ae1e76e7bb874a574joi@chromium.org  cwd = os.getcwd()
97ec8016c73b3b945b6284746230913d88653f35e7benrg@chromium.org  return [os.path.relpath(f, cwd) for f in sorted(files)]
9801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
9901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
10001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgdef PrintUsage():
1017867001e968e2827b3e70abccfd5a5124815198fjoi@chromium.org  print 'USAGE: ./grit_info.py --inputs [-D foo] [-f resource_ids] <grd-file>'
1027867001e968e2827b3e70abccfd5a5124815198fjoi@chromium.org  print ('       ./grit_info.py --outputs [-D foo] [-f resource_ids] ' +
1037867001e968e2827b3e70abccfd5a5124815198fjoi@chromium.org      '<out-prefix> <grd-file>')
10401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
10501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
10601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgdef DoMain(argv):
10701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  parser = optparse.OptionParser()
10801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  parser.add_option("--inputs", action="store_true", dest="inputs")
10901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  parser.add_option("--outputs", action="store_true", dest="outputs")
11001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  parser.add_option("-D", action="append", dest="defines", default=[])
11101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  # grit build also supports '-E KEY=VALUE', support that to share command
11201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  # line flags.
11301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  parser.add_option("-E", action="append", dest="build_env", default=[])
11401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  parser.add_option("-w", action="append", dest="whitelist_files", default=[])
1157867001e968e2827b3e70abccfd5a5124815198fjoi@chromium.org  parser.add_option("-f", dest="ids_file",
1167867001e968e2827b3e70abccfd5a5124815198fjoi@chromium.org                    default="GRIT_DIR/../gritsettings/resource_ids")
117de71a379bc5150da5b063e0de1bc92fe4d87d195joi@chromium.org  parser.add_option("-t", dest="target_platform", default=None)
11801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
11901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  options, args = parser.parse_args(argv)
12001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
12101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  defines = {}
12201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  for define in options.defines:
123418c15a67abb1566529fb247af2fe3e1c9e8c17dflackr@chromium.org    name, val = util.ParseDefine(define)
124418c15a67abb1566529fb247af2fe3e1c9e8c17dflackr@chromium.org    defines[name] = val
12501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
12612e636bfb67ece29620045b2936d85a95e4d6919joi@chromium.org  for env_pair in options.build_env:
127ef7918f5c87325d97a94438b3adf18e1bc799b7cjoi@chromium.org    (env_name, env_value) = env_pair.split('=', 1)
12812e636bfb67ece29620045b2936d85a95e4d6919joi@chromium.org    os.environ[env_name] = env_value
12912e636bfb67ece29620045b2936d85a95e4d6919joi@chromium.org
13001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  if options.inputs:
13101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    if len(args) > 1:
13201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org      raise WrongNumberOfArguments("Expected 0 or 1 arguments for --inputs.")
13301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
13401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    inputs = []
13501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    if len(args) == 1:
13601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org      filename = args[0]
137de71a379bc5150da5b063e0de1bc92fe4d87d195joi@chromium.org      inputs = Inputs(filename, defines, options.ids_file,
138de71a379bc5150da5b063e0de1bc92fe4d87d195joi@chromium.org                      options.target_platform)
13901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
14001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    # Add in the grit source files.  If one of these change, we want to re-run
14101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    # grit.
14201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    inputs.extend(GritSourceFiles())
14301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    inputs = [f.replace('\\', '/') for f in inputs]
14401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
14501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    if len(args) == 1:
14601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org      # Include grd file as second input (works around gyp expecting it).
14783717e82a9b5e0c629ff4f1078d50503ffd2ae75benrg@chromium.org      inputs.insert(1, args[0])
14801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    if options.whitelist_files:
14901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org      inputs.extend(options.whitelist_files)
15001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    return '\n'.join(inputs)
15101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  elif options.outputs:
15201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    if len(args) != 2:
15383717e82a9b5e0c629ff4f1078d50503ffd2ae75benrg@chromium.org      raise WrongNumberOfArguments(
15483717e82a9b5e0c629ff4f1078d50503ffd2ae75benrg@chromium.org          "Expected exactly 2 arguments for --outputs.")
15501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
15601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    prefix, filename = args
1577867001e968e2827b3e70abccfd5a5124815198fjoi@chromium.org    outputs = [posixpath.join(prefix, f)
158f505a00e3988cb05335debb4f1803447541e7b15joi@chromium.org               for f in Outputs(filename, defines,
159f505a00e3988cb05335debb4f1803447541e7b15joi@chromium.org                                options.ids_file, options.target_platform)]
16001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    return '\n'.join(outputs)
16101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  else:
16201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    raise WrongNumberOfArguments("Expected --inputs or --outputs.")
16301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
16401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
16501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgdef main(argv):
16695640e3a20adea634b4df4ccf8c93f411184c438joi@chromium.org  if sys.version_info < (2, 6):
16795640e3a20adea634b4df4ccf8c93f411184c438joi@chromium.org    print "GRIT requires Python 2.6 or later."
16895640e3a20adea634b4df4ccf8c93f411184c438joi@chromium.org    return 1
16995640e3a20adea634b4df4ccf8c93f411184c438joi@chromium.org
17001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  try:
17101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    result = DoMain(argv[1:])
17201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  except WrongNumberOfArguments, e:
17301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    PrintUsage()
17401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    print e
17501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    return 1
17601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  print result
17701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  return 0
17801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
17901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
18001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgif __name__ == '__main__':
18101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  sys.exit(main(sys.argv))
182