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

Manifest files storage #166

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE-MIT
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2015 Jacob Rief
Copyright (c) 2015-2023 Jacob Rief <[email protected]>
Copyright (c) 2021 Dominik George <[email protected]>

Permission is hereby granted, free of charge, to any person obtaining a copy
Expand Down
7 changes: 6 additions & 1 deletion sass_processor/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.files.base import ContentFile
from django.core.files.storage import get_storage_class
from django.template import Context
from django.utils.encoding import force_bytes

Expand All @@ -24,6 +25,7 @@

class SassProcessor:
source_storage = SassFileStorage()
delivery_storage = get_storage_class(settings.STATICFILES_STORAGE)()
include_paths = [str(ip) for ip in getattr(settings, 'SASS_PROCESSOR_INCLUDE_DIRS', [])]
try:
sass_precision = int(settings.SASS_PRECISION)
Expand Down Expand Up @@ -140,7 +142,10 @@ def is_latest(self, sourcemap_file, base):

@classmethod
def handle_simple(cls, path):
return cls.source_storage.url(path)
try:
return cls.delivery_storage.url(path)
except ValueError:
return cls.source_storage.url(path)


_sass_processor = SassProcessor()
Expand Down
3 changes: 3 additions & 0 deletions sass_processor/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ def _setup(self):

self._wrapped = storage_class(**storage_options)

def __repr__(self):
return repr(self._wrapped)


def find_file(path):
for finder in get_finders():
Expand Down
1 change: 0 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[metadata]
name = django-sass-processor
version = attr: sass_processor.__version__
description = SASS processor to compile SCSS files into *.css, while rendering, or offline.
long_description = file: README.md
long_description_content_type = text/markdown
Expand Down
5 changes: 4 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#!/usr/bin/env python
from setuptools import setup
from sass_processor import __version__

setup()
setup(
version=__version__,
)
13 changes: 6 additions & 7 deletions tests/settings.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import os
from pathlib import Path

from tests.jinja2 import environment

Expand All @@ -13,6 +13,8 @@
}
}

PROJECT_ROOT = Path(__file__).parent

INSTALLED_APPS = [
'django.contrib.contenttypes',
'django.contrib.sites',
Expand Down Expand Up @@ -64,18 +66,18 @@

STATIC_URL = '/static/'

PROJECT_ROOT = os.path.abspath(os.path.join(__file__, os.path.pardir))

STATICFILES_FINDERS = [
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'sass_processor.finders.CssFinder',
]

STATICFILES_DIRS = [
os.path.join(PROJECT_ROOT, 'static'),
PROJECT_ROOT / 'static',
]

STATIC_ROOT = PROJECT_ROOT / 'tmpstatic'

SASS_PROCESSOR_ENABLED = True

SASS_PROCESSOR_CUSTOM_FUNCTIONS = {
Expand All @@ -85,6 +87,3 @@
}

SASS_BLUE_COLOR = '#0000ff'


STATIC_ROOT = os.path.join(os.path.dirname(__file__), "tmpstatic")
63 changes: 43 additions & 20 deletions tests/test_sass_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,30 +28,30 @@ def assert_sass_src_engine(self, template_name, engine):
)
# Strip the line breaks.
template_content = template.render({}).strip()
self.assertEqual('/static/tests/css/main.css', template_content)
assert template_content == '/static/tests/css/main.css'

css_file = os.path.join(settings.STATIC_ROOT, 'tests/css/main.css')
self.assertTrue(os.path.exists(css_file))
with open(css_file, 'r') as f:
css_file = settings.STATIC_ROOT / 'tests/css/main.css'
assert css_file.exists()
with css_file.open('r') as f:
output = f.read()
expected = "#main p{color:#00ff00;width:97%}#main p .redbox{background-color:#ff0000}#main p .redbox:hover{color:#000000}\n\n/*# sourceMappingURL=main.css.map */"
self.assertEqual(expected, output)
assert expected == output

