Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding option to concatenate files before processing #286

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 31 additions & 6 deletions compressor/base.py
Expand Up @@ -50,6 +50,28 @@ def split_contents(self):
"""
raise NotImplementedError

def group_contents(self):
contents = []
groups = {}
for kind, value, basename, elems in self.split_contents():
attrs = self.parser.elem_attribs(elems[0])
charset = attrs.get("charset", self.charset)
mimetype = attrs.get("type", None)
if mimetype:
if kind == SOURCE_FILE:
value = self.get_filecontent(value, charset)
idx = groups.get(mimetype, -1)
if idx >= 0:
contents[idx][0] = SOURCE_HUNK
contents[idx][1] += value
contents[idx][3].extend(elems)
else:
groups[mimetype] = len(contents)
contents.append([kind, value, smart_unicode(basename), elems])
else:
contents.append([kind, value, basename, elems])
return contents

def get_template_name(self, mode):
"""
Returns the template path for the given mode.
Expand Down Expand Up @@ -147,14 +169,17 @@ def hunks(self, forced=False):
bunch of precompiled and/or rendered hunks.
"""
enabled = settings.COMPRESS_ENABLED or forced
group_first = getattr(self, 'opts', None) and self.opts.get('group_first', 'false').lowercase() == 'true'
contents = group_first and self.group_contents() or self.split_contents()

for kind, value, basename, elem in self.split_contents():
for kind, value, basename, elems in contents:
precompiled = False
attribs = self.parser.elem_attribs(elem)
# If it's a grouped set, they should all have the same charset and type
attribs = self.parser.elem_attribs(elems[0])
charset = attribs.get("charset", self.charset)
options = {
'method': METHOD_INPUT,
'elem': elem,
'elems': elems,
'kind': kind,
'basename': basename,
}
Expand All @@ -174,7 +199,7 @@ def hunks(self, forced=False):
value = self.handle_output(kind, value, forced=True, basename=basename)
yield smart_unicode(value, charset.lower())
else:
yield self.parser.elem_str(elem)
yield "\n".join([self.parser.elem_str(e) for e in elems])

def filter_output(self, content):
"""
Expand All @@ -193,10 +218,10 @@ def filter_input(self, forced=False):
content.append(hunk)
return content

def precompile(self, content, kind=None, elem=None, filename=None, **kwargs):
def precompile(self, content, kind=None, elems=None, filename=None, **kwargs):
if not kind:
return False, content
attrs = self.parser.elem_attribs(elem)
attrs = self.parser.elem_attribs(elems[0])
mimetype = attrs.get("type", None)
if mimetype:
command = self.all_mimetypes.get(mimetype)
Expand Down
4 changes: 2 additions & 2 deletions compressor/css.py
Expand Up @@ -21,9 +21,9 @@ def split_contents(self):
if elem_name == 'link' and elem_attribs['rel'].lower() == 'stylesheet':
basename = self.get_basename(elem_attribs['href'])
filename = self.get_filename(basename)
data = (SOURCE_FILE, filename, basename, elem)
data = (SOURCE_FILE, filename, basename, [elem])
elif elem_name == 'style':
data = (SOURCE_HUNK, self.parser.elem_content(elem), None, elem)
data = (SOURCE_HUNK, self.parser.elem_content(elem), None, [elem])
if data:
self.split_content.append(data)
media = elem_attribs.get('media', None)
Expand Down
4 changes: 2 additions & 2 deletions compressor/js.py
Expand Up @@ -17,9 +17,9 @@ def split_contents(self):
if 'src' in attribs:
basename = self.get_basename(attribs['src'])
filename = self.get_filename(basename)
content = (SOURCE_FILE, filename, basename, elem)
content = (SOURCE_FILE, filename, basename, [elem])
self.split_content.append(content)
else:
content = self.parser.elem_content(elem)
self.split_content.append((SOURCE_HUNK, content, None, elem))
self.split_content.append((SOURCE_HUNK, content, None, [elem]))
return self.split_content
1 change: 1 addition & 0 deletions compressor/tests/media/css/one.less
@@ -0,0 +1 @@
body { background:#990; }
1 change: 1 addition & 0 deletions compressor/tests/media/css/two.less
@@ -0,0 +1 @@
body { color:#fff; }
1 change: 1 addition & 0 deletions compressor/tests/media/js/two.coffee
@@ -0,0 +1 @@
# this is a comment.
58 changes: 56 additions & 2 deletions compressor/tests/test_base.py
Expand Up @@ -46,7 +46,7 @@ def test_css_split(self):
(SOURCE_FILE, os.path.join(settings.COMPRESS_ROOT, u'css', u'two.css'), u'css/two.css', u'<link rel="stylesheet" href="/media/css/two.css" type="text/css" />'),
]
split = self.css_node.split_contents()
split = [(x[0], x[1], x[2], self.css_node.parser.elem_str(x[3])) for x in split]
split = [(x[0], x[1], x[2], self.css_node.parser.elem_str(x[3][0])) for x in split]
self.assertEqual(out, split)

def test_css_hunks(self):
Expand Down Expand Up @@ -83,7 +83,7 @@ def test_js_split(self):
(SOURCE_HUNK, u'obj.value = "value";', None, '<script type="text/javascript">obj.value = "value";</script>'),
]
split = self.js_node.split_contents()
split = [(x[0], x[1], x[2], self.js_node.parser.elem_str(x[3])) for x in split]
split = [(x[0], x[1], x[2], self.js_node.parser.elem_str(x[3][0])) for x in split]
self.assertEqual(out, split)

