Files
deb-python-django-pyscss/django_pyscss/scss.py
2014-02-01 19:05:04 -07:00

95 lines
3.3 KiB
Python

from __future__ import absolute_import, unicode_literals
import fnmatch
from django.contrib.staticfiles import finders
from django.contrib.staticfiles.storage import staticfiles_storage
from django.conf import settings
from scss import (
Scss, dequote, log, spawn_rule,
OPTIONS, PROPERTIES,
)
def find_all_files(glob):
"""
Finds all files in the django finders for a given glob,
returns the file path, if available, and the django storage object.
storage objects must implement the File storage API:
https://docs.djangoproject.com/en/dev/ref/files/storage/
"""
for finder in finders.get_finders():
for path, storage in finder.list([]):
if fnmatch.fnmatchcase(path, glob):
yield path, storage
def find_one_file(path):
for file in find_all_files(path):
return file
class DjangoScss(Scss):
"""
A subclass of the Scss compiler that uses the storages API for accessing
files.
"""
def get_file_from_storage(self, filename):
try:
filename = staticfiles_storage.path(filename)
except NotImplementedError:
# remote storages don't implement path
pass
finally:
with staticfiles_storage.open(filename) as f:
return f.read()
def get_file_from_finders(self, filename):
path, storage = find_one_file(filename)
with storage.open(path) as f:
return f.read()
def get_file_contents(self, filename):
# TODO: the switch probably shouldn't be on DEBUG
if settings.DEBUG:
return self.get_file_from_finders(filename)
else:
return self.get_file_from_storage(filename)
def _do_import(self, rule, p_selectors, p_parents, p_children, scope, media, c_lineno, c_property, c_codestr, code, name):
"""
Implements @import using the django storages API.
"""
# Protect against going to prohibited places...
if '..' in name or '://' in name or 'url(' in name:
rule[PROPERTIES].append((c_lineno, c_property, None))
return
full_filename = None
i_codestr = None
names = name.split(',')
for filename in names:
filename = dequote(name.strip())
if '@import ' + filename in rule[OPTIONS]:
# If already imported in this scope, skip
continue
try:
i_codestr = self.scss_files[filename]
except KeyError:
i_codestr = self.get_file_contents(filename)
if i_codestr is None:
i_codestr = self._do_magic_import(rule, p_selectors, p_parents, p_children, scope, media, c_lineno, c_property, c_codestr, code, name)
if i_codestr is None:
log.warn("I couldn't find this file (%s)." % filename)
i_codestr = self.scss_files[name] = i_codestr and self.load_string(i_codestr, full_filename)
if name not in self.scss_files:
self._scss_files_order.append(name)
if i_codestr is not None:
_rule = spawn_rule(rule, codestr=i_codestr, path=full_filename, lineno=c_lineno)
self.manage_children(_rule, p_selectors, p_parents, p_children, scope, media)
rule[OPTIONS]['@import ' + name] = True