diff --git a/.gitignore b/.gitignore index 052a9d9..943d1b3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.pyc .project .pydevproject +.sass-cache/ build mediasync_example diff --git a/mediasync/__init__.py b/mediasync/__init__.py index 612bd14..662c91e 100644 --- a/mediasync/__init__.py +++ b/mediasync/__init__.py @@ -130,7 +130,7 @@ def sync(client=None, force=False, verbose=True): continue filedata, dirname = filedata - content_type = mimetypes.guess_type(joinfile)[0] or 'application/octet-stream' + content_type = mimetypes.guess_type(joinfile)[0] or msettings['DEFAULT_MIMETYPE'] remote_path = joinfile if dirname: @@ -156,7 +156,7 @@ def sync(client=None, force=False, verbose=True): filepath = os.path.join(dirpath, filename) remote_path = "%s/%s" % (dirname, filename) - content_type = mimetypes.guess_type(filepath)[0] or 'application/octet-stream' + content_type = mimetypes.guess_type(filepath)[0] or msettings['DEFAULT_MIMETYPE'] if not is_syncable_file(os.path.basename(filename)) or not os.path.isfile(filepath): continue # hidden file or directory, do not upload diff --git a/mediasync/conf.py b/mediasync/conf.py index cfe54a3..4214901 100644 --- a/mediasync/conf.py +++ b/mediasync/conf.py @@ -2,12 +2,13 @@ from django.conf import settings from mediasync.processors import slim _settings = { - 'CSS_PATH': "", + 'CSS_PATH': '', + 'DEFAULT_MIMETYPE': 'application/octet-stream', 'DOCTYPE': 'html5', 'EMULATE_COMBO': False, 'EXPIRATION_DAYS': 365, 'JOINED': {}, - 'JS_PATH': "", + 'JS_PATH': '', 'STATIC_ROOT': getattr(settings, 'STATIC_ROOT', None) or getattr(settings, 'MEDIA_ROOT', None), 'STATIC_URL': getattr(settings, 'STATIC_URL', None) or diff --git a/mediasync/signals.py b/mediasync/signals.py index 87097b2..8e98159 100644 --- a/mediasync/signals.py +++ b/mediasync/signals.py @@ -1,7 +1,10 @@ from django.core import management from django.core.management.base import CommandError from django.dispatch import Signal -from mediasync import SyncException +from mediasync import SyncException, listdir_recursive +from mediasync.conf import msettings +import os +import subprocess pre_sync = Signal() post_sync = Signal() @@ -11,3 +14,19 @@ def collectstatic_receiver(sender, **kwargs): management.call_command('collectstatic') except CommandError: raise SyncException("collectstatic management command not found") + +def sass_receiver(sender, **kwargs): + + sass_cmd = msettings.get("SASS_COMMAND", "sass") + + root = msettings['STATIC_ROOT'] + + for filename in listdir_recursive(root): + + if filename.lower().endswith('scss'): + + sass_path = os.path.join(root, filename) + css_path = sass_path[:-4] + "css" + + cmd = "%s %s %s" % (sass_cmd, sass_path, css_path) + subprocess.call(cmd.split(' ')) \ No newline at end of file diff --git a/mediasync/tests/media/css/3.scss b/mediasync/tests/media/css/3.scss new file mode 100644 index 0000000..5a2373f --- /dev/null +++ b/mediasync/tests/media/css/3.scss @@ -0,0 +1,5 @@ +a { + color: #ce4dd6; + &:hover { color: #ffb3ff; } + &:visited { color: #c458cb; } +} \ No newline at end of file diff --git a/mediasync/tests/tests.py b/mediasync/tests/tests.py index e8b0c44..aa75504 100644 --- a/mediasync/tests/tests.py +++ b/mediasync/tests/tests.py @@ -2,6 +2,7 @@ from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.dispatch import receiver from hashlib import md5 +import glob import httplib import itertools import os @@ -9,10 +10,10 @@ import re import time import unittest -from mediasync import backends, JS_MIMETYPES +from mediasync import backends, JS_MIMETYPES, listdir_recursive from mediasync.backends import BaseClient from mediasync.conf import msettings -from mediasync.signals import pre_sync, post_sync +from mediasync.signals import pre_sync, post_sync, sass_receiver import mediasync import mimetypes @@ -103,6 +104,7 @@ class MockClientTestCase(unittest.TestCase): allowed_files = [ 'css/1.css', 'css/2.css', + 'css/3.scss', 'img/black.png', 'js/1.js', 'js/2.js', @@ -116,6 +118,7 @@ class MockClientTestCase(unittest.TestCase): to_sync = { 'css/1.css': 'text/css', 'css/2.css': 'text/css', + 'css/3.scss': msettings['DEFAULT_MIMETYPE'], 'css/joined.css': 'text/css', 'img/black.png': 'image/png', 'js/1.js': 'application/javascript', @@ -219,7 +222,7 @@ class S3ClientTestCase(unittest.TestCase): response.read() # verify valid content type - content_type = mimetypes.guess_type(path)[0] or 'application/octet-stream' + content_type = mimetypes.guess_type(path)[0] or msettings['DEFAULT_MIMETYPE'] self.assertEqual(response.getheader("Content-Type", None), content_type) # check for valid expires headers @@ -344,6 +347,13 @@ class SignalTestCase(unittest.TestCase): msettings['BACKEND'] = 'mediasync.tests.tests' self.client = backends.client() + def tearDown(self): + root = msettings['STATIC_ROOT'] + for filename in glob.glob(os.path.join(root, "*/*.scss")): + path = filename[:-4] + "css" + if os.path.exists(path): + os.unlink(path) + def testSyncSignals(self): self.client.called_presync = False @@ -363,5 +373,17 @@ class SignalTestCase(unittest.TestCase): self.assertTrue(self.client.called_presync) self.assertTrue(self.client.called_postsync) + + def testSassReceiver(self): + + pre_sync.connect(sass_receiver) + + mediasync.sync(self.client, force=True, verbose=False) + + root = msettings['STATIC_ROOT'] + + for sass_path in glob.glob(os.path.join(root, "*/*.scss")): + css_path = sass_path[:-4] + "css" + self.assertTrue(os.path.exists(css_path)) \ No newline at end of file