def test_js_hunks(self):
Expand Down Expand Up @@ -135,6 +135,60 @@ def test_custom_output_dir(self):
settings.COMPRESS_OUTPUT_DIR = old_output_dir


def make_elems_str(parser, elems):
return "".join([parser.elem_str(x) for x in elems])


class CompressorGroupFirstTestCase(TestCase):
def setUp(self):
settings.COMPRESS_ENABLED = True
settings.COMPRESS_PRECOMPILERS = {}
self.css = """\
<link rel="stylesheet" href="/media/css/one.css" type="text/css" />
<style type="text/css">p { border:5px solid green;}</style>
<link rel="stylesheet" href="/media/css/one.less" type="text/less" />
<link rel="stylesheet" href="/media/css/two.less" type="text/less" />"""
self.css_node = CssCompressor(self.css)
self.css_node.opts = {'group_first': 'true'}

self.js = """\
<script src="/media/js/one.js" type="text/javascript"></script>
<script type="text/javascript">obj.value = "value";</script>
<script src="/media/js/one.coffee" type="text/coffeescript"></script>
<script src="/media/js/two.coffee" type="text/coffeescript"></script>"""
self.js_node = JsCompressor(self.js)

def test_css_group(self):
out = [
[SOURCE_HUNK,
u'body { background:#990; }p { border:5px solid green;}',
u'css/one.css',
u'<link rel="stylesheet" href="/media/css/one.css" type="text/css" /><style type="text/css">p { border:5px solid green;}</style>'],
[SOURCE_HUNK,
u'body { background:#990; }body { color:#fff; }',
u'css/one.less',
u'<link rel="stylesheet" href="/media/css/one.less" type="text/less" /><link rel="stylesheet" href="/media/css/two.less" type="text/less" />'],
]
split = self.css_node.group_contents()
split = [[x[0], x[1], x[2], make_elems_str(self.css_node.parser, x[3])] for x in split]
self.assertEqual(out, split)

def test_js_group(self):
out = [
[SOURCE_HUNK,
u'obj = {};obj.value = "value";',
u'js/one.js',
'<script src="/media/js/one.js" type="text/javascript"></script><script type="text/javascript">obj.value = "value";</script>'],
[SOURCE_HUNK,
u'# this is a comment.\n# this is a comment.',
u'js/one.coffee',
'<script src="/media/js/one.coffee" type="text/coffeescript"></script><script src="/media/js/two.coffee" type="text/coffeescript"></script>'],
]
split = self.js_node.group_contents()
split = [[x[0], x[1], x[2], make_elems_str(self.js_node.parser, x[3])] for x in split]
self.assertEqual(out, split)


class CssMediaTestCase(TestCase):
def setUp(self):
self.css = """\
Expand Down
4 changes: 2 additions & 2 deletions compressor/tests/test_parsers.py
Expand Up @@ -59,7 +59,7 @@ def test_css_split(self):
(SOURCE_FILE, os.path.join(settings.COMPRESS_ROOT, u'css', u'two.css'), u'css/two.css', u'<link href="/media/css/two.css" rel="stylesheet" type="text/css">'),
]
split = self.css_node.split_contents()
split = [(x[0], x[1], x[2], self.css_node.parser.elem_str(x[3])) for x in split]
split = [(x[0], x[1], x[2], self.css_node.parser.elem_str(x[3][0])) for x in split]
self.assertEqual(out, split)

def test_js_split(self):
Expand All @@ -68,7 +68,7 @@ def test_js_split(self):
(SOURCE_HUNK, u'obj.value = "value";', None, u'<script type="text/javascript">obj.value = "value";</script>'),
]
split = self.js_node.split_contents()
split = [(x[0], x[1], x[2], self.js_node.parser.elem_str(x[3])) for x in split]
split = [(x[0], x[1], x[2], self.js_node.parser.elem_str(x[3][0])) for x in split]
self.assertEqual(out, split)

Html5LibParserTests = skipIf(
Expand Down