OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python |
| 2 # Copyright (c) 2011 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 |
| 9 import optparse |
| 10 import os |
| 11 import posixpath |
| 12 import types |
| 13 import sys |
| 14 |
| 15 from grit import grd_reader |
| 16 from grit import util |
| 17 |
| 18 ############################################################################## |
| 19 # os.path.relpath is python 2.6 only. Some bots still run 2.5 only, so I took |
| 20 # the relpath implementation from the python source. |
| 21 # TODO(thakis): Once we're on 2.6 everywhere, remove this and use |
| 22 # os.path.relpath directly. |
| 23 |
| 24 # http://docs.python.org/license.html |
| 25 # PSF LICENSE AGREEMENT FOR PYTHON 2.7.1 |
| 26 # |
| 27 # 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), |
| 28 # and the Individual or Organization ("Licensee") accessing and otherwise using |
| 29 # Python 2.7.1 software in source or binary form and its associated |
| 30 # documentation. |
| 31 # |
| 32 # 2. Subject to the terms and conditions of this License Agreement, PSF hereby |
| 33 # grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, |
| 34 # analyze, test, perform and/or display publicly, prepare derivative works, |
| 35 # distribute, and otherwise use Python 2.7.1 alone or in any derivative version, |
| 36 # provided, however, that PSF's License Agreement and PSF's notice of copyright, |
| 37 # i.e., "Copyright c 2001-2010 Python Software Foundation; All Rights Reserved" |
| 38 # are retained in Python 2.7.1 alone or in any derivative version prepared by |
| 39 # Licensee. |
| 40 # |
| 41 # 3. In the event Licensee prepares a derivative work that is based on or |
| 42 # incorporates Python 2.7.1 or any part thereof, and wants to make the |
| 43 # derivative work available to others as provided herein, then Licensee hereby |
| 44 # agrees to include in any such work a brief summary of the changes made to |
| 45 # Python 2.7.1. |
| 46 # |
| 47 # 4. PSF is making Python 2.7.1 available to Licensee on an "AS IS" basis. PSF |
| 48 # MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, |
| 49 # BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY |
| 50 # OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF |
| 51 # PYTHON 2.7.1 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. |
| 52 # |
| 53 # 5.1 PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 2.7.1 FOR |
| 54 # ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF |
| 55 # MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.7.1, OR ANY DERIVATIVE |
| 56 # THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. |
| 57 # |
| 58 # 6. This License Agreement will automatically terminate upon a material breach |
| 59 # of its terms and conditions. |
| 60 # |
| 61 # 7. Nothing in this License Agreement shall be deemed to create any |
| 62 # relationship of agency, partnership, or joint venture between PSF and |
| 63 # Licensee. This License Agreement does not grant permission to use PSF |
| 64 # trademarks or trade name in a trademark sense to endorse or promote products |
| 65 # or services of Licensee, or any third party. |
| 66 # |
| 67 # 8. By copying, installing or otherwise using Python 2.7.1, Licensee agrees to |
| 68 # be bound by the terms and conditions of this License Agreement. |
| 69 |
| 70 # http://svn.python.org/view/python/trunk/Lib/genericpath.py?view=markup |
| 71 def commonprefix(m): |
| 72 "Given a list of pathnames, returns the longest common leading component" |
| 73 if not m: return '' |
| 74 s1 = min(m) |
| 75 s2 = max(m) |
| 76 for i, c in enumerate(s1): |
| 77 if c != s2[i]: |
| 78 return s1[:i] |
| 79 return s1 |
| 80 |
| 81 |
| 82 # http://svn.python.org/view/python/trunk/Lib/posixpath.py?view=markup |
| 83 def relpath(path, start=os.path.curdir): |
| 84 """Return a relative version of a path""" |
| 85 |
| 86 if not path: |
| 87 raise ValueError("no path specified") |
| 88 |
| 89 start_list = os.path.abspath(start).split(os.path.sep) |
| 90 path_list = os.path.abspath(path).split(os.path.sep) |
| 91 |
| 92 # Work out how much of the filepath is shared by start and path. |
| 93 i = len(commonprefix([start_list, path_list])) |
| 94 |
| 95 rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:] |
| 96 if not rel_list: |
| 97 return os.path.curdir |
| 98 return os.path.join(*rel_list) |
| 99 ############################################################################## |
| 100 |
| 101 |
| 102 class WrongNumberOfArguments(Exception): |
| 103 pass |
| 104 |
| 105 |
| 106 def Outputs(filename, defines): |
| 107 grd = grd_reader.Parse( |
| 108 filename, defines=defines, tags_to_ignore=set(['messages'])) |
| 109 |
| 110 target = [] |
| 111 lang_folders = {} |
| 112 # Add all explicitly-specified output files |
| 113 for output in grd.GetOutputFiles(): |
| 114 path = output.GetFilename() |
| 115 target.append(path) |
| 116 |
| 117 if path.endswith('.h'): |
| 118 path, filename = os.path.split(path) |
| 119 if output.attrs['lang']: |
| 120 lang_folders[output.attrs['lang']] = os.path.dirname(path) |
| 121 |
| 122 # Add all generated files, once for each output language. |
| 123 for node in grd: |
| 124 if node.name == 'structure': |
| 125 # TODO(joi) Should remove the "if sconsdep is true" thing as it is a |
| 126 # hack - see grit/node/structure.py |
| 127 if node.HasFileForLanguage() and node.attrs['sconsdep'] == 'true': |
| 128 for lang in lang_folders: |
| 129 path = node.FileForLanguage(lang, lang_folders[lang], |
| 130 create_file=False, |
| 131 return_if_not_generated=False) |
| 132 if path: |
| 133 target.append(path) |
| 134 |
| 135 return [t.replace('\\', '/') for t in target] |
| 136 |
| 137 |
| 138 def GritSourceFiles(): |
| 139 files = [] |
| 140 grit_root_dir = relpath(os.path.dirname(__file__), os.getcwd()) |
| 141 for root, dirs, filenames in os.walk(grit_root_dir): |
| 142 grit_src = [os.path.join(root, f) for f in filenames |
| 143 if f.endswith('.py')] |
| 144 files.extend(grit_src) |
| 145 # TODO(joi@chromium.org): Once we switch to specifying the |
| 146 # resource_ids file via a .grd attribute, it should be considered an |
| 147 # input of grit and this bit should no longer be necessary. |
| 148 default_resource_ids = relpath( |
| 149 os.path.join(grit_root_dir, '..', 'gritsettings', 'resource_ids'), |
| 150 os.getcwd()) |
| 151 if os.path.exists(default_resource_ids): |
| 152 files.append(default_resource_ids) |
| 153 return files |
| 154 |
| 155 |
| 156 def Inputs(filename, defines): |
| 157 grd = grd_reader.Parse( |
| 158 filename, debug=False, defines=defines, tags_to_ignore=set(['messages'])) |
| 159 files = [] |
| 160 for node in grd: |
| 161 if (node.name == 'structure' or node.name == 'skeleton' or |
| 162 (node.name == 'file' and node.parent and |
| 163 node.parent.name == 'translations')): |
| 164 files.append(node.GetFilePath()) |
| 165 elif node.name == 'include': |
| 166 # Only include files that we actually plan on using. |
| 167 if node.SatisfiesOutputCondition(): |
| 168 files.append(node.FilenameToOpen()) |
| 169 # If it's a flattened node, grab inlined resources too. |
| 170 if node.attrs['flattenhtml'] == 'true': |
| 171 files.extend(node.GetHtmlResourceFilenames()) |
| 172 |
| 173 return files |
| 174 |
| 175 |
| 176 def PrintUsage(): |
| 177 print 'USAGE: ./grit_info.py --inputs [-D foo] <grd-file>' |
| 178 print ' ./grit_info.py --outputs [-D foo] <out-prefix> <grd-file>' |
| 179 |
| 180 |
| 181 def DoMain(argv): |
| 182 parser = optparse.OptionParser() |
| 183 parser.add_option("--inputs", action="store_true", dest="inputs") |
| 184 parser.add_option("--outputs", action="store_true", dest="outputs") |
| 185 parser.add_option("-D", action="append", dest="defines", default=[]) |
| 186 # grit build also supports '-E KEY=VALUE', support that to share command |
| 187 # line flags. |
| 188 parser.add_option("-E", action="append", dest="build_env", default=[]) |
| 189 parser.add_option("-w", action="append", dest="whitelist_files", default=[]) |
| 190 |
| 191 options, args = parser.parse_args(argv) |
| 192 |
| 193 defines = {} |
| 194 for define in options.defines: |
| 195 defines[define] = 1 |
| 196 |
| 197 if options.inputs: |
| 198 if len(args) > 1: |
| 199 raise WrongNumberOfArguments("Expected 0 or 1 arguments for --inputs.") |
| 200 |
| 201 inputs = [] |
| 202 if len(args) == 1: |
| 203 filename = args[0] |
| 204 inputs = Inputs(filename, defines) |
| 205 |
| 206 # Add in the grit source files. If one of these change, we want to re-run |
| 207 # grit. |
| 208 inputs.extend(GritSourceFiles()) |
| 209 inputs = [f.replace('\\', '/') for f in inputs] |
| 210 |
| 211 if len(args) == 1: |
| 212 # Include grd file as second input (works around gyp expecting it). |
| 213 inputs = [inputs[0], args[0]] + inputs[1:] |
| 214 if options.whitelist_files: |
| 215 inputs.extend(options.whitelist_files) |
| 216 return '\n'.join(inputs) |
| 217 elif options.outputs: |
| 218 if len(args) != 2: |
| 219 raise WrongNumberOfArguments("Expected exactly 2 arguments for --ouputs.") |
| 220 |
| 221 prefix, filename = args |
| 222 outputs = [posixpath.join(prefix, f) for f in Outputs(filename, defines)] |
| 223 return '\n'.join(outputs) |
| 224 else: |
| 225 raise WrongNumberOfArguments("Expected --inputs or --outputs.") |
| 226 |
| 227 |
| 228 def main(argv): |
| 229 try: |
| 230 result = DoMain(argv[1:]) |
| 231 except WrongNumberOfArguments, e: |
| 232 PrintUsage() |
| 233 print e |
| 234 return 1 |
| 235 print result |
| 236 return 0 |
| 237 |
| 238 |
| 239 if __name__ == '__main__': |
| 240 sys.exit(main(sys.argv)) |
OLD | NEW |