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 '''Miscellaneous node types. | 6 '''Miscellaneous node types. |
7 ''' | 7 ''' |
8 | 8 |
9 import os.path | 9 import os.path |
10 import re | 10 import re |
11 import sys | 11 import sys |
12 | 12 |
13 from grit.node import base | 13 from grit.node import base |
14 from grit.node import message | 14 from grit.node import message |
15 | 15 |
16 from grit import exception | 16 from grit import exception |
17 from grit import constants | 17 from grit import constants |
18 from grit import util | 18 from grit import util |
19 | 19 |
20 import grit.format.rc_header | 20 import grit.format.rc_header |
21 | 21 |
22 | 22 |
| 23 # RTL languages |
| 24 # TODO(jennyz): remove this fixed set of RTL language array |
| 25 # now that generic expand_variable code exists. |
| 26 _RTL_LANGS = ( |
| 27 'ar', # Arabic |
| 28 'fa', # Farsi |
| 29 'iw', # Hebrew |
| 30 'ks', # Kashmiri |
| 31 'ku', # Kurdish |
| 32 'ps', # Pashto |
| 33 'ur', # Urdu |
| 34 'yi', # Yiddish |
| 35 ) |
| 36 |
| 37 |
23 def _ReadFirstIdsFromFile(filename, defines): | 38 def _ReadFirstIdsFromFile(filename, defines): |
24 '''Read the starting resource id values from |filename|. We also | 39 '''Read the starting resource id values from |filename|. We also |
25 expand variables of the form <(FOO) based on defines passed in on | 40 expand variables of the form <(FOO) based on defines passed in on |
26 the command line. | 41 the command line. |
27 | 42 |
28 Returns a tuple, the absolute path of SRCDIR followed by the | 43 Returns a tuple, the absolute path of SRCDIR followed by the |
29 first_ids dictionary. | 44 first_ids dictionary. |
30 ''' | 45 ''' |
31 first_ids_dict = eval(open(filename).read()) | 46 first_ids_dict = eval(open(filename).read()) |
32 src_root_dir = os.path.abspath(os.path.join(os.path.dirname(filename), | 47 src_root_dir = os.path.abspath(os.path.join(os.path.dirname(filename), |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
81 | 96 |
82 def MandatoryAttributes(self): | 97 def MandatoryAttributes(self): |
83 return ['expr'] | 98 return ['expr'] |
84 | 99 |
85 def IsConditionSatisfied(self): | 100 def IsConditionSatisfied(self): |
86 '''Returns true if and only if the Python expression stored in attribute | 101 '''Returns true if and only if the Python expression stored in attribute |
87 'expr' evaluates to true. | 102 'expr' evaluates to true. |
88 ''' | 103 ''' |
89 return self.EvaluateCondition(self.attrs['expr']) | 104 return self.EvaluateCondition(self.attrs['expr']) |
90 | 105 |
| 106 def SatisfiesOutputCondition(self): |
| 107 '''Returns true if its condition is satisfied, including on ancestors.''' |
| 108 if not self.IsConditionSatisfied(): |
| 109 return False |
| 110 else: |
| 111 return base.Node.SatisfiesOutputCondition(self) |
| 112 |
91 | 113 |
92 class ReleaseNode(base.Node): | 114 class ReleaseNode(base.Node): |
93 '''The <release> element.''' | 115 '''The <release> element.''' |
94 | 116 |
95 def _IsValidChild(self, child): | 117 def _IsValidChild(self, child): |
96 from grit.node import empty | 118 from grit.node import empty |
97 return isinstance(child, (empty.IncludesNode, empty.MessagesNode, | 119 return isinstance(child, (empty.IncludesNode, empty.MessagesNode, |
98 empty.StructuresNode, empty.IdentifiersNode)) | 120 empty.StructuresNode, empty.IdentifiersNode)) |
99 | 121 |
100 def _IsValidAttribute(self, name, value): | 122 def _IsValidAttribute(self, name, value): |
(...skipping 19 matching lines...) Expand all Loading... |
120 else: | 142 else: |
121 return super(type(self), self).ItemFormatter(t) | 143 return super(type(self), self).ItemFormatter(t) |
122 | 144 |
123 class GritNode(base.Node): | 145 class GritNode(base.Node): |
124 '''The <grit> root element.''' | 146 '''The <grit> root element.''' |
125 | 147 |
126 def __init__(self): | 148 def __init__(self): |
127 base.Node.__init__(self) | 149 base.Node.__init__(self) |
128 self.output_language = '' | 150 self.output_language = '' |
129 self.defines = {} | 151 self.defines = {} |
| 152 self.substituter = util.Substituter() |
130 | 153 |
131 def _IsValidChild(self, child): | 154 def _IsValidChild(self, child): |
132 from grit.node import empty | 155 from grit.node import empty |
133 return isinstance(child, (ReleaseNode, empty.TranslationsNode, | 156 return isinstance(child, (ReleaseNode, empty.TranslationsNode, |
134 empty.OutputsNode)) | 157 empty.OutputsNode)) |
135 | 158 |
136 def _IsValidAttribute(self, name, value): | 159 def _IsValidAttribute(self, name, value): |
137 if name not in ['base_dir', 'first_ids_file', 'source_lang_id', | 160 if name not in ['base_dir', 'first_ids_file', 'source_lang_id', |
138 'latest_public_release', 'current_release', | 161 'latest_public_release', 'current_release', |
139 'enc_check', 'tc_project']: | 162 'enc_check', 'tc_project', 'grit_version']: |
140 return False | 163 return False |
141 if name in ['latest_public_release', 'current_release'] and value.strip( | 164 if name in ['latest_public_release', 'current_release'] and value.strip( |
142 '0123456789') != '': | 165 '0123456789') != '': |
143 return False | 166 return False |
144 return True | 167 return True |
145 | 168 |
146 def MandatoryAttributes(self): | 169 def MandatoryAttributes(self): |
147 return ['latest_public_release', 'current_release'] | 170 return ['latest_public_release', 'current_release'] |
148 | 171 |
149 def DefaultAttributes(self): | 172 def DefaultAttributes(self): |
150 return { | 173 return { |
151 'base_dir' : '.', | 174 'base_dir' : '.', |
152 'first_ids_file': '', | 175 'first_ids_file': '', |
| 176 'grit_version': 1, |
153 'source_lang_id' : 'en', | 177 'source_lang_id' : 'en', |
154 'enc_check' : constants.ENCODING_CHECK, | 178 'enc_check' : constants.ENCODING_CHECK, |
155 'tc_project' : 'NEED_TO_SET_tc_project_ATTRIBUTE', | 179 'tc_project' : 'NEED_TO_SET_tc_project_ATTRIBUTE', |
156 } | 180 } |
157 | 181 |
158 def EndParsing(self): | 182 def EndParsing(self): |
159 base.Node.EndParsing(self) | 183 base.Node.EndParsing(self) |
160 if (int(self.attrs['latest_public_release']) | 184 if (int(self.attrs['latest_public_release']) |
161 > int(self.attrs['current_release'])): | 185 > int(self.attrs['current_release'])): |
162 raise exception.Parsing('latest_public_release cannot have a greater ' | 186 raise exception.Parsing('latest_public_release cannot have a greater ' |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
284 '''Returns the list of <output> nodes that are descendants of this node's | 308 '''Returns the list of <output> nodes that are descendants of this node's |
285 <outputs> child and are not enclosed by unsatisfied <if> conditionals. | 309 <outputs> child and are not enclosed by unsatisfied <if> conditionals. |
286 ''' | 310 ''' |
287 for child in self.children: | 311 for child in self.children: |
288 if child.name == 'outputs': | 312 if child.name == 'outputs': |
289 output_files = [] | 313 output_files = [] |
290 self._CollectOutputFiles(child.children, output_files) | 314 self._CollectOutputFiles(child.children, output_files) |
291 return output_files | 315 return output_files |
292 raise exception.MissingElement() | 316 raise exception.MissingElement() |
293 | 317 |
| 318 def GetSubstitutionMessages(self): |
| 319 '''Returns the list of <message sub_variable="true"> nodes.''' |
| 320 msg_nodes = self.GetChildrenOfType(message.MessageNode) |
| 321 return [n for n in msg_nodes if |
| 322 n.attrs['sub_variable'] == 'true' and n.SatisfiesOutputCondition()] |
| 323 |
294 def ItemFormatter(self, t): | 324 def ItemFormatter(self, t): |
295 if t == 'rc_header': | 325 if t == 'rc_header': |
296 from grit.format import rc_header # import here to avoid circular dep | 326 from grit.format import rc_header # import here to avoid circular dep |
297 return rc_header.TopLevel() | 327 return rc_header.TopLevel() |
298 elif t in ['rc_all', 'rc_translateable', 'rc_nontranslateable']: | 328 elif t in ['rc_all', 'rc_translateable', 'rc_nontranslateable']: |
299 from grit.format import rc # avoid circular dep | 329 from grit.format import rc # avoid circular dep |
300 return rc.TopLevel() | 330 return rc.TopLevel() |
301 elif t == 'c_format': | 331 elif t == 'c_format': |
302 from grit.format import c_format | 332 from grit.format import c_format |
303 return c_format.TopLevel() | 333 return c_format.TopLevel() |
304 elif t == 'resource_map_header': | 334 elif t == 'resource_map_header': |
305 from grit.format import resource_map | 335 from grit.format import resource_map |
306 return resource_map.HeaderTopLevel() | 336 return resource_map.HeaderTopLevel() |
307 elif t in ('resource_map_source', 'resource_file_map_source'): | 337 elif t in ('resource_map_source', 'resource_file_map_source'): |
308 from grit.format import resource_map | 338 from grit.format import resource_map |
309 return resource_map.SourceTopLevel() | 339 return resource_map.SourceTopLevel() |
310 elif t == 'js_map_format': | 340 elif t == 'js_map_format': |
311 from grit.format import js_map_format | 341 from grit.format import js_map_format |
312 return js_map_format.TopLevel() | 342 return js_map_format.TopLevel() |
313 elif t in ('adm', 'plist', 'plist_strings', 'admx', 'adml', 'doc', 'json', | 343 elif t in ('adm', 'plist', 'plist_strings', 'admx', 'adml', 'doc', 'json', |
314 'reg'): | 344 'reg'): |
315 from grit.format.policy_templates import template_formatter | 345 from grit.format.policy_templates import template_formatter |
316 return template_formatter.TemplateFormatter(t) | 346 return template_formatter.TemplateFormatter(t) |
317 else: | 347 else: |
318 return super(type(self), self).ItemFormatter(t) | 348 return super(type(self), self).ItemFormatter(t) |
319 | 349 |
320 def SetOutputContext(self, output_language, defines): | 350 def SetOutputContext(self, output_language, defines): |
| 351 '''Set the output context: language and defines. Prepares substitutions. |
| 352 |
| 353 The substitutions are reset every time the OutputContext is changed. |
| 354 They include messages designated as variables, and language codes for html |
| 355 and rc files. |
| 356 |
| 357 Args: |
| 358 output_language: a two-letter language code (eg: 'en', 'ar'...) |
| 359 defines: a map of names to values (strings or booleans.) |
| 360 ''' |
| 361 output_language = output_language or self.GetSourceLanguage() |
321 self.output_language = output_language | 362 self.output_language = output_language |
322 self.defines = defines | 363 self.defines = defines |
| 364 self.substituter.AddMessages(self.GetSubstitutionMessages(), |
| 365 output_language) |
| 366 if output_language in _RTL_LANGS: |
| 367 direction = 'dir="RTL"' |
| 368 else: |
| 369 direction = 'dir="LTR"' |
| 370 self.substituter.AddSubstitutions({ |
| 371 'GRITLANGCODE': output_language, |
| 372 'GRITDIR': direction, |
| 373 }) |
| 374 from grit.format import rc # avoid circular dep |
| 375 rc.RcSubstitutions(self.substituter, output_language) |
323 | 376 |
324 def SetDefines(self, defines): | 377 def SetDefines(self, defines): |
325 self.defines = defines | 378 self.defines = defines |
326 | 379 |
327 def AssignFirstIds(self, filename_or_stream, defines): | 380 def AssignFirstIds(self, filename_or_stream, defines): |
328 '''Assign first ids to each grouping node based on values from the | 381 '''Assign first ids to each grouping node based on values from the |
329 first_ids file (if specified on the <grit> node). | 382 first_ids file (if specified on the <grit> node). |
330 ''' | 383 ''' |
331 # If the input is a stream, then we're probably in a unit test and | 384 # If the input is a stream, then we're probably in a unit test and |
332 # should skip this step. | 385 # should skip this step. |
(...skipping 30 matching lines...) Expand all Loading... |
363 'update that file.' % (first_ids_filename, filename)) | 416 'update that file.' % (first_ids_filename, filename)) |
364 print '-' * 78 | 417 print '-' * 78 |
365 raise e | 418 raise e |
366 | 419 |
367 try: | 420 try: |
368 node.attrs['first_id'] = str(id_list.pop(0)) | 421 node.attrs['first_id'] = str(id_list.pop(0)) |
369 except IndexError, e: | 422 except IndexError, e: |
370 raise Exception('Please update %s and add a first id for %s (%s).' | 423 raise Exception('Please update %s and add a first id for %s (%s).' |
371 % (first_ids_filename, filename, node.name)) | 424 % (first_ids_filename, filename, node.name)) |
372 | 425 |
| 426 def RunGatherers(self, recursive=0, debug=False): |
| 427 '''Gathers information for the structure nodes, then apply substitutions. |
| 428 |
| 429 The substitutions step requires that the OutputContext has been set. |
| 430 Locally, get the Substitution messages |
| 431 and add them to the substituter. Also add substitutions for language codes |
| 432 in the Rc. |
| 433 |
| 434 Args: |
| 435 recursive: will call RunGatherers() recursively on all child nodes first. |
| 436 debug: will print information while running gatherers. |
| 437 ''' |
| 438 base.Node.RunGatherers(self, recursive, False) |
| 439 assert self.output_language |
| 440 self.SubstituteMessages(self.substituter) |
| 441 |
373 | 442 |
374 class IdentifierNode(base.Node): | 443 class IdentifierNode(base.Node): |
375 '''A node for specifying identifiers that should appear in the resource | 444 '''A node for specifying identifiers that should appear in the resource |
376 header file, and be unique amongst all other resource identifiers, but don't | 445 header file, and be unique amongst all other resource identifiers, but don't |
377 have any other attributes or reference any resources. | 446 have any other attributes or reference any resources. |
378 ''' | 447 ''' |
379 | 448 |
380 def MandatoryAttributes(self): | 449 def MandatoryAttributes(self): |
381 return ['name'] | 450 return ['name'] |
382 | 451 |
(...skipping 17 matching lines...) Expand all Loading... |
400 by parameters of the same name. | 469 by parameters of the same name. |
401 ''' | 470 ''' |
402 node = IdentifierNode() | 471 node = IdentifierNode() |
403 node.StartParsing('identifier', parent) | 472 node.StartParsing('identifier', parent) |
404 node.HandleAttribute('name', name) | 473 node.HandleAttribute('name', name) |
405 node.HandleAttribute('id', id) | 474 node.HandleAttribute('id', id) |
406 node.HandleAttribute('comment', comment) | 475 node.HandleAttribute('comment', comment) |
407 node.EndParsing() | 476 node.EndParsing() |
408 return node | 477 return node |
409 Construct = staticmethod(Construct) | 478 Construct = staticmethod(Construct) |
OLD | NEW |