/tools/grit/grit/node/structure.py
Python | 260 lines | 220 code | 20 blank | 20 comment | 1 complexity | 7407ec6bed89bcc9f91e1831340e1822 MD5 | raw file
1#!/usr/bin/python2.4 2# Copyright (c) 2006-2008 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'''The <structure> element. 7''' 8 9import os 10 11from grit.node import base 12from grit.node import variant 13 14from grit import constants 15from grit import exception 16from grit import util 17 18import grit.gather.rc 19import grit.gather.tr_html 20import grit.gather.admin_template 21import grit.gather.txt 22import grit.gather.muppet_strings 23 24import grit.format.rc 25import grit.format.rc_header 26 27# RTL languages 28# TODO(jennyz): remove this fixed set of RTL language array 29# when generic expand_variable code is added by grit team. 30_RTL_LANGS = [ 31 'ar', 32 'iw', 33 'ur', 34] 35 36# Type of the gatherer to use for each type attribute 37_GATHERERS = { 38 'accelerators' : grit.gather.rc.Accelerators, 39 'admin_template' : grit.gather.admin_template.AdmGatherer, 40 'dialog' : grit.gather.rc.Dialog, 41 'menu' : grit.gather.rc.Menu, 42 'muppet' : grit.gather.muppet_strings.MuppetStrings, 43 'rcdata' : grit.gather.rc.RCData, 44 'tr_html' : grit.gather.tr_html.TrHtml, 45 'txt' : grit.gather.txt.TxtFile, 46 'version' : grit.gather.rc.Version, 47} 48 49 50# Formatter instance to use for each type attribute 51# when formatting .rc files. 52_RC_FORMATTERS = { 53 'accelerators' : grit.format.rc.RcSection(), 54 'admin_template' : grit.format.rc.RcInclude('ADM'), 55 'dialog' : grit.format.rc.RcSection(), 56 'menu' : grit.format.rc.RcSection(), 57 'muppet' : grit.format.rc.RcInclude('XML'), 58 'rcdata' : grit.format.rc.RcSection(), 59 'tr_html' : grit.format.rc.RcInclude('HTML'), 60 'txt' : grit.format.rc.RcInclude('TXT'), 61 'version' : grit.format.rc.RcSection(), 62} 63 64 65# TODO(joi) Print a warning if the 'variant_of_revision' attribute indicates 66# that a skeleton variant is older than the original file. 67 68 69class StructureNode(base.Node): 70 '''A <structure> element.''' 71 72 def __init__(self): 73 base.Node.__init__(self) 74 self.gatherer = None 75 self.skeletons = {} # expressions to skeleton gatherers 76 77 def _IsValidChild(self, child): 78 return isinstance(child, variant.SkeletonNode) 79 80 def MandatoryAttributes(self): 81 return ['type', 'name', 'file'] 82 83 def DefaultAttributes(self): 84 return { 'encoding' : 'cp1252', 85 'exclude_from_rc' : 'false', 86 'line_end' : 'unix', 87 'output_encoding' : 'utf-8', 88 'generateid': 'true', 89 'expand_variables' : 'false', 90 'output_filename' : '', 91 # TODO(joi) this is a hack - should output all generated files 92 # as SCons dependencies; however, for now there is a bug I can't 93 # find where GRIT doesn't build the matching fileset, therefore 94 # this hack so that only the files you really need are marked as 95 # dependencies. 96 'sconsdep' : 'false', 97 } 98 99 def IsExcludedFromRc(self): 100 return self.attrs['exclude_from_rc'] == 'true' 101 102 def GetLineEnd(self): 103 '''Returns the end-of-line character or characters for files output because 104 of this node ('\r\n', '\n', or '\r' depending on the 'line_end' attribute). 105 ''' 106 if self.attrs['line_end'] == 'unix': 107 return '\n' 108 elif self.attrs['line_end'] == 'windows': 109 return '\r\n' 110 elif self.attrs['line_end'] == 'mac': 111 return '\r' 112 else: 113 raise exception.UnexpectedAttribute( 114 "Attribute 'line_end' must be one of 'linux' (default), 'windows' or 'mac'") 115 116 def GetCliques(self): 117 if self.gatherer: 118 return self.gatherer.GetCliques() 119 else: 120 return [] 121 122 def GetTextualIds(self): 123 if self.gatherer and self.attrs['type'] not in ['tr_html', 'admin_template', 'txt']: 124 return self.gatherer.GetTextualIds() 125 else: 126 return [self.attrs['name']] 127 128 def ItemFormatter(self, t): 129 if t == 'rc_header': 130 return grit.format.rc_header.Item() 131 elif (t in ['rc_all', 'rc_translateable', 'rc_nontranslateable'] and 132 self.SatisfiesOutputCondition()): 133 return _RC_FORMATTERS[self.attrs['type']] 134 else: 135 return super(type(self), self).ItemFormatter(t) 136 137 def RunGatherers(self, recursive=False, debug=False): 138 if self.gatherer: 139 return # idempotent 140 141 gathertype = _GATHERERS[self.attrs['type']] 142 143 if debug: 144 print 'Running gatherer %s for file %s' % (str(gathertype), self.FilenameToOpen()) 145 146 self.gatherer = gathertype.FromFile(self.FilenameToOpen(), 147 self.attrs['name'], 148 self.attrs['encoding']) 149 self.gatherer.SetUberClique(self.UberClique()) 150 self.gatherer.Parse() 151 152 for child in self.children: 153 assert isinstance(child, variant.SkeletonNode) 154 skel = gathertype.FromFile(child.FilenameToOpen(), 155 self.attrs['name'], 156 child.GetEncodingToUse()) 157 skel.SetUberClique(self.UberClique()) 158 skel.SetSkeleton(True) 159 skel.Parse() 160 self.skeletons[child.attrs['expr']] = skel 161 162 def GetSkeletonGatherer(self): 163 '''Returns the gatherer for the alternate skeleton that should be used, 164 based on the expressions for selecting skeletons, or None if the skeleton 165 from the English version of the structure should be used. 166 ''' 167 for expr in self.skeletons: 168 if self.EvaluateCondition(expr): 169 return self.skeletons[expr] 170 return None 171 172 def GetFilePath(self): 173 return self.ToRealPath(self.attrs['file']) 174 175 def HasFileForLanguage(self): 176 return self.attrs['type'] in ['tr_html', 'admin_template', 'txt', 'muppet'] 177 178 def FileForLanguage(self, lang, output_dir, create_file=True, 179 return_if_not_generated=True): 180 '''Returns the filename of the file associated with this structure, 181 for the specified language. 182 183 Args: 184 lang: 'fr' 185 output_dir: 'c:\temp' 186 create_file: True 187 ''' 188 assert self.HasFileForLanguage() 189 if (lang == self.GetRoot().GetSourceLanguage() and 190 self.attrs['expand_variables'] != 'true'): 191 if return_if_not_generated: 192 return self.GetFilePath() 193 else: 194 return None 195 else: 196 if self.attrs['output_filename'] != '': 197 filename = self.attrs['output_filename'] 198 else: 199 filename = os.path.basename(self.attrs['file']) 200 assert len(filename) 201 filename = '%s_%s' % (lang, filename) 202 filename = os.path.join(output_dir, filename) 203 204 if create_file: 205 text = self.gatherer.Translate( 206 lang, 207 pseudo_if_not_available=self.PseudoIsAllowed(), 208 fallback_to_english=self.ShouldFallbackToEnglish(), 209 skeleton_gatherer=self.GetSkeletonGatherer()) 210 211 file_object = util.WrapOutputStream(file(filename, 'wb'), 212 self._GetOutputEncoding()) 213 file_contents = util.FixLineEnd(text, self.GetLineEnd()) 214 if self.attrs['expand_variables'] == 'true': 215 file_contents = file_contents.replace('[GRITLANGCODE]', lang) 216 # TODO(jennyz): remove this hard coded logic for expanding 217 # [GRITDIR] variable for RTL languages when the generic 218 # expand_variable code is added by grit team. 219 if lang in _RTL_LANGS : 220 file_contents = file_contents.replace('[GRITDIR]', 'dir="RTL"') 221 else : 222 file_contents = file_contents.replace('[GRITDIR]', 'dir="LTR"') 223 if self._ShouldAddBom(): 224 file_object.write(constants.BOM) 225 file_object.write(file_contents) 226 file_object.close() 227 228 return filename 229 230 def _GetOutputEncoding(self): 231 '''Python doesn't natively support UTF encodings with a BOM signature, 232 so we add support by allowing you to append '-sig' to the encoding name. 233 This function returns the specified output encoding minus that part. 234 ''' 235 enc = self.attrs['output_encoding'] 236 if enc.endswith('-sig'): 237 return enc[0:len(enc) - len('-sig')] 238 else: 239 return enc 240 241 def _ShouldAddBom(self): 242 '''Returns true if output files should have the Unicode BOM prepended. 243 ''' 244 return self.attrs['output_encoding'].endswith('-sig') 245 246 # static method 247 def Construct(parent, name, type, file, encoding='cp1252'): 248 '''Creates a new node which is a child of 'parent', with attributes set 249 by parameters of the same name. 250 ''' 251 node = StructureNode() 252 node.StartParsing('structure', parent) 253 node.HandleAttribute('name', name) 254 node.HandleAttribute('type', type) 255 node.HandleAttribute('file', file) 256 node.HandleAttribute('encoding', encoding) 257 node.EndParsing() 258 return node 259 Construct = staticmethod(Construct) 260