PageRenderTime 53ms CodeModel.GetById 40ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/hyde/ext/plugins/less.py

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