Skip to content

Commit c8e9eb8

Browse files
committed
Fix #22 Use importer callbacks to handle static path prefixes
Instead of import paths, use the importer callback so we can handle static paths prefixes, and possibly also non-filesystem storage. This is more complicated than anticipated, because we have to re-create the fallback mechanisms for handling partials and extensions, and because finders.find ignores prefixes. There is probably room for improvement, especially around the source maps, but this is a start. Note that the test_raw_css_import test had to be changed, because the libsass doesn't seem to use @import when callbacks are used.
1 parent edfa47a commit c8e9eb8

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

django_libsass.py

+41-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,46 @@ def static(path):
3030
INCLUDE_PATHS = None # populate this on first call to 'get_include_paths'
3131

3232

33+
def importer(path, prev):
34+
"""
35+
A callback for handling included files.
36+
"""
37+
if path.startswith('/'):
38+
# An absolute path was used, don't try relative paths.
39+
candidates = [path[1:]]
40+
elif prev == 'stdin':
41+
# The parent is STDIN, so only try absolute paths.
42+
candidates = [path]
43+
else:
44+
# Try both relative and absolute paths, prefer relative.
45+
candidates = [
46+
os.path.normpath(os.path.join(os.path.dirname(prev), path)),
47+
path,
48+
]
49+
# Try adding _ in front of the file for partials.
50+
for candidate in candidates[:]:
51+
candidates.insert(0, '/_'.join(candidate.rsplit('/', 1)))
52+
# Try adding extensions.
53+
for candidate in candidates[:]:
54+
for ext in ['.scss', '.sass', '.css']:
55+
candidates.append(candidate + ext)
56+
for finder in get_finders():
57+
# We can't use finder.find() because we need the prefixes.
58+
for storage_filename, storage in finder.list([]):
59+
prefix = getattr(storage, "prefix", "")
60+
filename = os.path.join(prefix, storage_filename)
61+
if filename in candidates:
62+
return [(filename, storage.open(storage_filename).read())]
63+
# Additional includes are just regular directories.
64+
for directory in ADDITIONAL_INCLUDE_PATHS:
65+
for candidate in candidates:
66+
filename = os.path.join(directory, candidate)
67+
if os.path.exists(filename):
68+
return [(candidate, open(filename).read())]
69+
# Nothing was found.
70+
return None
71+
72+
3373
def get_include_paths():
3474
"""
3575
Generate a list of include paths that libsass should use to find files
@@ -110,11 +150,11 @@ def compile(**kwargs):
110150
kwargs = kwargs.copy()
111151
if PRECISION is not None:
112152
kwargs['precision'] = PRECISION
113-
kwargs['include_paths'] = (kwargs.get('include_paths') or []) + get_include_paths()
114153

115154
custom_functions = CUSTOM_FUNCTIONS.copy()
116155
custom_functions.update(kwargs.get('custom_functions', {}))
117156
kwargs['custom_functions'] = custom_functions
157+
kwargs['importers'] = [(0, importer)]
118158

119159
if SOURCEMAPS and kwargs.get('filename', None):
120160
# We need to pass source_map_file to libsass so it generates

tests/tests/test_sass.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def test_extra_include_path(self):
1919

2020
def test_raw_css_import(self):
2121
result = compile(filename=os.path.join(settings.BASE_DIR, 'tests', 'static', 'css', 'with_raw_css_import.scss'))
22-
self.assertIn('@import url(raw1.css);', result)
22+
self.assertIn('.raw-style-1', result)
2323
self.assertIn('.raw-style-2', result)
2424

2525
def test_static_function(self):

0 commit comments

Comments
 (0)