1 #!/usr/bin/env python 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 4 # found in the LICENSE file. 5 6 """Handling of the <include> element. 7 """ 8 9 import os 10 11 import grit.format.html_inline 12 import grit.format.rc_header 13 import grit.format.rc 14 15 from grit.node import base 16 from grit import util 17 18 class IncludeNode(base.Node): 19 """An <include> element.""" 20 def __init__(self): 21 super(IncludeNode, self).__init__() 22 23 # Cache flattened data so that we don't flatten the same file 24 # multiple times. 25 self._flattened_data = None 26 # Also keep track of the last filename we flattened to, so we can 27 # avoid doing it more than once. 28 self._last_flat_filename = None 29 30 def _IsValidChild(self, child): 31 return False 32 33 def _GetFlattenedData(self, allow_external_script=False): 34 if not self._flattened_data: 35 filename = self.ToRealPath(self.GetInputPath()) 36 self._flattened_data = ( 37 grit.format.html_inline.InlineToString(filename, self, 38 allow_external_script=allow_external_script)) 39 return self._flattened_data 40 41 def MandatoryAttributes(self): 42 return ['name', 'type', 'file'] 43 44 def DefaultAttributes(self): 45 return {'translateable' : 'true', 46 'generateid': 'true', 47 'filenameonly': 'false', 48 'mkoutput': 'false', 49 'flattenhtml': 'false', 50 'allowexternalscript': 'false', 51 'relativepath': 'false', 52 'use_base_dir': 'true', 53 } 54 55 def GetInputPath(self): 56 # Do not mess with absolute paths, that would make them invalid. 57 if os.path.isabs(os.path.expandvars(self.attrs['file'])): 58 return self.attrs['file'] 59 60 # We have no control over code that calles ToRealPath later, so convert 61 # the path to be relative against our basedir. 62 if self.attrs.get('use_base_dir', 'true') != 'true': 63 return os.path.relpath(self.attrs['file'], self.GetRoot().GetBaseDir()) 64 65 return self.attrs['file'] 66 67 def FileForLanguage(self, lang, output_dir): 68 """Returns the file for the specified language. This allows us to return 69 different files for different language variants of the include file. 70 """ 71 return self.ToRealPath(self.GetInputPath()) 72 73 def GetDataPackPair(self, lang, encoding): 74 """Returns a (id, string) pair that represents the resource id and raw 75 bytes of the data. This is used to generate the data pack data file. 76 """ 77 # TODO(benrg/joi): Move this and other implementations of GetDataPackPair 78 # to grit.format.data_pack? 79 from grit.format import rc_header 80 id_map = rc_header.GetIds(self.GetRoot()) 81 id = id_map[self.GetTextualIds()[0]] 82 if self.attrs['flattenhtml'] == 'true': 83 allow_external_script = self.attrs['allowexternalscript'] == 'true' 84 data = self._GetFlattenedData(allow_external_script=allow_external_script) 85 else: 86 filename = self.ToRealPath(self.GetInputPath()) 87 data = util.ReadFile(filename, util.BINARY) 88 89 # Include does not care about the encoding, because it only returns binary 90 # data. 91 return id, data 92 93 def Process(self, output_dir): 94 """Rewrite file references to be base64 encoded data URLs. The new file 95 will be written to output_dir and the name of the new file is returned.""" 96 filename = self.ToRealPath(self.GetInputPath()) 97 flat_filename = os.path.join(output_dir, 98 self.attrs['name'] + '_' + os.path.basename(filename)) 99 100 if self._last_flat_filename == flat_filename: 101 return 102 103 with open(flat_filename, 'wb') as outfile: 104 outfile.write(self._GetFlattenedData()) 105 106 self._last_flat_filename = flat_filename 107 return os.path.basename(flat_filename) 108 109 def GetHtmlResourceFilenames(self): 110 """Returns a set of all filenames inlined by this file.""" 111 allow_external_script = self.attrs['allowexternalscript'] == 'true' 112 return grit.format.html_inline.GetResourceFilenames( 113 self.ToRealPath(self.GetInputPath()), 114 allow_external_script=allow_external_script) 115 116 def IsResourceMapSource(self): 117 return True 118 119 def GeneratesResourceMapEntry(self, output_all_resource_defines, 120 is_active_descendant): 121 # includes always generate resource entries. 122 if output_all_resource_defines: 123 return True 124 return is_active_descendant 125 126 @staticmethod 127 def Construct(parent, name, type, file, translateable=True, 128 filenameonly=False, mkoutput=False, relativepath=False): 129 """Creates a new node which is a child of 'parent', with attributes set 130 by parameters of the same name. 131 """ 132 # Convert types to appropriate strings 133 translateable = util.BoolToString(translateable) 134 filenameonly = util.BoolToString(filenameonly) 135 mkoutput = util.BoolToString(mkoutput) 136 relativepath = util.BoolToString(relativepath) 137 138 node = IncludeNode() 139 node.StartParsing('include', parent) 140 node.HandleAttribute('name', name) 141 node.HandleAttribute('type', type) 142 node.HandleAttribute('file', file) 143 node.HandleAttribute('translateable', translateable) 144 node.HandleAttribute('filenameonly', filenameonly) 145 node.HandleAttribute('mkoutput', mkoutput) 146 node.HandleAttribute('relativepath', relativepath) 147 node.EndParsing() 148 return node 149