|
| 1 | +from __future__ import unicode_literals |
| 2 | + |
| 3 | +import codecs |
| 4 | +import json |
| 5 | +import os |
| 6 | + |
| 7 | +from django.contrib.staticfiles.storage import staticfiles_storage |
| 8 | + |
| 9 | +from pipeline.conf import settings |
| 10 | +from pipeline.compressors import SubProcessCompressor |
| 11 | +from pipeline.utils import source_map_re, relurl |
| 12 | + |
| 13 | + |
| 14 | +class CleanCSSCompressor(SubProcessCompressor): |
| 15 | + |
| 16 | + def compress_css(self, css): |
| 17 | + args = [settings.CLEANCSS_BINARY, settings.CLEANCSS_ARGUMENTS] |
| 18 | + return self.execute_command(args, css) |
| 19 | + |
| 20 | + def compress_css_with_source_map(self, paths, output_filename): |
| 21 | + output_path = staticfiles_storage.path(output_filename) |
| 22 | + output_dir = os.path.dirname(output_path) |
| 23 | + if not os.path.exists(output_dir): |
| 24 | + os.makedirs(output_dir) |
| 25 | + |
| 26 | + args = [settings.CLEANCSS_BINARY] |
| 27 | + args += ['--source-map'] |
| 28 | + if settings.CLEANCSS_ARGUMENTS: |
| 29 | + args += [settings.CLEANCSS_ARGUMENTS] |
| 30 | + else: |
| 31 | + # At present, without these arguments, cleancss does not |
| 32 | + # generate accurate source maps |
| 33 | + args += [ |
| 34 | + '--skip-advanced', '--skip-media-merging', |
| 35 | + '--skip-restructuring', '--skip-shorthand-compacting', |
| 36 | + '--keep-line-breaks'] |
| 37 | + args += ['--output', output_path] |
| 38 | + args += [staticfiles_storage.path(p) for p in paths] |
| 39 | + |
| 40 | + self.execute_command(args, cwd=output_dir) |
| 41 | + |
| 42 | + source_map_file = "%s.map" % output_path |
| 43 | + |
| 44 | + with codecs.open(output_path, encoding='utf-8') as f: |
| 45 | + css = f.read() |
| 46 | + with codecs.open(source_map_file, encoding='utf-8') as f: |
| 47 | + source_map = f.read() |
| 48 | + |
| 49 | + # Strip out existing source map comment (it will be re-added with packaging) |
| 50 | + css = source_map_re.sub('', css) |
| 51 | + |
| 52 | + output_url = "%s/%s" % ( |
| 53 | + staticfiles_storage.url(os.path.dirname(output_filename)), |
| 54 | + os.path.basename(output_path)) |
| 55 | + |
| 56 | + # Grab urls from staticfiles storage (in case filenames are hashed) |
| 57 | + source_map_data = json.loads(source_map) |
| 58 | + for i, source in enumerate(source_map_data['sources']): |
| 59 | + source_abs_path = os.path.join(output_dir, source) |
| 60 | + source_rel_path = os.path.relpath( |
| 61 | + source_abs_path, staticfiles_storage.base_location) |
| 62 | + source_url = staticfiles_storage.url(source_rel_path) |
| 63 | + source_map_data['sources'][i] = relurl(source_url, output_url) |
| 64 | + source_map = json.dumps(source_map_data, indent="\t") |
| 65 | + |
| 66 | + return css, source_map |
0 commit comments