---
This new plugin allow to combine multiple files into one. Here is an
example:
```
---
combine:
files: luffy.*.js
where: top
---
luffy.effects();
luffy.search();
```
All luffy.*.js files will be combined and added to the top of the file.
main
| @@ -0,0 +1,108 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| """ | |||||
| Contains classes to combine files into one | |||||
| """ | |||||
| from fnmatch import fnmatch | |||||
| from hyde.model import Expando | |||||
| from hyde.plugin import Plugin | |||||
| class CombinePlugin(Plugin): | |||||
| """ | |||||
| To use this combine, the following configuration should be added | |||||
| to meta data:: | |||||
| combine: | |||||
| files: | |||||
| - ns1.*.js | |||||
| - ns2.*.js | |||||
| where: top | |||||
| remove: yes | |||||
| `files` is a list of resources (or just a resource) that should be | |||||
| combined. Globbing is performed. `where` indicate where the | |||||
| combination should be done. This could be `top` or `bottom` of the | |||||
| file. `remove` tell if we should remove resources that have been | |||||
| combined into the resource. | |||||
| """ | |||||
| def __init__(self, site): | |||||
| super(CombinePlugin, self).__init__(site) | |||||
| def _combined(self, resource): | |||||
| """ | |||||
| Return the list of resources to combine to build this one. | |||||
| """ | |||||
| try: | |||||
| config = resource.meta.combine | |||||
| except AttributeError: | |||||
| return [] # Not a combined resource | |||||
| try: | |||||
| files = config.files | |||||
| except AttributeError: | |||||
| raise AttributeError("No resources to combine for [%s]" % resource) | |||||
| if type(files) is str: | |||||
| files = [ files ] | |||||
| # Grab resources to combine | |||||
| resources = [] | |||||
| for r in resource.node.resources: | |||||
| for f in files: | |||||
| if fnmatch(r.name, f): | |||||
| resources.append(r) | |||||
| break | |||||
| if not resources: | |||||
| self.logger.debug("No resources to combine for [%s]" % resource) | |||||
| return [] | |||||
| return sorted(resources, key=lambda r: r.name) | |||||
| def begin_site(self): | |||||
| """ | |||||
| Initialize the plugin and search for the combined resources | |||||
| """ | |||||
| for node in self.site.content.walk(): | |||||
| for resource in node.resources: | |||||
| resources = self._combined(resource) | |||||
| if not resources: | |||||
| continue | |||||
| # Build depends | |||||
| if not hasattr(resource, 'depends'): | |||||
| resource.depends = [] | |||||
| resource.depends.extend( | |||||
| [r.relative_path for r in resources | |||||
| if r.relative_path not in resource.depends]) | |||||
| # Remove combined resources if needed | |||||
| if hasattr(resource.meta.combine, "remove") and \ | |||||
| resource.meta.combine.remove: | |||||
| for r in resources: | |||||
| self.logger.debug( | |||||
| "Resource [%s] removed because combined" % r) | |||||
| r.is_processable = False | |||||
| def begin_text_resource(self, resource, text): | |||||
| """ | |||||
| When generating a resource, add combined file if needed. | |||||
| """ | |||||
| resources = self._combined(resource) | |||||
| if not resources: | |||||
| return | |||||
| where = "bottom" | |||||
| try: | |||||
| where = resource.meta.combine.where | |||||
| except AttributeError: | |||||
| pass | |||||
| if where not in [ "top", "bottom" ]: | |||||
| raise ValueError("%r should be either `top` or `bottom`" % where) | |||||
| self.logger.debug( | |||||
| "Combining %d resources for [%s]" % (len(resources), | |||||
| resource)) | |||||
| if where == "top": | |||||
| return "".join([r.source.read_all() for r in resources] + [text]) | |||||
| else: | |||||
| return "".join([text] + [r.source.read_all() for r in resources]) | |||||
| @@ -161,7 +161,7 @@ class Generator(object): | |||||
| if not target.exists or target.older_than(resource.source_file): | if not target.exists or target.older_than(resource.source_file): | ||||
| logger.debug("Found changes in %s" % resource) | logger.debug("Found changes in %s" % resource) | ||||
| return True | return True | ||||
| if resource.source_file.is_binary or not resource.uses_template: | |||||
| if resource.source_file.is_binary: | |||||
| logger.debug("No Changes found in %s" % resource) | logger.debug("No Changes found in %s" % resource) | ||||
| return False | return False | ||||
| deps = self.get_dependencies(resource) | deps = self.get_dependencies(resource) | ||||
| @@ -0,0 +1 @@ | |||||
| var a = 1 + 2; | |||||
| @@ -0,0 +1 @@ | |||||
| var b = a + 3; | |||||
| @@ -0,0 +1 @@ | |||||
| var c = a + 5; | |||||
| @@ -0,0 +1,86 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| """ | |||||
| Use nose | |||||
| `$ pip install nose` | |||||
| `$ nosetests` | |||||
| """ | |||||
| from hyde.fs import File, Folder | |||||
| from hyde.model import Expando | |||||
| from hyde.generator import Generator | |||||
| from hyde.site import Site | |||||
| COMBINE_SOURCE = File(__file__).parent.child_folder('combine') | |||||
| TEST_SITE = File(__file__).parent.parent.child_folder('_test') | |||||
| class TestCombine(object): | |||||
| def setUp(self): | |||||
| TEST_SITE.make() | |||||
| TEST_SITE.parent.child_folder( | |||||
| 'sites/test_jinja').copy_contents_to(TEST_SITE) | |||||
| TEST_SITE.child_folder('content/media/js').make() | |||||
| COMBINE_SOURCE.copy_contents_to(TEST_SITE.child('content/media/js')) | |||||
| def tearDown(self): | |||||
| TEST_SITE.delete() | |||||
| def _test_combine(self, content): | |||||
| s = Site(TEST_SITE) | |||||
| s.config.plugins = [ | |||||
| 'hyde.ext.plugins.meta.MetaPlugin', | |||||
| 'hyde.ext.plugins.combine.CombinePlugin'] | |||||
| source = TEST_SITE.child('content/media/js/script.js') | |||||
| target = File(Folder(s.config.deploy_root_path).child('media/js/script.js')) | |||||
| File(source).write(content) | |||||
| gen = Generator(s) | |||||
| gen.generate_resource_at_path(source) | |||||
| assert target.exists | |||||
| text = target.read_all() | |||||
| return text, s | |||||
| def test_combine_top(self): | |||||
| text, _ = self._test_combine(""" | |||||
| --- | |||||
| combine: | |||||
| files: script.*.js | |||||
| where: top | |||||
| --- | |||||
| Last line""") | |||||
| assert text == """var a = 1 + 2; | |||||
| var b = a + 3; | |||||
| var c = a + 5; | |||||
| Last line""" | |||||
| return | |||||
| def test_combine_bottom(self): | |||||
| text, _ = self._test_combine(""" | |||||
| --- | |||||
| combine: | |||||
| files: script.*.js | |||||
| where: bottom | |||||
| --- | |||||
| First line | |||||
| """) | |||||
| assert text == """First line | |||||
| var a = 1 + 2; | |||||
| var b = a + 3; | |||||
| var c = a + 5;""" | |||||
| return | |||||
| def test_combine_remove(self): | |||||
| _, s = self._test_combine(""" | |||||
| --- | |||||
| combine: | |||||
| files: script.*.js | |||||
| remove: yes | |||||
| --- | |||||
| First line""") | |||||
| for i in range(1,4): | |||||
| assert not File(Folder(s.config.deploy_root_path). | |||||
| child('media/js/script.%d.js' % i)).exists | |||||