/hyde/ext/plugins/combine.py

http://github.com/hyde/hyde · Python · 134 lines · 76 code · 20 blank · 38 comment · 42 complexity · 8963813a9ff0a42affbcf78f86178e18 MD5 · raw file

  1. # -*- coding: utf-8 -*-
  2. """
  3. Contains classes to combine files into one
  4. """
  5. from fnmatch import fnmatch
  6. from hyde.model import Expando
  7. from hyde.plugin import Plugin
  8. import operator
  9. class CombinePlugin(Plugin):
  10. """
  11. To use this combine, the following configuration should be added
  12. to meta data::
  13. combine:
  14. sort: false #Optional. Defaults to true.
  15. root: content/media #Optional. Path must be relative to content folder - default current folder
  16. recurse: true #Optional. Default false.
  17. files:
  18. - ns1.*.js
  19. - ns2.*.js
  20. where: top
  21. remove: yes
  22. `files` is a list of resources (or just a resource) that should be
  23. combined. Globbing is performed. `where` indicate where the
  24. combination should be done. This could be `top` or `bottom` of the
  25. file. `remove` tell if we should remove resources that have been
  26. combined into the resource.
  27. """
  28. def __init__(self, site):
  29. super(CombinePlugin, self).__init__(site)
  30. def _combined(self, resource):
  31. """
  32. Return the list of resources to combine to build this one.
  33. """
  34. try:
  35. config = resource.meta.combine
  36. except AttributeError:
  37. return [] # Not a combined resource
  38. try:
  39. files = config.files
  40. except AttributeError:
  41. raise AttributeError("No resources to combine for [%s]" % resource)
  42. if type(files) is str:
  43. files = [ files ]
  44. # Grab resources to combine
  45. # select site root
  46. try:
  47. root = self.site.content.node_from_relative_path(resource.meta.combine.root)
  48. except AttributeError:
  49. root = resource.node
  50. # select walker
  51. try:
  52. recurse = resource.meta.combine.recurse
  53. except AttributeError:
  54. recurse = False
  55. walker = root.walk_resources() if recurse else root.resources
  56. # Must we sort?
  57. try:
  58. sort = resource.meta.combine.sort
  59. except AttributeError:
  60. sort = True
  61. if sort:
  62. resources = sorted([r for r in walker if any(fnmatch(r.name, f) for f in files)],
  63. key=operator.attrgetter('name'))
  64. else:
  65. resources = [(f, r) for r in walker for f in files if fnmatch(r.name, f)]
  66. resources = [r[1] for f in files for r in resources if f in r]
  67. if not resources:
  68. self.logger.debug("No resources to combine for [%s]" % resource)
  69. return []
  70. return resources
  71. def begin_site(self):
  72. """
  73. Initialize the plugin and search for the combined resources
  74. """
  75. for node in self.site.content.walk():
  76. for resource in node.resources:
  77. resources = self._combined(resource)
  78. if not resources:
  79. continue
  80. # Build depends
  81. if not hasattr(resource, 'depends'):
  82. resource.depends = []
  83. resource.depends.extend(
  84. [r.relative_path for r in resources
  85. if r.relative_path not in resource.depends])
  86. # Remove combined resources if needed
  87. if hasattr(resource.meta.combine, "remove") and \
  88. resource.meta.combine.remove:
  89. for r in resources:
  90. self.logger.debug(
  91. "Resource [%s] removed because combined" % r)
  92. r.is_processable = False
  93. def begin_text_resource(self, resource, text):
  94. """
  95. When generating a resource, add combined file if needed.
  96. """
  97. resources = self._combined(resource)
  98. if not resources:
  99. return
  100. where = "bottom"
  101. try:
  102. where = resource.meta.combine.where
  103. except AttributeError:
  104. pass
  105. if where not in [ "top", "bottom" ]:
  106. raise ValueError("%r should be either `top` or `bottom`" % where)
  107. self.logger.debug(
  108. "Combining %d resources for [%s]" % (len(resources),
  109. resource))
  110. if where == "top":
  111. return "".join([r.source.read_all() for r in resources] + [text])
  112. else:
  113. return "".join([text] + [r.source.read_all() for r in resources])