Mercurial > piecrust2
comparison piecrust/processing/compass.py @ 196:154b8df04829
processing: Add Compass and Sass processors.
The Sass processor is similar to the Less processor, i.e. it tries to be
part of the structured pipeline processing by using the mapfile produced by
the Sass compiler in order to provide a list of dependencies.
The Compass processor is completely acting outside of the pipeline, so the
server won't know what's up to date and what's not. It's expected that the
user will run `compass watch` to keep things up to date. However, it will
require to pass the server's cache directory to put things in, so we'll need
to add some easy way to get that path for the user.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 11 Jan 2015 23:08:49 -0800 |
parents | |
children | c4b3a7fd2f87 |
comparison
equal
deleted
inserted
replaced
195:b4724e577a8c | 196:154b8df04829 |
---|---|
1 import os | |
2 import os.path | |
3 import logging | |
4 import platform | |
5 import subprocess | |
6 from piecrust.processing.base import Processor, PRIORITY_FIRST | |
7 from piecrust.uriutil import multi_replace | |
8 | |
9 | |
10 logger = logging.getLogger(__name__) | |
11 | |
12 | |
13 class CompassProcessor(Processor): | |
14 PROCESSOR_NAME = 'compass' | |
15 | |
16 STATE_UNKNOWN = 0 | |
17 STATE_INACTIVE = 1 | |
18 STATE_ACTIVE = 2 | |
19 | |
20 def __init__(self): | |
21 super(CompassProcessor, self).__init__() | |
22 # Using a high priority is needed to get to the `.scss` files before | |
23 # the Sass processor. | |
24 self.priority = PRIORITY_FIRST | |
25 self.is_bypassing_structured_processing = True | |
26 self.is_delegating_dependency_check = False | |
27 self._state = self.STATE_UNKNOWN | |
28 | |
29 def initialize(self, app): | |
30 super(CompassProcessor, self).initialize(app) | |
31 | |
32 def onPipelineStart(self, pipeline): | |
33 super(CompassProcessor, self).onPipelineStart(pipeline) | |
34 self._maybeActivate(pipeline) | |
35 | |
36 def onPipelineEnd(self, pipeline): | |
37 super(CompassProcessor, self).onPipelineEnd(pipeline) | |
38 self._maybeRunCompass(pipeline) | |
39 | |
40 def matches(self, path): | |
41 if self._state != self.STATE_ACTIVE: | |
42 return False | |
43 | |
44 _, ext = os.path.splitext(path) | |
45 return ext == '.scss' or ext == '.sass' | |
46 | |
47 def getDependencies(self, path): | |
48 raise Exception("Compass processor should handle dependencies by " | |
49 "itself.") | |
50 | |
51 def getOutputFilenames(self, filename): | |
52 raise Exception("Compass processor should handle outputs by itself.") | |
53 | |
54 def process(self, path, out_dir): | |
55 if path.startswith(self.app.theme_dir): | |
56 if not self._runInTheme: | |
57 logger.debug("Scheduling Compass execution in theme directory " | |
58 "after the pipeline is done.") | |
59 self._runInTheme = True | |
60 else: | |
61 if not self._runInSite: | |
62 logger.debug("Scheduling Compass execution after the pipeline " | |
63 "is done.") | |
64 self._runInSite = True | |
65 | |
66 def _maybeActivate(self, pipeline): | |
67 if self._state != self.STATE_UNKNOWN: | |
68 return | |
69 | |
70 config = self.app.config.get('compass') | |
71 if config is None or not config.get('enable'): | |
72 logger.debug("Compass processing is disabled (set " | |
73 "`compass/enable` to `true` to enable it).") | |
74 self._state = self.STATE_INACTIVE | |
75 return | |
76 | |
77 logger.debug("Activating Compass processing for SCSS/SASS files.") | |
78 self._state = self.STATE_ACTIVE | |
79 | |
80 bin_path = config.get('bin', 'compass') | |
81 | |
82 config_path = config.get('config_path', 'config.rb') | |
83 config_path = os.path.join(self.app.root_dir, config_path) | |
84 if not os.path.exists(config_path): | |
85 raise Exception("Can't find Compass configuration file: %s" % | |
86 config_path) | |
87 self._args = '%s compile --config "%s"' % (bin_path, config_path) | |
88 | |
89 frameworks = config.get('frameworks', []) | |
90 if not isinstance(frameworks, list): | |
91 frameworks = frameworks.split(',') | |
92 for f in frameworks: | |
93 self._args += ' --load %s' % f | |
94 | |
95 custom_args = config.get('options') | |
96 if custom_args: | |
97 self._args += ' ' + custom_args | |
98 | |
99 out_dir = pipeline.out_dir | |
100 tmp_dir = os.path.join(pipeline.tmp_dir, 'compass') | |
101 self._args = multi_replace( | |
102 self._args, | |
103 {'%out_dir%': out_dir, | |
104 '%tmp_dir%': tmp_dir}) | |
105 | |
106 self._runInSite = False | |
107 self._runInTheme = False | |
108 | |
109 def _maybeRunCompass(self, pipeline): | |
110 if self._state != self.STATE_ACTIVE: | |
111 return | |
112 | |
113 logger.debug("Running Compass with:") | |
114 logger.debug(self._args) | |
115 | |
116 prev_cwd = os.getcwd() | |
117 os.chdir(self.app.root_dir) | |
118 try: | |
119 retcode = subprocess.call(self._args, shell=True) | |
120 except FileNotFoundError as ex: | |
121 logger.error("Tried running Compass with command: %s" % | |
122 self._args) | |
123 raise Exception("Error running Compass. " | |
124 "Did you install it?") from ex | |
125 finally: | |
126 os.chdir(prev_cwd) | |
127 | |
128 if retcode != 0: | |
129 raise Exception("Error occured in Compass. Please check " | |
130 "log messages above for more information.") | |
131 return True | |
132 |