OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 '''The 'grit build' tool along with integration for this tool with the | 6 '''The 'grit build' tool along with integration for this tool with the |
7 SCons build system. | 7 SCons build system. |
8 ''' | 8 ''' |
9 | 9 |
10 import filecmp | 10 import filecmp |
11 import getopt | 11 import getopt |
12 import os | 12 import os |
13 import shutil | 13 import shutil |
14 import sys | 14 import sys |
15 import types | 15 import types |
16 | 16 |
17 from grit import grd_reader | 17 from grit import grd_reader |
18 from grit import util | 18 from grit import util |
19 from grit.tool import interface | 19 from grit.tool import interface |
20 from grit import shortcuts | 20 from grit import shortcuts |
21 | 21 |
22 | 22 |
23 def ParseDefine(define): | |
24 '''Parses a define that is either like "NAME" or "NAME=VAL" and | |
25 returns its components, using True as the default value. Values of | |
26 "1" and "0" are transformed to True and False respectively. | |
27 ''' | |
28 parts = [part.strip() for part in define.split('=')] | |
29 assert len(parts) >= 1 | |
30 name = parts[0] | |
31 val = True | |
32 if len(parts) > 1: | |
33 val = parts[1] | |
34 if val == "1": val = True | |
35 elif val == "0": val = False | |
36 return (name, val) | |
37 | |
38 | |
39 class RcBuilder(interface.Tool): | 23 class RcBuilder(interface.Tool): |
40 '''A tool that builds RC files and resource header files for compilation. | 24 '''A tool that builds RC files and resource header files for compilation. |
41 | 25 |
42 Usage: grit build [-o OUTPUTDIR] [-D NAME[=VAL]]* | 26 Usage: grit build [-o OUTPUTDIR] [-D NAME[=VAL]]* |
43 | 27 |
44 All output options for this tool are specified in the input file (see | 28 All output options for this tool are specified in the input file (see |
45 'grit help' for details on how to specify the input file - it is a global | 29 'grit help' for details on how to specify the input file - it is a global |
46 option). | 30 option). |
47 | 31 |
48 Options: | 32 Options: |
(...skipping 28 matching lines...) Expand all Loading... |
77 | 61 |
78 def Run(self, opts, args): | 62 def Run(self, opts, args): |
79 self.output_directory = '.' | 63 self.output_directory = '.' |
80 first_ids_file = None | 64 first_ids_file = None |
81 whitelist_filenames = [] | 65 whitelist_filenames = [] |
82 (own_opts, args) = getopt.getopt(args, 'o:D:E:f:w:') | 66 (own_opts, args) = getopt.getopt(args, 'o:D:E:f:w:') |
83 for (key, val) in own_opts: | 67 for (key, val) in own_opts: |
84 if key == '-o': | 68 if key == '-o': |
85 self.output_directory = val | 69 self.output_directory = val |
86 elif key == '-D': | 70 elif key == '-D': |
87 name, val = ParseDefine(val) | 71 name, val = util.ParseDefine(val) |
88 self.defines[name] = val | 72 self.defines[name] = val |
89 elif key == '-E': | 73 elif key == '-E': |
90 (env_name, env_value) = val.split('=') | 74 (env_name, env_value) = val.split('=') |
91 os.environ[env_name] = env_value | 75 os.environ[env_name] = env_value |
92 elif key == '-f': | 76 elif key == '-f': |
93 # TODO(joi@chromium.org): Remove this override once change | 77 # TODO(joi@chromium.org): Remove this override once change |
94 # lands in WebKit.grd to specify the first_ids_file in the | 78 # lands in WebKit.grd to specify the first_ids_file in the |
95 # .grd itself. | 79 # .grd itself. |
96 first_ids_file = val | 80 first_ids_file = val |
97 elif key == '-w': | 81 elif key == '-w': |
98 whitelist_filenames.append(val) | 82 whitelist_filenames.append(val) |
99 | 83 |
100 if len(args): | 84 if len(args): |
101 print "This tool takes no tool-specific arguments." | 85 print 'This tool takes no tool-specific arguments.' |
102 return 2 | 86 return 2 |
103 self.SetOptions(opts) | 87 self.SetOptions(opts) |
104 if self.scons_targets: | 88 if self.scons_targets: |
105 self.VerboseOut('Using SCons targets to identify files to output.\n') | 89 self.VerboseOut('Using SCons targets to identify files to output.\n') |
106 else: | 90 else: |
107 self.VerboseOut('Output directory: %s (absolute path: %s)\n' % | 91 self.VerboseOut('Output directory: %s (absolute path: %s)\n' % |
108 (self.output_directory, | 92 (self.output_directory, |
109 os.path.abspath(self.output_directory))) | 93 os.path.abspath(self.output_directory))) |
110 | 94 |
111 if whitelist_filenames: | 95 if whitelist_filenames: |
112 self.whitelist_names = set() | 96 self.whitelist_names = set() |
113 for whitelist_filename in whitelist_filenames: | 97 for whitelist_filename in whitelist_filenames: |
114 self.VerboseOut('Using whitelist: %s\n' % whitelist_filename); | 98 self.VerboseOut('Using whitelist: %s\n' % whitelist_filename); |
115 whitelist_file = open(whitelist_filename) | 99 whitelist_file = open(whitelist_filename) |
116 self.whitelist_names |= set(whitelist_file.read().strip().split('\n')) | 100 self.whitelist_names |= set(whitelist_file.read().strip().split('\n')) |
117 whitelist_file.close() | 101 whitelist_file.close() |
118 | 102 |
119 self.res = grd_reader.Parse(opts.input, | 103 self.res = grd_reader.Parse(opts.input, |
120 debug=opts.extra_verbose, | 104 debug=opts.extra_verbose, |
121 first_ids_file=first_ids_file, | 105 first_ids_file=first_ids_file, |
122 defines=self.defines) | 106 defines=self.defines) |
123 # Set an output context so that conditionals can use defines during the | 107 # Set an output context so that conditionals can use defines during the |
124 # gathering stage; we use a dummy language here since we are not outputting | 108 # gathering stage; we use a dummy language here since we are not outputting |
125 # a specific language. | 109 # a specific language. |
126 self.res.SetOutputContext('no-specific-language', self.defines) | 110 self.res.SetOutputContext('en', self.defines) |
127 self.res.RunGatherers(recursive = True) | 111 self.res.RunGatherers(recursive = True) |
128 self.Process() | 112 self.Process() |
129 return 0 | 113 return 0 |
130 | 114 |
131 def __init__(self, defines=None): | 115 def __init__(self, defines=None): |
132 # Default file-creation function is built-in file(). Only done to allow | 116 # Default file-creation function is built-in file(). Only done to allow |
133 # overriding by unit test. | 117 # overriding by unit test. |
134 self.fo_create = file | 118 self.fo_create = file |
135 | 119 |
136 # key/value pairs of C-preprocessor like defines that are used for | 120 # key/value pairs of C-preprocessor like defines that are used for |
137 # conditional output of resources | 121 # conditional output of resources |
138 if defines: | 122 self.defines = defines or {} |
139 self.defines = defines | |
140 else: | |
141 self.defines = {} | |
142 | 123 |
143 # self.res is a fully-populated resource tree if Run() | 124 # self.res is a fully-populated resource tree if Run() |
144 # has been called, otherwise None. | 125 # has been called, otherwise None. |
145 self.res = None | 126 self.res = None |
146 | 127 |
147 # Set to a list of filenames for the output nodes that are relative | 128 # Set to a list of filenames for the output nodes that are relative |
148 # to the current working directory. They are in the same order as the | 129 # to the current working directory. They are in the same order as the |
149 # output nodes in the file. | 130 # output nodes in the file. |
150 self.scons_targets = None | 131 self.scons_targets = None |
151 | 132 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 # Note: Some Format calls have side effects, so Format is always called | 166 # Note: Some Format calls have side effects, so Format is always called |
186 # and the whitelist is used to only avoid the output. | 167 # and the whitelist is used to only avoid the output. |
187 should_write = not node.WhitelistMarkedAsSkip() | 168 should_write = not node.WhitelistMarkedAsSkip() |
188 | 169 |
189 base_dir = util.dirname(output_node.GetOutputFilename()) | 170 base_dir = util.dirname(output_node.GetOutputFilename()) |
190 | 171 |
191 try: | 172 try: |
192 formatter = node.ItemFormatter(output_node.GetType()) | 173 formatter = node.ItemFormatter(output_node.GetType()) |
193 if formatter: | 174 if formatter: |
194 formatted = formatter.Format(node, output_node.GetLanguage(), | 175 formatted = formatter.Format(node, output_node.GetLanguage(), |
195 begin_item=True, output_dir=base_dir) | 176 output_dir=base_dir) |
196 if should_write: | 177 if should_write: |
197 outfile.write(formatted) | 178 outfile.write(formatted) |
198 except: | 179 except: |
199 print u"Error processing node %s" % unicode(node) | 180 print u'Error processing node %s' % unicode(node) |
200 raise | 181 raise |
201 | 182 |
202 for child in node.children: | 183 for child in node.children: |
203 RcBuilder.ProcessNode(child, output_node, outfile) | 184 RcBuilder.ProcessNode(child, output_node, outfile) |
204 | 185 |
205 try: | 186 try: |
206 if formatter: | 187 if formatter: |
207 formatted = formatter.Format(node, output_node.GetLanguage(), | 188 formatted = formatter.FormatEnd(node, output_node.GetLanguage(), |
208 begin_item=False, output_dir=base_dir) | 189 output_dir=base_dir) |
209 if should_write: | 190 if should_write: |
210 outfile.write(formatted) | 191 outfile.write(formatted) |
211 except: | 192 except: |
212 print u"Error processing node %s" % unicode(node) | 193 print u'Error processing node %s' % unicode(node) |
213 raise | 194 raise |
214 ProcessNode = staticmethod(ProcessNode) | 195 ProcessNode = staticmethod(ProcessNode) |
215 | 196 |
216 | 197 |
217 def Process(self): | 198 def Process(self): |
218 # Update filenames with those provided by SCons if we're being invoked | 199 # Update filenames with those provided by SCons if we're being invoked |
219 # from SCons. The list of SCons targets also includes all <structure> | 200 # from SCons. The list of SCons targets also includes all <structure> |
220 # node outputs, but it starts with our output files, in the order they | 201 # node outputs, but it starts with our output files, in the order they |
221 # occur in the .grd | 202 # occur in the .grd |
222 if self.scons_targets: | 203 if self.scons_targets: |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
303 | 284 |
304 # Print out any fallback warnings, and missing translation errors, and | 285 # Print out any fallback warnings, and missing translation errors, and |
305 # exit with an error code if there are missing translations in a non-pseudo | 286 # exit with an error code if there are missing translations in a non-pseudo |
306 # and non-official build. | 287 # and non-official build. |
307 warnings = (self.res.UberClique().MissingTranslationsReport(). | 288 warnings = (self.res.UberClique().MissingTranslationsReport(). |
308 encode('ascii', 'replace')) | 289 encode('ascii', 'replace')) |
309 if warnings and self.defines.get('_google_chrome', False): | 290 if warnings and self.defines.get('_google_chrome', False): |
310 print warnings | 291 print warnings |
311 if self.res.UberClique().HasMissingTranslations(): | 292 if self.res.UberClique().HasMissingTranslations(): |
312 sys.exit(-1) | 293 sys.exit(-1) |
OLD | NEW |