@@ -1,133 +0,0 @@ | |||
# -*- coding: utf-8 -*- | |||
""" | |||
Contains classes to combine files into one | |||
""" | |||
from fnmatch import fnmatch | |||
from hyde.plugin import Plugin | |||
import operator | |||
class CombinePlugin(Plugin): | |||
""" | |||
To use this combine, the following configuration should be added | |||
to meta data:: | |||
combine: | |||
sort: false #Optional. Defaults to true. | |||
root: content/media #Optional. Path must be relative to content folder - default current folder | |||
recurse: true #Optional. Default false. | |||
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 | |||
# select site root | |||
try: | |||
root = self.site.content.node_from_relative_path(resource.meta.combine.root) | |||
except AttributeError: | |||
root = resource.node | |||
# select walker | |||
try: | |||
recurse = resource.meta.combine.recurse | |||
except AttributeError: | |||
recurse = False | |||
walker = root.walk_resources() if recurse else root.resources | |||
# Must we sort? | |||
try: | |||
sort = resource.meta.combine.sort | |||
except AttributeError: | |||
sort = True | |||
if sort: | |||
resources = sorted([r for r in walker if any(fnmatch(r.name, f) for f in files)], | |||
key=operator.attrgetter('name')) | |||
else: | |||
resources = [(f, r) for r in walker for f in files if fnmatch(r.name, f)] | |||
resources = [r[1] for f in files for r in resources if f in r] | |||
if not resources: | |||
self.logger.debug("No resources to combine for [%s]" % resource) | |||
return [] | |||
return resources | |||
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]) |
@@ -7,6 +7,9 @@ from hyde.plugin import Plugin | |||
from fswrap import Folder | |||
from fnmatch import fnmatch | |||
import operator | |||
class FlattenerPlugin(Plugin): | |||
""" | |||
The plugin class for flattening nested folders. | |||
@@ -43,3 +46,128 @@ class FlattenerPlugin(Plugin): | |||
for child in node.walk(): | |||
child.relative_deploy_path = target.path | |||
class CombinePlugin(Plugin): | |||
""" | |||
To use this combine, the following configuration should be added | |||
to meta data:: | |||
combine: | |||
sort: false #Optional. Defaults to true. | |||
root: content/media #Optional. Path must be relative to content folder - default current folder | |||
recurse: true #Optional. Default false. | |||
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 | |||
# select site root | |||
try: | |||
root = self.site.content.node_from_relative_path(resource.meta.combine.root) | |||
except AttributeError: | |||
root = resource.node | |||
# select walker | |||
try: | |||
recurse = resource.meta.combine.recurse | |||
except AttributeError: | |||
recurse = False | |||
walker = root.walk_resources() if recurse else root.resources | |||
# Must we sort? | |||
try: | |||
sort = resource.meta.combine.sort | |||
except AttributeError: | |||
sort = True | |||
if sort: | |||
resources = sorted([r for r in walker if any(fnmatch(r.name, f) for f in files)], | |||
key=operator.attrgetter('name')) | |||
else: | |||
resources = [(f, r) for r in walker for f in files if fnmatch(r.name, f)] | |||
resources = [r[1] for f in files for r in resources if f in r] | |||
if not resources: | |||
self.logger.debug("No resources to combine for [%s]" % resource) | |||
return [] | |||
return resources | |||
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]) | |||
@@ -17,7 +17,7 @@ class CombineTester(object): | |||
s = Site(TEST_SITE) | |||
s.config.plugins = [ | |||
'hyde.ext.plugins.meta.MetaPlugin', | |||
'hyde.ext.plugins.combine.CombinePlugin'] | |||
'hyde.ext.plugins.structure.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) | |||