1#!/usr/bin/env python 2# Copyright (c) 2012 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'''Tool to determine inputs and outputs of a grit file. 7''' 8 9from __future__ import print_function 10 11import optparse 12import os 13import posixpath 14import sys 15 16from grit import grd_reader 17from grit import util 18 19class WrongNumberOfArguments(Exception): 20 pass 21 22 23def Outputs(filename, defines, ids_file, target_platform=None): 24 grd = grd_reader.Parse( 25 filename, defines=defines, tags_to_ignore=set(['messages']), 26 first_ids_file=ids_file, target_platform=target_platform) 27 28 target = [] 29 lang_folders = {} 30 # Add all explicitly-specified output files 31 for output in grd.GetOutputFiles(): 32 path = output.GetFilename() 33 target.append(path) 34 35 if path.endswith('.h'): 36 path, filename = os.path.split(path) 37 if output.attrs['lang']: 38 lang_folders[output.attrs['lang']] = os.path.dirname(path) 39 40 return [t.replace('\\', '/') for t in target] 41 42 43def GritSourceFiles(): 44 files = [] 45 grit_root_dir = os.path.relpath(os.path.dirname(__file__), os.getcwd()) 46 for root, dirs, filenames in os.walk(grit_root_dir): 47 grit_src = [os.path.join(root, f) for f in filenames 48 if f.endswith('.py') and not f.endswith('_unittest.py')] 49 files.extend(grit_src) 50 return sorted(files) 51 52 53def Inputs(filename, defines, ids_file, target_platform=None): 54 grd = grd_reader.Parse( 55 filename, debug=False, defines=defines, tags_to_ignore=set(['message']), 56 first_ids_file=ids_file, target_platform=target_platform) 57 files = set() 58 for lang, ctx, fallback in grd.GetConfigurations(): 59 # TODO(tdanderson): Refactor all places which perform the action of setting 60 # output attributes on the root. See crbug.com/503637. 61 grd.SetOutputLanguage(lang or grd.GetSourceLanguage()) 62 grd.SetOutputContext(ctx) 63 grd.SetFallbackToDefaultLayout(fallback) 64 for node in grd.ActiveDescendants(): 65 with node: 66 if (node.name == 'structure' or node.name == 'skeleton' or 67 (node.name == 'file' and node.parent and 68 node.parent.name == 'translations')): 69 path = node.GetInputPath() 70 if path is not None: 71 files.add(grd.ToRealPath(path)) 72 73 # If it's a flattened node, grab inlined resources too. 74 if node.name == 'structure' and node.attrs['flattenhtml'] == 'true': 75 node.RunPreSubstitutionGatherer() 76 files.update(node.GetHtmlResourceFilenames()) 77 elif node.name == 'grit': 78 first_ids_file = node.GetFirstIdsFile() 79 if first_ids_file: 80 files.add(first_ids_file) 81 elif node.name == 'include': 82 files.add(grd.ToRealPath(node.GetInputPath())) 83 # If it's a flattened node, grab inlined resources too. 84 if node.attrs['flattenhtml'] == 'true': 85 files.update(node.GetHtmlResourceFilenames()) 86 elif node.name == 'part': 87 files.add(util.normpath(os.path.join(os.path.dirname(filename), 88 node.GetInputPath()))) 89 90 cwd = os.getcwd() 91 return [os.path.relpath(f, cwd) for f in sorted(files)] 92 93 94def PrintUsage(): 95 print('USAGE: ./grit_info.py --inputs [-D foo] [-f resource_ids] <grd-file>') 96 print(' ./grit_info.py --outputs [-D foo] [-f resource_ids] ' + 97 '<out-prefix> <grd-file>') 98 99 100def DoMain(argv): 101 os.environ['cwd'] = os.getcwd() 102 103 parser = optparse.OptionParser() 104 parser.add_option("--inputs", action="store_true", dest="inputs") 105 parser.add_option("--outputs", action="store_true", dest="outputs") 106 parser.add_option("-D", action="append", dest="defines", default=[]) 107 # grit build also supports '-E KEY=VALUE', support that to share command 108 # line flags. 109 parser.add_option("-E", action="append", dest="build_env", default=[]) 110 parser.add_option("-p", action="store", dest="predetermined_ids_file") 111 parser.add_option("-w", action="append", dest="allowlist_files", default=[]) 112 parser.add_option("-f", dest="ids_file", default="") 113 parser.add_option("-t", dest="target_platform", default=None) 114 115 options, args = parser.parse_args(argv) 116 117 defines = {} 118 for define in options.defines: 119 name, val = util.ParseDefine(define) 120 defines[name] = val 121 122 for env_pair in options.build_env: 123 (env_name, env_value) = env_pair.split('=', 1) 124 os.environ[env_name] = env_value 125 126 if options.inputs: 127 if len(args) > 1: 128 raise WrongNumberOfArguments("Expected 0 or 1 arguments for --inputs.") 129 130 inputs = [] 131 if len(args) == 1: 132 filename = args[0] 133 inputs = Inputs(filename, defines, options.ids_file, 134 options.target_platform) 135 136 # Add in the grit source files. If one of these change, we want to re-run 137 # grit. 138 inputs.extend(GritSourceFiles()) 139 inputs = [f.replace('\\', '/') for f in inputs] 140 141 if len(args) == 1: 142 # Include grd file as second input (works around gyp expecting it). 143 inputs.insert(1, args[0]) 144 if options.allowlist_files: 145 inputs.extend(options.allowlist_files) 146 return '\n'.join(inputs) 147 elif options.outputs: 148 if len(args) != 2: 149 raise WrongNumberOfArguments( 150 "Expected exactly 2 arguments for --outputs.") 151 152 prefix, filename = args 153 outputs = [posixpath.join(prefix, f) 154 for f in Outputs(filename, defines, 155 options.ids_file, options.target_platform)] 156 return '\n'.join(outputs) 157 else: 158 raise WrongNumberOfArguments("Expected --inputs or --outputs.") 159 160 161def main(argv): 162 try: 163 result = DoMain(argv[1:]) 164 except WrongNumberOfArguments as e: 165 PrintUsage() 166 print(e) 167 return 1 168 print(result) 169 return 0 170 171 172if __name__ == '__main__': 173 sys.exit(main(sys.argv)) 174