A fork of hyde, the static site generation. Some patches will be pushed upstream.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

116 lines
3.6 KiB

  1. # -*- coding: utf-8 -*-
  2. """
  3. Less css plugin
  4. """
  5. from hyde.plugin import CLTransformer
  6. import re
  7. import subprocess
  8. from fswrap import File
  9. class LessCSSPlugin(CLTransformer):
  10. """
  11. The plugin class for less css
  12. """
  13. def __init__(self, site):
  14. super(LessCSSPlugin, self).__init__(site)
  15. @property
  16. def executable_name(self):
  17. return "lessc"
  18. def _should_parse_resource(self, resource):
  19. """
  20. Check user defined
  21. """
  22. return getattr(resource, 'meta', {}).get('parse', True)
  23. def _should_replace_imports(self, resource):
  24. return getattr(resource, 'meta', {}).get('uses_template', True)
  25. def begin_site(self):
  26. """
  27. Find all the less css files and set their relative deploy path.
  28. """
  29. for resource in self.site.content.walk_resources():
  30. if resource.source_file.kind == 'less' and \
  31. self._should_parse_resource(resource):
  32. new_name = resource.source_file.name_without_extension + ".css"
  33. target_folder = File(resource.relative_deploy_path).parent
  34. resource.relative_deploy_path = target_folder.child(new_name)
  35. def begin_text_resource(self, resource, text):
  36. """
  37. Replace @import statements with {% include %} statements.
  38. """
  39. if not resource.source_file.kind == 'less' or not \
  40. self._should_parse_resource(resource) or not \
  41. self._should_replace_imports(resource):
  42. return text
  43. import_finder = re.compile(
  44. '^\\s*@import\s+(?:\'|\")([^\'\"]*)(?:\'|\")\s*\;\s*$',
  45. re.MULTILINE)
  46. def import_to_include(match):
  47. if not match.lastindex:
  48. return ''
  49. path = match.groups(1)[0]
  50. afile = File(resource.source_file.parent.child(path))
  51. if len(afile.kind.strip()) == 0:
  52. afile = File(afile.path + '.less')
  53. ref = self.site.content.resource_from_path(afile.path)
  54. if not ref:
  55. raise self.template.exception_class(
  56. "Cannot import from path [%s]" % afile.path)
  57. ref.is_processable = False
  58. return self.template.get_include_statement(ref.relative_path)
  59. text = import_finder.sub(import_to_include, text)
  60. return text
  61. @property
  62. def plugin_name(self):
  63. """
  64. The name of the plugin.
  65. """
  66. return "less"
  67. def text_resource_complete(self, resource, text):
  68. """
  69. Save the file to a temporary place and run less compiler.
  70. Read the generated file and return the text as output.
  71. Set the target path to have a css extension.
  72. """
  73. if not resource.source_file.kind == 'less' or not \
  74. self._should_parse_resource(resource):
  75. return
  76. supported = [
  77. "verbose",
  78. ("silent", "s"),
  79. ("compress", "x"),
  80. "O0",
  81. "O1",
  82. "O2",
  83. "include-path="
  84. ]
  85. less = self.app
  86. source = File.make_temp(text)
  87. target = File.make_temp('')
  88. args = [unicode(less)]
  89. args.extend(self.process_args(supported))
  90. args.extend([unicode(source), unicode(target)])
  91. try:
  92. self.call_app(args)
  93. except subprocess.CalledProcessError:
  94. raise self.template.exception_class(
  95. "Cannot process %s. Error occurred when "
  96. "processing [%s]" % (self.app.name, resource.source_file))
  97. return target.read_all()