| 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 '''Support for formatting an RC file for compilation. | 6 '''Support for formatting an RC file for compilation. |
| 7 ''' | 7 ''' |
| 8 | 8 |
| 9 import os | 9 import os |
| 10 import types | 10 import types |
| 11 import re | 11 import re |
| 12 | 12 |
| 13 from grit import lazy_re | 13 from grit import lazy_re |
| 14 from grit import util | 14 from grit import util |
| 15 from grit.format import interface | 15 from grit.format import interface |
| 16 | 16 |
| 17 # Matches all different types of linebreaks. | |
| 18 _LINEBREAKS = lazy_re.compile('\r\n|\n|\r') | |
| 19 | |
| 20 ''' | 17 ''' |
| 21 This dictionary defines the langauge charset pair lookup table, which is used | 18 This dictionary defines the langauge charset pair lookup table, which is used |
| 22 for replacing the GRIT expand variables for language info in Product Version | 19 for replacing the GRIT expand variables for language info in Product Version |
| 23 resource. The key is the language ISO country code, and the value | 20 resource. The key is the language ISO country code, and the value |
| 24 is the language and character-set pair, which is a hexadecimal string | 21 is the language and character-set pair, which is a hexadecimal string |
| 25 consisting of the concatenation of the language and character-set identifiers. | 22 consisting of the concatenation of the language and character-set identifiers. |
| 26 The first 4 digit of the value is the hex value of LCID, the remaining | 23 The first 4 digit of the value is the hex value of LCID, the remaining |
| 27 4 digits is the hex value of character-set id(code page)of the language. | 24 4 digits is the hex value of character-set id(code page)of the language. |
| 28 | 25 |
| 29 We have defined three GRIT expand_variables to be used in the version resource | 26 We have defined three GRIT expand_variables to be used in the version resource |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 | 177 |
| 181 def GetUnifiedLangCode(language) : | 178 def GetUnifiedLangCode(language) : |
| 182 r = re.compile('([a-z]{1,2})_([a-z]{1,2})') | 179 r = re.compile('([a-z]{1,2})_([a-z]{1,2})') |
| 183 if r.match(language) : | 180 if r.match(language) : |
| 184 underscore = language.find('_') | 181 underscore = language.find('_') |
| 185 return language[0:underscore] + '-' + language[underscore + 1:].upper() | 182 return language[0:underscore] + '-' + language[underscore + 1:].upper() |
| 186 else : | 183 else : |
| 187 return language | 184 return language |
| 188 | 185 |
| 189 | 186 |
| 190 def _MakeRelativePath(base_path, path_to_make_relative): | |
| 191 '''Returns a relative path such from the base_path to | |
| 192 the path_to_make_relative. | |
| 193 | |
| 194 In other words, os.join(base_path, | |
| 195 MakeRelativePath(base_path, path_to_make_relative)) | |
| 196 is the same location as path_to_make_relative. | |
| 197 | |
| 198 Args: | |
| 199 base_path: the root path | |
| 200 path_to_make_relative: an absolute path that is on the same drive | |
| 201 as base_path | |
| 202 ''' | |
| 203 | |
| 204 def _GetPathAfterPrefix(prefix_path, path_with_prefix): | |
| 205 '''Gets the subpath within in prefix_path for the path_with_prefix | |
| 206 with no beginning or trailing path separators. | |
| 207 | |
| 208 Args: | |
| 209 prefix_path: the base path | |
| 210 path_with_prefix: a path that starts with prefix_path | |
| 211 ''' | |
| 212 assert path_with_prefix.startswith(prefix_path) | |
| 213 path_without_prefix = path_with_prefix[len(prefix_path):] | |
| 214 normalized_path = os.path.normpath(path_without_prefix.strip(os.path.sep)) | |
| 215 if normalized_path == '.': | |
| 216 normalized_path = '' | |
| 217 return normalized_path | |
| 218 | |
| 219 def _GetCommonBaseDirectory(*args): | |
| 220 '''Returns the common prefix directory for the given paths | |
| 221 | |
| 222 Args: | |
| 223 The list of paths (at least one of which should be a directory) | |
| 224 ''' | |
| 225 prefix = os.path.commonprefix(args) | |
| 226 # prefix is a character-by-character prefix (i.e. it does not end | |
| 227 # on a directory bound, so this code fixes that) | |
| 228 | |
| 229 # if the prefix ends with the separator, then it is prefect. | |
| 230 if len(prefix) > 0 and prefix[-1] == os.path.sep: | |
| 231 return prefix | |
| 232 | |
| 233 # We need to loop through all paths or else we can get | |
| 234 # tripped up by "c:\a" and "c:\abc". The common prefix | |
| 235 # is "c:\a" which is a directory and looks good with | |
| 236 # respect to the first directory but it is clear that | |
| 237 # isn't a common directory when the second path is | |
| 238 # examined. | |
| 239 for path in args: | |
| 240 assert len(path) >= len(prefix) | |
| 241 # If the prefix the same length as the path, | |
| 242 # then the prefix must be a directory (since one | |
| 243 # of the arguements should be a directory). | |
| 244 if path == prefix: | |
| 245 continue | |
| 246 # if the character after the prefix in the path | |
| 247 # is the separator, then the prefix appears to be a | |
| 248 # valid a directory as well for the given path | |
| 249 if path[len(prefix)] == os.path.sep: | |
| 250 continue | |
| 251 # Otherwise, the prefix is not a directory, so it needs | |
| 252 # to be shortened to be one | |
| 253 index_sep = prefix.rfind(os.path.sep) | |
| 254 # The use "index_sep + 1" because it includes the final sep | |
| 255 # and it handles the case when the index_sep is -1 as well | |
| 256 prefix = prefix[:index_sep + 1] | |
| 257 # At this point we backed up to a directory bound which is | |
| 258 # common to all paths, so we can quit going through all of | |
| 259 # the paths. | |
| 260 break | |
| 261 return prefix | |
| 262 | |
| 263 prefix = _GetCommonBaseDirectory(base_path, path_to_make_relative) | |
| 264 # If the paths had no commonality at all, then return the absolute path | |
| 265 # because it is the best that can be done. If the path had to be relative | |
| 266 # then eventually this absolute path will be discovered (when a build breaks) | |
| 267 # and an appropriate fix can be made, but having this allows for the best | |
| 268 # backward compatibility with the absolute path behavior in the past. | |
| 269 if len(prefix) <= 0: | |
| 270 return path_to_make_relative | |
| 271 # Build a path from the base dir to the common prefix | |
| 272 remaining_base_path = _GetPathAfterPrefix(prefix, base_path) | |
| 273 | |
| 274 # The follow handles two case: "" and "foo\\bar" | |
| 275 path_pieces = remaining_base_path.split(os.path.sep) | |
| 276 base_depth_from_prefix = len([d for d in path_pieces if len(d)]) | |
| 277 base_to_prefix = (".." + os.path.sep) * base_depth_from_prefix | |
| 278 | |
| 279 # Put add in the path from the prefix to the path_to_make_relative | |
| 280 remaining_other_path = _GetPathAfterPrefix(prefix, path_to_make_relative) | |
| 281 return base_to_prefix + remaining_other_path | |
| 282 | |
| 283 | |
| 284 class TopLevel(interface.ItemFormatter): | 187 class TopLevel(interface.ItemFormatter): |
| 285 '''Writes out the required preamble for RC files.''' | 188 '''Writes out the required preamble for RC files.''' |
| 286 def Format(self, item, lang='en', begin_item=True, output_dir='.'): | 189 def Format(self, item, lang='en', begin_item=True, output_dir='.'): |
| 287 assert isinstance(lang, types.StringTypes) | 190 assert isinstance(lang, types.StringTypes) |
| 288 if not begin_item: | 191 if not begin_item: |
| 289 return '' | 192 return '' |
| 290 else: | 193 else: |
| 291 # Find the location of the resource header file, so that we can include | 194 # Find the location of the resource header file, so that we can include |
| 292 # it. | 195 # it. |
| 293 resource_header = 'resource.h' # fall back to this | 196 resource_header = 'resource.h' # fall back to this |
| 294 language_directive = '' | 197 language_directive = '' |
| 295 for output in item.GetRoot().GetOutputFiles(): | 198 for output in item.GetRoot().GetOutputFiles(): |
| 296 if output.attrs['type'] == 'rc_header': | 199 if output.attrs['type'] == 'rc_header': |
| 297 resource_header = os.path.abspath(output.GetOutputFilename()) | 200 resource_header = os.path.abspath(output.GetOutputFilename()) |
| 298 resource_header = _MakeRelativePath(output_dir, resource_header) | 201 resource_header = util.MakeRelativePath(output_dir, resource_header) |
| 299 if output.attrs['lang'] != lang: | 202 if output.attrs['lang'] != lang: |
| 300 continue | 203 continue |
| 301 if output.attrs['language_section'] == '': | 204 if output.attrs['language_section'] == '': |
| 302 # If no language_section is requested, no directive is added | 205 # If no language_section is requested, no directive is added |
| 303 # (Used when the generated rc will be included from another rc | 206 # (Used when the generated rc will be included from another rc |
| 304 # file that will have the appropriate language directive) | 207 # file that will have the appropriate language directive) |
| 305 language_directive = '' | 208 language_directive = '' |
| 306 elif output.attrs['language_section'] == 'neutral': | 209 elif output.attrs['language_section'] == 'neutral': |
| 307 # If a neutral language section is requested (default), add a | 210 # If a neutral language section is requested (default), add a |
| 308 # neutral language directive | 211 # neutral language directive |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 349 if not begin_item: | 252 if not begin_item: |
| 350 return '' | 253 return '' |
| 351 | 254 |
| 352 assert isinstance(lang, types.StringTypes) | 255 assert isinstance(lang, types.StringTypes) |
| 353 assert isinstance(item, message.MessageNode) | 256 assert isinstance(item, message.MessageNode) |
| 354 | 257 |
| 355 message = item.ws_at_start + item.Translate(lang) + item.ws_at_end | 258 message = item.ws_at_start + item.Translate(lang) + item.ws_at_end |
| 356 # Escape quotation marks (RC format uses doubling-up | 259 # Escape quotation marks (RC format uses doubling-up |
| 357 message = message.replace('"', '""') | 260 message = message.replace('"', '""') |
| 358 # Replace linebreaks with a \n escape | 261 # Replace linebreaks with a \n escape |
| 359 message = _LINEBREAKS.sub(r'\\n', message) | 262 message = util.LINEBREAKS.sub(r'\\n', message) |
| 360 | 263 |
| 361 name_attr = item.GetTextualIds()[0] | 264 name_attr = item.GetTextualIds()[0] |
| 362 | 265 |
| 363 return ' %-15s "%s"\n' % (name_attr, message) | 266 return ' %-15s "%s"\n' % (name_attr, message) |
| 364 | 267 |
| 365 | 268 |
| 366 class RcSection(interface.ItemFormatter): | 269 class RcSection(interface.ItemFormatter): |
| 367 '''Writes out an .rc file section.''' | 270 '''Writes out an .rc file section.''' |
| 368 | 271 |
| 369 def Format(self, item, lang='en', begin_item=True, output_dir='.'): | 272 def Format(self, item, lang='en', begin_item=True, output_dir='.'): |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 # sharing the resulting .rc files is possible. | 331 # sharing the resulting .rc files is possible. |
| 429 # | 332 # |
| 430 # The FileForLanguage() Function has the side effect of generating the file | 333 # The FileForLanguage() Function has the side effect of generating the file |
| 431 # if needed (e.g. if it is an HTML file include). | 334 # if needed (e.g. if it is an HTML file include). |
| 432 filename = os.path.abspath(item.FileForLanguage(lang, output_dir)) | 335 filename = os.path.abspath(item.FileForLanguage(lang, output_dir)) |
| 433 if self.flatten_html: | 336 if self.flatten_html: |
| 434 filename = item.Flatten(output_dir) | 337 filename = item.Flatten(output_dir) |
| 435 elif self.filenameWithoutPath: | 338 elif self.filenameWithoutPath: |
| 436 filename = os.path.basename(filename) | 339 filename = os.path.basename(filename) |
| 437 elif self.relative_path_: | 340 elif self.relative_path_: |
| 438 filename = _MakeRelativePath(output_dir, filename) | 341 filename = util.MakeRelativePath(output_dir, filename) |
| 439 | 342 |
| 440 filename = filename.replace('\\', '\\\\') # escape for the RC format | 343 filename = filename.replace('\\', '\\\\') # escape for the RC format |
| 441 | 344 |
| 442 if isinstance(item, structure.StructureNode) and item.IsExcludedFromRc(): | 345 if isinstance(item, structure.StructureNode) and item.IsExcludedFromRc(): |
| 443 return '' | 346 return '' |
| 444 else: | 347 else: |
| 445 return '%-18s %-18s "%s"\n' % (item.attrs['name'], self.type_, filename) | 348 return '%-18s %-18s "%s"\n' % (item.attrs['name'], self.type_, filename) |
| 446 | 349 |
| OLD | NEW |