# check if compilation is skipped file for a second invocation of `sass_src`
timestamp = os.path.getmtime(css_file)
timestamp = css_file.stat().st_mtime
template.render({})
self.assertEqual(timestamp, os.path.getmtime(css_file))
assert timestamp == css_file.stat().st_mtime

# removing `main.css.map` should trigger a recompilation
os.remove(css_file + '.map')
css_file.with_suffix(css_file.suffix + '.map').unlink()
template.render({})
self.assertTrue(os.path.exists(css_file + '.map'))
assert css_file.with_suffix(css_file.suffix + '.map').exists()

# if `main.scss` is newer than `main.css`, recompile everything
longago = calendar.timegm(datetime(2017, 1, 1).timetuple())
os.utime(css_file, (longago, longago))
template.render({})
self.assertGreater(timestamp, os.path.getmtime(css_file))
assert timestamp > css_file.stat().st_mtime

def test_sass_src_django(self):
self.assert_sass_src_engine(
Expand All @@ -76,31 +76,31 @@ def test_sass_processor(self):

css_file = sass_processor('tests/css/bluebox.scss')
self.assertEqual('/static/tests/css/bluebox.css', css_file)
css_file = os.path.join(settings.STATIC_ROOT, 'tests/css/bluebox.css')
self.assertTrue(os.path.exists(css_file))
with open(css_file, 'r') as f:
css_file = settings.STATIC_ROOT / 'tests/css/bluebox.css'
assert css_file.exists()
with css_file.open('r') as f:
output = f.read()
expected = '.bluebox{background-color:#0000ff;margin:10.0px 5.0px 20.0px 15.0px;color:#fa0a78}\n\n/*# sourceMappingURL=bluebox.css.map */'
self.assertEqual(expected, output)
assert expected == output

def assert_management_command(self, **kwargs):
call_command(
'compilescss',
**kwargs
)
if kwargs.get('use_storage', False):
css_file = os.path.join(settings.STATIC_ROOT, 'tests/css/main.css')
css_file = settings.STATIC_ROOT / 'tests/css/main.css'
else:
css_file = os.path.join(settings.PROJECT_ROOT, 'static/tests/css/main.css')
with open(css_file, 'r') as f:
css_file = settings.PROJECT_ROOT / 'static/tests/css/main.css'
with css_file.open('r') as f:
output = f.read()
expected = '#main p{color:#00ff00;width:97%}#main p .redbox{background-color:#ff0000}#main p .redbox:hover{color:#000000}\n'
self.assertEqual(expected, output)
self.assertFalse(os.path.exists(css_file + '.map'))
assert expected == output
assert not css_file.with_suffix(css_file.suffix + '.map').exists()

if not kwargs.get('use_storage', False):
call_command('compilescss', delete_files=True)
self.assertFalse(os.path.exists(css_file))
assert not css_file.exists()

@override_settings(DEBUG=False)
def test_management_command_django(self):
Expand Down Expand Up @@ -140,3 +140,26 @@ def test_use_storage_multiple(self):
engine=['jinja2', 'django'],
use_storage=True
)

@override_settings(
DEBUG=False,
SASS_PROCESSOR_STORAGE='django.contrib.staticfiles.storage.StaticFilesStorage',
STATICFILES_STORAGE='django.contrib.staticfiles.storage.ManifestStaticFilesStorage',
)
def test_manifest_static_files_storage(self):
css_file = settings.PROJECT_ROOT / 'static/tests/css/main.css'
assert not css_file.exists()
call_command('compilescss', use_storage=False)
assert css_file.exists()
with css_file.open('r') as f:
output = f.read()
expected = '#main p{color:#00ff00;width:97%}#main p .redbox{background-color:#ff0000}#main p .redbox:hover{color:#000000}\n'
assert expected == output
hashed_css_file = settings.PROJECT_ROOT / 'tmpstatic/tests/css/main.08b498e281f7.css'
assert not hashed_css_file.exists()
call_command('collectstatic', interactive=False, ignore_patterns=['*.scss'])
assert hashed_css_file.exists()
with hashed_css_file.open('r') as f:
output = f.read()
assert expected == output
call_command('compilescss', use_storage=False, delete_files=True)