diff options
author | joaodasilva@chromium.org <joaodasilva@chromium.org@7262f16d-afe8-6277-6482-052fa10e57b1> | 2013-06-10 08:22:38 +0000 |
---|---|---|
committer | joaodasilva@chromium.org <joaodasilva@chromium.org@7262f16d-afe8-6277-6482-052fa10e57b1> | 2013-06-10 08:22:38 +0000 |
commit | 006588227ffb5ff646051dcb4f04198edcf038c9 (patch) | |
tree | cb20009486d620e3712582edc5279d55f27d9f30 | |
parent | abf31db73d7f62930be9d3d9b7f5b2b360378821 (diff) | |
download | grit-006588227ffb5ff646051dcb4f04198edcf038c9.tar.gz |
GRIT: Enable variable expansion in filenames during HTML inlining.
BUG=232048
R=flackr@chromium.org
Review URL: https://codereview.chromium.org/16539002
git-svn-id: http://grit-i18n.googlecode.com/svn/trunk@125 7262f16d-afe8-6277-6482-052fa10e57b1
-rwxr-xr-x | grit/format/html_inline.py | 55 | ||||
-rwxr-xr-x | grit/format/html_inline_unittest.py | 60 | ||||
-rw-r--r-- | grit/gather/chrome_html.py | 60 | ||||
-rw-r--r-- | grit/gather/chrome_html_unittest.py | 57 | ||||
-rw-r--r-- | grit/gather/interface.py | 4 | ||||
-rw-r--r-- | grit/node/structure.py | 6 | ||||
-rw-r--r-- | grit/node/structure_unittest.py | 11 | ||||
-rw-r--r-- | grit/testdata/structure_variables.html | 1 |
8 files changed, 216 insertions, 38 deletions
diff --git a/grit/format/html_inline.py b/grit/format/html_inline.py index 569c282..b5e0b0f 100755 --- a/grit/format/html_inline.py +++ b/grit/format/html_inline.py @@ -72,7 +72,8 @@ def GetDistribution(): def SrcInlineAsDataURL( - src_match, base_path, distribution, inlined_files, names_only=False): + src_match, base_path, distribution, inlined_files, names_only=False, + filename_expansion_function=None): """regex replace function. Takes a regex match for src="filename", attempts to read the file @@ -93,6 +94,8 @@ def SrcInlineAsDataURL( string """ filename = src_match.group('filename') + if filename_expansion_function: + filename = filename_expansion_function(filename) quote = src_match.group('quote') if filename.find(':') != -1: @@ -126,7 +129,7 @@ class InlinedData: def DoInline( input_filename, grd_node, allow_external_script=False, names_only=False, - rewrite_function=None): + rewrite_function=None, filename_expansion_function=None): """Helper function that inlines the resources in a specified file. Reads input_filename, finds all the src attributes and attempts to @@ -139,10 +142,14 @@ def DoInline( names_only: |nil| will be returned for the inlined contents (faster). rewrite_function: function(filepath, text, distribution) which will be called to rewrite html content before inlining images. + filename_expansion_function: function(filename) which will be called to + rewrite filenames before attempting to read them. Returns: a tuple of the inlined data as a string and the set of filenames of all the inlined files """ + if filename_expansion_function: + input_filename = filename_expansion_function(input_filename) input_filepath = os.path.dirname(input_filename) distribution = GetDistribution() @@ -153,7 +160,8 @@ def DoInline( inlined_files=inlined_files): """Helper function to provide SrcInlineAsDataURL with the base file path""" return SrcInlineAsDataURL( - src_match, filepath, distribution, inlined_files, names_only=names_only) + src_match, filepath, distribution, inlined_files, names_only=names_only, + filename_expansion_function=filename_expansion_function) def GetFilepath(src_match, base_path = input_filepath): filename = src_match.group('filename') @@ -163,6 +171,8 @@ def DoInline( return None filename = filename.replace('%DISTRIBUTION%', distribution) + if filename_expansion_function: + filename = filename_expansion_function(filename) return os.path.normpath(os.path.join(base_path, filename)) def IsConditionSatisfied(src_match): @@ -214,12 +224,16 @@ def DoInline( inlined_files.add(filepath) if names_only: - inlined_files.update(GetResourceFilenames(filepath, - allow_external_script, - rewrite_function)) + inlined_files.update(GetResourceFilenames( + filepath, + allow_external_script, + rewrite_function, + filename_expansion_function=filename_expansion_function)) return "" - return pattern % InlineToString(filepath, grd_node, allow_external_script) + return pattern % InlineToString( + filepath, grd_node, allow_external_script, + filename_expansion_function=filename_expansion_function) def InlineIncludeFiles(src_match): """Helper function to directly inline generic external files (without @@ -338,7 +352,7 @@ def DoInline( def InlineToString(input_filename, grd_node, allow_external_script=False, - rewrite_function=None): + rewrite_function=None, filename_expansion_function=None): """Inlines the resources in a specified file and returns it as a string. Args: @@ -348,10 +362,12 @@ def InlineToString(input_filename, grd_node, allow_external_script=False, the inlined data as a string """ try: - return DoInline(input_filename, - grd_node, - allow_external_script=allow_external_script, - rewrite_function=rewrite_function).inlined_data + return DoInline( + input_filename, + grd_node, + allow_external_script=allow_external_script, + rewrite_function=rewrite_function, + filename_expansion_function=filename_expansion_function).inlined_data except IOError, e: raise Exception("Failed to open %s while trying to flatten %s. (%s)" % (e.filename, input_filename, e.strerror)) @@ -378,14 +394,17 @@ def InlineToFile(input_filename, output_filename, grd_node): def GetResourceFilenames(filename, allow_external_script=False, - rewrite_function=None): + rewrite_function=None, + filename_expansion_function=None): """For a grd file, returns a set of all the files that would be inline.""" try: - return DoInline(filename, - None, - names_only=True, - allow_external_script=allow_external_script, - rewrite_function=rewrite_function).inlined_files + return DoInline( + filename, + None, + names_only=True, + allow_external_script=allow_external_script, + rewrite_function=rewrite_function, + filename_expansion_function=filename_expansion_function).inlined_files except IOError, e: raise Exception("Failed to open %s while trying to flatten %s. (%s)" % (e.filename, filename, e.strerror)) diff --git a/grit/format/html_inline_unittest.py b/grit/format/html_inline_unittest.py index 7d546a5..45840f2 100755 --- a/grit/format/html_inline_unittest.py +++ b/grit/format/html_inline_unittest.py @@ -202,6 +202,66 @@ class HtmlInlineUnittest(unittest.TestCase): self.failUnlessEqual(expected_inlined, util.FixLineEnd(result.inlined_data, '\n')) + def testFilenameVariableExpansion(self): + '''Tests that variables are expanded in filenames before inlining.''' + + files = { + 'index.html': ''' + <html> + <head> + <link rel="stylesheet" href="style[WHICH].css"> + <script src="script[WHICH].js"></script> + </head> + <include src="tmpl[WHICH].html"> + <img src="img[WHICH].png"> + </html> + ''', + 'style1.css': '''h1 {}''', + 'tmpl1.html': '''<h1></h1>''', + 'script1.js': '''console.log('hello');''', + 'img1.png': '''abc''', + } + + expected_inlined = ''' + <html> + <head> + <style>h1 {}</style> + <script>console.log('hello');</script> + </head> + <h1></h1> + <img src="data:image/png;base64,YWJj"> + </html> + ''' + + source_resources = set() + tmp_dir = util.TempDir(files) + for filename in files: + source_resources.add(tmp_dir.GetPath(filename)) + + def replacer(var, repl): + return lambda filename: filename.replace('[%s]' % var, repl) + + # Test normal inlining. + result = html_inline.DoInline( + tmp_dir.GetPath('index.html'), + None, + filename_expansion_function=replacer('WHICH', '1')) + resources = result.inlined_files + resources.add(tmp_dir.GetPath('index.html')) + self.failUnlessEqual(resources, source_resources) + self.failUnlessEqual(expected_inlined, + util.FixLineEnd(result.inlined_data, '\n')) + + # Test names-only inlining. + result = html_inline.DoInline( + tmp_dir.GetPath('index.html'), + None, + names_only=True, + filename_expansion_function=replacer('WHICH', '1')) + resources = result.inlined_files + resources.add(tmp_dir.GetPath('index.html')) + self.failUnlessEqual(resources, source_resources) + if __name__ == '__main__': unittest.main() diff --git a/grit/gather/chrome_html.py b/grit/gather/chrome_html.py index d5a2b07..d554776 100644 --- a/grit/gather/chrome_html.py +++ b/grit/gather/chrome_html.py @@ -48,7 +48,8 @@ _HTML_IMAGE_SRC = lazy_re.compile( '<img[^>]+src=\"(?P<filename>[^">]*)\"[^>]*>') def GetImageList( - base_path, filename, scale_factors, distribution): + base_path, filename, scale_factors, distribution, + filename_expansion_function=None): """Generate the list of images which match the provided scale factors. Takes an image filename and checks for files of the same name in folders @@ -79,6 +80,8 @@ def GetImageList( return [('1x', filename)] filename = filename.replace(DIST_SUBSTR, distribution) + if filename_expansion_function: + filename = filename_expansion_function(filename) filepath = os.path.join(base_path, filename) images = [('1x', filename)] @@ -114,7 +117,8 @@ def GenerateImageSet(images, quote): def InsertImageSet( - src_match, base_path, scale_factors, distribution): + src_match, base_path, scale_factors, distribution, + filename_expansion_function=None): """Regex replace function which inserts -webkit-image-set. Takes a regex match for url('path'). If the file is local, checks for @@ -136,7 +140,9 @@ def InsertImageSet( quote = src_match.group('quote') filename = src_match.group('filename') attr = src_match.group('attribute') - image_list = GetImageList(base_path, filename, scale_factors, distribution) + image_list = GetImageList( + base_path, filename, scale_factors, distribution, + filename_expansion_function=filename_expansion_function) # Don't modify the source if there is only one image. if len(image_list) == 1: @@ -146,14 +152,17 @@ def InsertImageSet( def InsertImageStyle( - src_match, base_path, scale_factors, distribution): + src_match, base_path, scale_factors, distribution, + filename_expansion_function=None): """Regex replace function which adds a content style to an <img>. Takes a regex match from _HTML_IMAGE_SRC and replaces the attribute with a CSS style which defines the image set. """ filename = src_match.group('filename') - image_list = GetImageList(base_path, filename, scale_factors, distribution) + image_list = GetImageList( + base_path, filename, scale_factors, distribution, + filename_expansion_function=filename_expansion_function) # Don't modify the source if there is only one image or image already defines # a style. @@ -165,16 +174,21 @@ def InsertImageStyle( def InsertImageSets( - filepath, text, scale_factors, distribution): + filepath, text, scale_factors, distribution, + filename_expansion_function=None): """Helper function that adds references to external images available in any of scale_factors in CSS backgrounds. """ # Add high DPI urls for css attributes: content, background, # or *-image or <img src="foo">. return _CSS_IMAGE_URLS.sub( - lambda m: InsertImageSet(m, filepath, scale_factors, distribution), + lambda m: InsertImageSet( + m, filepath, scale_factors, distribution, + filename_expansion_function=filename_expansion_function), _HTML_IMAGE_SRC.sub( - lambda m: InsertImageStyle(m, filepath, scale_factors, distribution), + lambda m: InsertImageStyle( + m, filepath, scale_factors, distribution, + filename_expansion_function=filename_expansion_function), text)).decode('utf-8').encode('utf-8') @@ -208,17 +222,20 @@ def RemoveImageSetImages(text, scale_factors): def ProcessImageSets( - filepath, text, scale_factors, distribution): + filepath, text, scale_factors, distribution, + filename_expansion_function=None): """Helper function that adds references to external images available in other scale_factors and removes images from image-sets in unsupported scale_factors. """ # Explicitly add 1x to supported scale factors so that it is not removed. supported_scale_factors = ['1x'] supported_scale_factors.extend(scale_factors) - return InsertImageSets(filepath, - RemoveImageSetImages(text, supported_scale_factors), - scale_factors, - distribution) + return InsertImageSets( + filepath, + RemoveImageSetImages(text, supported_scale_factors), + scale_factors, + distribution, + filename_expansion_function=filename_expansion_function) class ChromeHtml(interface.GathererBase): @@ -238,6 +255,7 @@ class ChromeHtml(interface.GathererBase): # 1x resources are implicitly already in the source and do not need to be # added. self.scale_factors_ = [] + self.filename_expansion_function = None def SetAttributes(self, attrs): self.allow_external_script_ = ('allowexternalscript' in attrs and @@ -267,7 +285,9 @@ class ChromeHtml(interface.GathererBase): self.grd_node.ToRealPath(self.GetInputPath()), allow_external_script=self.allow_external_script_, rewrite_function=lambda fp, t, d: ProcessImageSets( - fp, t, self.scale_factors_, d)) + fp, t, self.scale_factors_, d, + filename_expansion_function=self.filename_expansion_function), + filename_expansion_function=self.filename_expansion_function) return [] def Translate(self, lang, pseudo_if_not_available=True, @@ -275,10 +295,15 @@ class ChromeHtml(interface.GathererBase): """Returns this document translated.""" return self.inlined_text_ + def SetFilenameExpansionFunction(self, fn): + self.filename_expansion_function = fn + def Parse(self): """Parses and inlines the represented file.""" filename = self.GetInputPath() + if self.filename_expansion_function: + filename = self.filename_expansion_function(filename) # Hack: some unit tests supply an absolute path and no root node. if not os.path.isabs(filename): filename = self.grd_node.ToRealPath(filename) @@ -288,11 +313,14 @@ class ChromeHtml(interface.GathererBase): self.grd_node, allow_external_script = self.allow_external_script_, rewrite_function=lambda fp, t, d: ProcessImageSets( - fp, t, self.scale_factors_, d)) + fp, t, self.scale_factors_, d, + filename_expansion_function=self.filename_expansion_function), + filename_expansion_function=self.filename_expansion_function) else: distribution = html_inline.GetDistribution() self.inlined_text_ = ProcessImageSets( os.path.dirname(filename), util.ReadFile(filename, 'utf-8'), self.scale_factors_, - distribution) + distribution, + filename_expansion_function=self.filename_expansion_function) diff --git a/grit/gather/chrome_html_unittest.py b/grit/gather/chrome_html_unittest.py index 7d0b702..8f636ff 100644 --- a/grit/gather/chrome_html_unittest.py +++ b/grit/gather/chrome_html_unittest.py @@ -345,5 +345,62 @@ class ChromeHtmlUnittest(unittest.TestCase): ''')) tmp_dir.CleanUp() + def testExpandVariablesInFilename(self): + ''' + Tests variable substitution in filenames while flattening images + with multiple scale factors. + ''' + + tmp_dir = util.TempDir({ + 'index.html': ''' + <!DOCTYPE HTML> + <html> + <head> + <link rel="stylesheet" href="test.css"> + </head> + <body> + <!-- Don't need a body. --> + </body> + </html> + ''', + + 'test.css': ''' + .image { + background: url('test[WHICH].png'); + } + ''', + + 'test1.png': 'PNG DATA', + '1.4x/test1.png': '1.4x PNG DATA', + '1.8x/test1.png': '1.8x PNG DATA', + }) + + def replacer(var, repl): + return lambda filename: filename.replace('[%s]' % var, repl) + + html = chrome_html.ChromeHtml(tmp_dir.GetPath('index.html')) + html.SetDefines({'scale_factors': '1.4x,1.8x'}) + html.SetAttributes({'flattenhtml': 'true'}) + html.SetFilenameExpansionFunction(replacer('WHICH', '1')); + html.Parse() + self.failUnlessEqual(StandardizeHtml(html.GetData('en', 'utf-8')), + StandardizeHtml(''' + <!DOCTYPE HTML> + <html> + <head> + <style> + .image { + background: -webkit-image-set(url('data:image/png;base64,UE5HIERBVEE=') 1x, url('data:image/png;base64,MS40eCBQTkcgREFUQQ==') 1.4x, url('data:image/png;base64,MS44eCBQTkcgREFUQQ==') 1.8x); + } + </style> + </head> + <body> + <!-- Don't need a body. --> + </body> + </html> + ''')) + tmp_dir.CleanUp() + + if __name__ == '__main__': unittest.main() diff --git a/grit/gather/interface.py b/grit/gather/interface.py index 084392a..c277d37 100644 --- a/grit/gather/interface.py +++ b/grit/gather/interface.py @@ -152,6 +152,10 @@ class GathererBase(object): ''' pass + def SetFilenameExpansionFunction(self, fn): + '''Sets a function for rewriting filenames before gathering.''' + pass + # TODO(benrg): Move this elsewhere, since it isn't part of the interface. def _LoadInputFile(self): '''A convenience function for subclasses that loads the contents of the diff --git a/grit/node/structure.py b/grit/node/structure.py index 99f2014..48968f6 100644 --- a/grit/node/structure.py +++ b/grit/node/structure.py @@ -93,6 +93,8 @@ class StructureNode(base.Node): if hasattr(self.GetRoot(), 'defines'): self.gatherer.SetDefines(self.GetRoot().defines) self.gatherer.SetAttributes(self.attrs) + if self.ExpandVariables(): + self.gatherer.SetFilenameExpansionFunction(self._Substitute) # Parse local variables and instantiate the substituter. if self.attrs['variables']: @@ -109,6 +111,10 @@ class StructureNode(base.Node): is_skeleton=True) skel.SetGrdNode(self) # TODO(benrg): Or child? Only used for ToRealPath skel.SetUberClique(self.UberClique()) + if hasattr(self.GetRoot(), 'defines'): + skel.SetDefines(self.GetRoot().defines) + if self.ExpandVariables(): + skel.SetFilenameExpansionFunction(self._Substitute) self.skeletons[child.attrs['expr']] = skel def MandatoryAttributes(self): diff --git a/grit/node/structure_unittest.py b/grit/node/structure_unittest.py index c07c2bc..a039bce 100644 --- a/grit/node/structure_unittest.py +++ b/grit/node/structure_unittest.py @@ -49,7 +49,7 @@ class StructureUnittest(unittest.TestCase): def testVariables(self): grd = util.ParseGrdForUnittest(''' <structures> - <structure type="chrome_html" name="hello_tmpl" file="structure_variables.html" expand_variables="true" variables="GREETING=Hello,THINGS=foo,, bar,, baz,EQUATION=2+2==4"></structure> + <structure type="chrome_html" name="hello_tmpl" file="structure_variables.html" expand_variables="true" variables="GREETING=Hello,THINGS=foo,, bar,, baz,EQUATION=2+2==4,filename=simple" flattenhtml="true"></structure> </structures>''', base_dir=util.PathFromRoot('grit/testdata')) grd.SetOutputLanguage('en') grd.RunGatherers() @@ -57,9 +57,12 @@ class StructureUnittest(unittest.TestCase): filename = node.Process(tempfile.gettempdir()) with open(os.path.join(tempfile.gettempdir(), filename)) as f: result = f.read() - self.failUnless(result == ('<h1>Hello!</h1>\n' - 'Some cool things are foo, bar, baz.\n' - 'Did you know that 2+2==4?\n')) + self.failUnlessEqual(('<h1>Hello!</h1>\n' + 'Some cool things are foo, bar, baz.\n' + 'Did you know that 2+2==4?\n' + '<p>\n' + ' Hello!\n' + '</p>\n'), result) if __name__ == '__main__': diff --git a/grit/testdata/structure_variables.html b/grit/testdata/structure_variables.html index c90bfc9..2a15de8 100644 --- a/grit/testdata/structure_variables.html +++ b/grit/testdata/structure_variables.html @@ -1,3 +1,4 @@ <h1>[GREETING]!</h1> Some cool things are [THINGS]. Did you know that [EQUATION]? +<include src="[filename].html"> |