diff --git a/core/management/commands/compilestatic.py b/core/management/commands/compilestatic.py index 46e7596e..88436fd9 100644 --- a/core/management/commands/compilestatic.py +++ b/core/management/commands/compilestatic.py @@ -26,10 +26,22 @@ import os import sass from django.core.management.base import BaseCommand +from django.conf import settings + class Command(BaseCommand): help = "Compile scss files from static folder" + def compile(self, filename): + args = { + "filename": filename, + "include_paths": settings.STATIC_ROOT, + } + if settings.SASS_PRECISION: + args['precision'] = settings.SASS_PRECISION + return sass.compile(**args) + + def is_compilable(self, file, ext_list): path, ext = os.path.splitext(file) return ext in ext_list @@ -48,9 +60,8 @@ class Command(BaseCommand): def compilescss(self, file): print("compiling %s" % file) - with open(file, "r") as oldfile: - with open(file.replace('.scss', '.css'), "w") as newfile: - newfile.write(sass.compile(string=oldfile.read())) + with(open(file.replace('.scss', '.css'), "w")) as newfile: + newfile.write(self.compile(file)) def removescss(self, file): print("removing %s" % file) @@ -58,10 +69,10 @@ class Command(BaseCommand): def handle(self, *args, **options): - if 'static' in os.listdir(): + if os.path.isdir(settings.STATIC_ROOT): print("---- Compiling scss files ---") - self.exec_on_folder('static', self.compilescss) + self.exec_on_folder(settings.STATIC_ROOT, self.compilescss) print("---- Removing scss files ----") - self.exec_on_folder('static', self.removescss) + self.exec_on_folder(settings.STATIC_ROOT, self.removescss) else: - print("No static folder avalaible, please use collectstatic before compiling scss") \ No newline at end of file + print("No static folder avalaible, please use collectstatic before compiling scss") diff --git a/core/scss/finder.py b/core/scss/finder.py new file mode 100644 index 00000000..c9ef0859 --- /dev/null +++ b/core/scss/finder.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -* +# +# Copyright 2016,2017 +# - Sli +# +# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM, +# http://ae.utbm.fr. +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License a published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple +# Place - Suite 330, Boston, MA 02111-1307, USA. +# +# + +import os +from collections import OrderedDict +from django.conf import settings +from django.contrib.staticfiles.finders import FileSystemFinder +from django.core.files.storage import FileSystemStorage + + +class ScssFinder(FileSystemFinder): + """ + Find static *.css files compiled on the fly + """ + locations = [] + + def __init__(self, apps=None, *args, **kwargs): + location = settings.STATIC_ROOT + if not os.path.isdir(location): + return + self.locations = [ + ('', location), + ] + self.storages = OrderedDict() + filesystem_storage = FileSystemStorage(location=location) + filesystem_storage.prefix = self.locations[0][0] + self.storages[location] = filesystem_storage + + def find(self, path, all=False): + if path.endswith('.css'): + return super(ScssFinder, self).find(path, all) + return [] diff --git a/core/scss/processor.py b/core/scss/processor.py new file mode 100644 index 00000000..a4109759 --- /dev/null +++ b/core/scss/processor.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -* +# +# Copyright 2016,2017 +# - Sli +# +# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM, +# http://ae.utbm.fr. +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License a published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple +# Place - Suite 330, Boston, MA 02111-1307, USA. +# +# + +import os +import sass +from django.utils.encoding import force_bytes, iri_to_uri +from django.core.files.base import ContentFile +from django.utils.six.moves.urllib.parse import urljoin +from django.templatetags.static import static +from django.conf import settings +from .storage import ScssFileStorage, find_file + + +class ScssProcessor(object): + prefix = iri_to_uri(getattr(settings, 'STATIC_URL', '/static/')) + storage = ScssFileStorage() + scss_extensions = [".scss"] + + def __init__(self, path=None): + self.path = path + + def _convert_scss(self): + basename, ext = os.path.splitext(self.path) + css_filename = self.path.replace(".scss", ".css") + url = urljoin(self.prefix, css_filename) + + if not settings.DEBUG: + return url + + if ext not in self.scss_extensions: + return static(self.path) + + # Compilation on the fly + compile_args = { + "filename": find_file(self.path), + "include_paths": settings.SASS_INCLUDE_FOLDERS, + } + if settings.SASS_PRECISION: + compile_args['precision'] = settings.SASS_PRECISION + content = sass.compile(**compile_args) + content = force_bytes(content) + + if self.storage.exists(css_filename): + self.storage.delete(css_filename) + self.storage.save(css_filename, ContentFile(content)) + print("saved") + + return url + + def get_converted_scss(self): + if self.path: + return self._convert_scss() + else: + return "" diff --git a/core/scss/storage.py b/core/scss/storage.py new file mode 100644 index 00000000..242e8ff4 --- /dev/null +++ b/core/scss/storage.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -* +# +# Copyright 2016,2017 +# - Sli +# +# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM, +# http://ae.utbm.fr. +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License a published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple +# Place - Suite 330, Boston, MA 02111-1307, USA. +# +# + +from django.conf import settings +from django.contrib.staticfiles.finders import get_finders +from django.core.files.storage import FileSystemStorage + + +class ScssFileStorage(FileSystemStorage): + def __init__(self, location=None, base_url=None, *args, **kwargs): + if location is None: + location = settings.STATIC_ROOT + if base_url is None: + base_url = settings.STATIC_URL + super(ScssFileStorage, self).__init__(location, base_url, *args, **kwargs) + + +def find_file(path): + for finder in get_finders(): + result = finder.find(path) + if result: + return result diff --git a/core/templates/core/base.jinja b/core/templates/core/base.jinja index 33842017..a07a0257 100644 --- a/core/templates/core/base.jinja +++ b/core/templates/core/base.jinja @@ -8,7 +8,8 @@ - + {# #} + {% endblock %} diff --git a/core/templatetags/scss.py b/core/templatetags/scss.py new file mode 100644 index 00000000..da929983 --- /dev/null +++ b/core/templatetags/scss.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -* +# +# Copyright 2016,2017 +# - Sli +# +# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM, +# http://ae.utbm.fr. +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License a published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple +# Place - Suite 330, Boston, MA 02111-1307, USA. +# +# + +from django import template +from core.scss.processor import ScssProcessor + +register = template.Library() + + +@register.simple_tag() +def scss(path): + processor = ScssProcessor(path) + return processor.get_converted_scss() diff --git a/requirements.txt b/requirements.txt index 0660033b..53648d48 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,6 +13,4 @@ django-haystack whoosh django-debug-toolbar libsass -django-compressor -django-sass-processor # mysqlclient diff --git a/sith/settings.py b/sith/settings.py index d4eb721d..43ab6dd3 100644 --- a/sith/settings.py +++ b/sith/settings.py @@ -72,7 +72,6 @@ INSTALLED_APPS = ( 'rest_framework', 'ajax_select', 'haystack', - 'sass_processor', 'core', 'club', 'subscription', @@ -134,7 +133,6 @@ TEMPLATES = [ "django_jinja.builtins.extensions.UrlsExtension", "django_jinja.builtins.extensions.StaticFilesExtension", "django_jinja.builtins.extensions.DjangoFiltersExtension", - "sass_processor.jinja2.ext.SassSrc", ], "filters": { "markdown": "core.templatetags.renderer.markdown", @@ -149,6 +147,7 @@ TEMPLATES = [ "ProductType": "counter.models.ProductType", "timezone": "django.utils.timezone", "get_sith": "com.views.sith", + "scss": "core.templatetags.scss.scss", }, "bytecode_cache": { "name": "default", @@ -186,10 +185,6 @@ HAYSTACK_SIGNAL_PROCESSOR = 'core.search_indexes.UserOnlySignalProcessor' SASS_PRECISION = 8 -SASS_OUTPUT_STYLE = 'compact' - -SASS_TEMPLATE_EXTS = ['.jinja'] - WSGI_APPLICATION = 'sith.wsgi.application' @@ -242,7 +237,7 @@ STATIC_ROOT = './static/' STATICFILES_FINDERS = [ 'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder', - 'sass_processor.finders.CssFinder', + 'core.scss.finder.ScssFinder', ] # Auth configuration @@ -567,3 +562,6 @@ if DEBUG: 'debug_toolbar.panels.logging.LoggingPanel', 'debug_toolbar.panels.redirects.RedirectsPanel', ] + SASS_INCLUDE_FOLDERS = [ + 'core/static/', + ]