| 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 |