Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(28)

Side by Side Diff: grit/node/misc.py

Issue 7994004: Initial source commit to grit-i18n project. (Closed) Base URL: http://grit-i18n.googlecode.com/svn/trunk/
Patch Set: Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « grit/node/message_unittest.py ('k') | grit/node/misc_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 #!/usr/bin/python2.4
2 # Copyright (c) 2010 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 '''Miscellaneous node types.
7 '''
8
9 import os.path
10 import re
11 import sys
12
13 from grit.node import base
14 from grit.node import message
15
16 from grit import exception
17 from grit import constants
18 from grit import util
19
20 import grit.format.rc_header
21
22
23 def _ReadFirstIdsFromFile(filename, defines):
24 '''Read the starting resource id values from |filename|. We also
25 expand variables of the form <(FOO) based on defines passed in on
26 the command line.
27
28 Returns a tuple, the absolute path of SRCDIR followed by the
29 first_ids dictionary.
30 '''
31 first_ids_dict = eval(open(filename).read())
32
33 # TODO(joi@chromium.org): It might make sense to make this a
34 # parameter of the .grd file rather than of the resource_ids file.
35 src_root_dir = os.path.abspath(os.path.join(os.path.dirname(filename),
36 first_ids_dict['SRCDIR']))
37
38 def ReplaceVariable(matchobj):
39 for key, value in defines.iteritems():
40 if matchobj.group(1) == key:
41 value = os.path.join(src_root_dir, value)
42 value = os.path.abspath(value)[len(src_root_dir) + 1:]
43 return value
44 return ''
45
46 renames = []
47 for grd_filename in first_ids_dict:
48 new_grd_filename = re.sub(r'<\(([A-Za-z_]+)\)', ReplaceVariable,
49 grd_filename)
50 if new_grd_filename != grd_filename:
51 new_grd_filename = new_grd_filename.replace('\\', '/')
52 renames.append((grd_filename, new_grd_filename))
53
54 for grd_filename, new_grd_filename in renames:
55 first_ids_dict[new_grd_filename] = first_ids_dict[grd_filename]
56 del(first_ids_dict[grd_filename])
57
58 return (src_root_dir, first_ids_dict)
59
60
61 class IfNode(base.Node):
62 '''A node for conditional inclusion of resources.
63 '''
64
65 def _IsValidChild(self, child):
66 from grit.node import empty
67 assert self.parent, '<if> node should never be root.'
68 if isinstance(self.parent, empty.IncludesNode):
69 from grit.node import include
70 return isinstance(child, include.IncludeNode)
71 elif isinstance(self.parent, empty.MessagesNode):
72 from grit.node import message
73 return isinstance(child, message.MessageNode)
74 elif isinstance(self.parent, empty.StructuresNode):
75 from grit.node import structure
76 return isinstance(child, structure.StructureNode)
77 elif isinstance(self.parent, empty.OutputsNode):
78 from grit.node import io
79 return isinstance(child, io.OutputNode)
80 elif isinstance(self.parent, empty.TranslationsNode):
81 from grit.node import io
82 return isinstance(child, io.FileNode)
83 else:
84 return False
85
86 def MandatoryAttributes(self):
87 return ['expr']
88
89 def IsConditionSatisfied(self):
90 '''Returns true if and only if the Python expression stored in attribute
91 'expr' evaluates to true.
92 '''
93 return self.EvaluateCondition(self.attrs['expr'])
94
95
96 class ReleaseNode(base.Node):
97 '''The <release> element.'''
98
99 def _IsValidChild(self, child):
100 from grit.node import empty
101 return isinstance(child, (empty.IncludesNode, empty.MessagesNode,
102 empty.StructuresNode, empty.IdentifiersNode))
103
104 def _IsValidAttribute(self, name, value):
105 return (
106 (name == 'seq' and int(value) <= self.GetRoot().GetCurrentRelease()) or
107 name == 'allow_pseudo'
108 )
109
110 def MandatoryAttributes(self):
111 return ['seq']
112
113 def DefaultAttributes(self):
114 return { 'allow_pseudo' : 'true' }
115
116 def GetReleaseNumber():
117 '''Returns the sequence number of this release.'''
118 return self.attribs['seq']
119
120 def ItemFormatter(self, t):
121 if t == 'data_package':
122 from grit.format import data_pack
123 return data_pack.DataPack()
124 else:
125 return super(type(self), self).ItemFormatter(t)
126
127 class GritNode(base.Node):
128 '''The <grit> root element.'''
129
130 def __init__(self):
131 base.Node.__init__(self)
132 self.output_language = ''
133 self.defines = {}
134
135 def _IsValidChild(self, child):
136 from grit.node import empty
137 return isinstance(child, (ReleaseNode, empty.TranslationsNode,
138 empty.OutputsNode))
139
140 def _IsValidAttribute(self, name, value):
141 if name not in ['base_dir', 'source_lang_id',
142 'latest_public_release', 'current_release',
143 'enc_check', 'tc_project']:
144 return False
145 if name in ['latest_public_release', 'current_release'] and value.strip(
146 '0123456789') != '':
147 return False
148 return True
149
150 def MandatoryAttributes(self):
151 return ['latest_public_release', 'current_release']
152
153 def DefaultAttributes(self):
154 return {
155 'base_dir' : '.',
156 'source_lang_id' : 'en',
157 'enc_check' : constants.ENCODING_CHECK,
158 'tc_project' : 'NEED_TO_SET_tc_project_ATTRIBUTE',
159 }
160
161 def EndParsing(self):
162 base.Node.EndParsing(self)
163 if (int(self.attrs['latest_public_release'])
164 > int(self.attrs['current_release'])):
165 raise exception.Parsing('latest_public_release cannot have a greater '
166 'value than current_release')
167
168 self.ValidateUniqueIds()
169
170 # Add the encoding check if it's not present (should ensure that it's always
171 # present in all .grd files generated by GRIT). If it's present, assert if
172 # it's not correct.
173 if 'enc_check' not in self.attrs or self.attrs['enc_check'] == '':
174 self.attrs['enc_check'] = constants.ENCODING_CHECK
175 else:
176 assert self.attrs['enc_check'] == constants.ENCODING_CHECK, (
177 'Are you sure your .grd file is in the correct encoding (UTF-8)?')
178
179 def ValidateUniqueIds(self):
180 '''Validate that 'name' attribute is unique in all nodes in this tree
181 except for nodes that are children of <if> nodes.
182 '''
183 unique_names = {}
184 duplicate_names = []
185 for node in self:
186 if isinstance(node, message.PhNode):
187 continue # PhNode objects have a 'name' attribute which is not an ID
188
189 node_ids = node.GetTextualIds()
190 if node_ids:
191 for node_id in node_ids:
192 if util.SYSTEM_IDENTIFIERS.match(node_id):
193 continue # predefined IDs are sometimes used more than once
194
195 # Don't complain about duplicate IDs if they occur in a node that is
196 # inside an <if> node.
197 if (node_id in unique_names and node_id not in duplicate_names and
198 (not node.parent or not isinstance(node.parent, IfNode))):
199 duplicate_names.append(node_id)
200 unique_names[node_id] = 1
201
202 if len(duplicate_names):
203 raise exception.DuplicateKey(', '.join(duplicate_names))
204
205
206 def GetCurrentRelease(self):
207 '''Returns the current release number.'''
208 return int(self.attrs['current_release'])
209
210 def GetLatestPublicRelease(self):
211 '''Returns the latest public release number.'''
212 return int(self.attrs['latest_public_release'])
213
214 def GetSourceLanguage(self):
215 '''Returns the language code of the source language.'''
216 return self.attrs['source_lang_id']
217
218 def GetTcProject(self):
219 '''Returns the name of this project in the TranslationConsole, or
220 'NEED_TO_SET_tc_project_ATTRIBUTE' if it is not defined.'''
221 return self.attrs['tc_project']
222
223 def SetOwnDir(self, dir):
224 '''Informs the 'grit' element of the directory the file it is in resides.
225 This allows it to calculate relative paths from the input file, which is
226 what we desire (rather than from the current path).
227
228 Args:
229 dir: r'c:\bla'
230
231 Return:
232 None
233 '''
234 assert dir
235 self.base_dir = os.path.normpath(os.path.join(dir, self.attrs['base_dir']))
236
237 def GetBaseDir(self):
238 '''Returns the base directory, relative to the working directory. To get
239 the base directory as set in the .grd file, use GetOriginalBaseDir()
240 '''
241 if hasattr(self, 'base_dir'):
242 return self.base_dir
243 else:
244 return self.GetOriginalBaseDir()
245
246 def GetOriginalBaseDir(self):
247 '''Returns the base directory, as set in the .grd file.
248 '''
249 return self.attrs['base_dir']
250
251 def _CollectOutputFiles(self, nodes, output_files):
252 '''Recursively filters the list of nodes that may contain other lists
253 in <if> nodes, and collects all the nodes that are not enclosed by
254 unsatisfied <if> conditionals and not <if> nodes themselves.
255
256 Args:
257 nodes: The list of nodes to filter.
258 output_files: The list of satisfying nodes.
259 '''
260 for node in nodes:
261 if node.name == 'if':
262 if node.IsConditionSatisfied():
263 self._CollectOutputFiles(node.children, output_files)
264 else:
265 output_files.append(node)
266
267 def GetOutputFiles(self):
268 '''Returns the list of <output> nodes that are descendants of this node's
269 <outputs> child and are not enclosed by unsatisfied <if> conditionals.
270 '''
271 for child in self.children:
272 if child.name == 'outputs':
273 output_files = []
274 self._CollectOutputFiles(child.children, output_files)
275 return output_files
276 raise exception.MissingElement()
277
278 def ItemFormatter(self, t):
279 if t == 'rc_header':
280 from grit.format import rc_header # import here to avoid circular dep
281 return rc_header.TopLevel()
282 elif t in ['rc_all', 'rc_translateable', 'rc_nontranslateable']:
283 from grit.format import rc # avoid circular dep
284 return rc.TopLevel()
285 elif t == 'resource_map_header':
286 from grit.format import resource_map
287 return resource_map.HeaderTopLevel()
288 elif t in ('resource_map_source', 'resource_file_map_source'):
289 from grit.format import resource_map
290 return resource_map.SourceTopLevel()
291 elif t == 'js_map_format':
292 from grit.format import js_map_format
293 return js_map_format.TopLevel()
294 elif t in ('adm', 'plist', 'plist_strings', 'admx', 'adml', 'doc', 'json',
295 'reg'):
296 from grit.format.policy_templates import template_formatter
297 return template_formatter.TemplateFormatter(t)
298 else:
299 return super(type(self), self).ItemFormatter(t)
300
301 def SetOutputContext(self, output_language, defines):
302 self.output_language = output_language
303 self.defines = defines
304
305 def SetDefines(self, defines):
306 self.defines = defines
307
308 def AssignFirstIds(self, filename_or_stream, first_id_filename, defines):
309 '''Assign first ids to each grouping node based on values from
310 tools/grit/resource_ids.'''
311 # If the input is a stream, then we're probably in a unit test and
312 # should skip this step.
313 if type(filename_or_stream) not in (str, unicode):
314 return
315
316 # TODO(joi@chromium.org): Get rid of this hack by making it
317 # possible to specify the resource_ids file to use as an attribute
318 # of the <grit> node in the .grd file, and doing so in all Chrome
319 # .grd files.
320 #
321 # For now, by default, we use the the file
322 # ../gritsettings/resource_ids relative to grit.py.
323 if not first_id_filename:
324 first_id_filename = os.path.join(
325 os.path.dirname(__file__),
326 '..', '..', '..',
327 'gritsettings', 'resource_ids')
328
329 first_ids = None
330 from grit.node import empty
331 for node in self.inorder():
332 if isinstance(node, empty.GroupingNode):
333 if not first_ids:
334 src_root_dir, first_ids = _ReadFirstIdsFromFile(first_id_filename,
335 defines)
336 filename = os.path.abspath(filename_or_stream)[
337 len(src_root_dir) + 1:]
338 filename = filename.replace('\\', '/')
339
340 # TODO(joi@chromium.org): Generalize this; users other than
341 # Chrome might want to use the first_id attribute; could check
342 # for first_ids == None to indicate not loaded, first_ids ==
343 # {} to indicate tried to load but found no resource_ids file.
344 if node.attrs['first_id'] != '':
345 raise Exception("Don't set the first_id attribute, update "
346 "%s instead." % first_id_filename)
347
348 try:
349 id_list = first_ids[filename][node.name]
350 except KeyError, e:
351 print '-' * 78
352 print 'Resource id not set for %s (%s)!' % (filename, node.name)
353 print ('Please update %s to include an entry for %s. See the '
354 'comments in resource_ids for information on why you need to '
355 'update that file.' % (first_id_filename, filename))
356 print '-' * 78
357 raise e
358
359 try:
360 node.attrs['first_id'] = str(id_list.pop(0))
361 except IndexError, e:
362 raise Exception('Please update %s and add a first id for %s (%s).'
363 % (first_id_filename, filename, node.name))
364
365
366 class IdentifierNode(base.Node):
367 '''A node for specifying identifiers that should appear in the resource
368 header file, and be unique amongst all other resource identifiers, but don't
369 have any other attributes or reference any resources.
370 '''
371
372 def MandatoryAttributes(self):
373 return ['name']
374
375 def DefaultAttributes(self):
376 return { 'comment' : '', 'id' : '' }
377
378 def ItemFormatter(self, t):
379 if t == 'rc_header':
380 return grit.format.rc_header.Item()
381
382 def GetId(self):
383 '''Returns the id of this identifier if it has one, None otherwise
384 '''
385 if 'id' in self.attrs:
386 return self.attrs['id']
387 return None
388
389 # static method
390 def Construct(parent, name, id, comment):
391 '''Creates a new node which is a child of 'parent', with attributes set
392 by parameters of the same name.
393 '''
394 node = IdentifierNode()
395 node.StartParsing('identifier', parent)
396 node.HandleAttribute('name', name)
397 node.HandleAttribute('id', id)
398 node.HandleAttribute('comment', comment)
399 node.EndParsing()
400 return node
401 Construct = staticmethod(Construct)
OLDNEW
« no previous file with comments | « grit/node/message_unittest.py ('k') | grit/node/misc_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698