Files
edx-platform/openedx/core/djangoapps/theming/finders.py
Zia Fazal a796b56314 saleem-latif/WL-328: Multi-Site Comprehensive Theming
ziafazal: improvements need for multi-tenancy
ziafazal: fixed broken tests
ziafazal: no need to add setting in test.py
ziafazal: added hostname validation
ziafazal: changes after feedback from mattdrayer
ziafazal: fixed branding and microsite broken tests
ziafazal: make STATICFILES_DIRS to list
ziafazal: added theme directory to mako lookup for tests
ziafazal: added more protection in test_util
saleem-latif: Enable SCSS Overrides for Comprehensive Theming
saleem-latif: Incoporate feedback changes, Correct test failures, add tests and enable theming for django templates
saleem-latif: Correct errors in python tests
mattdrayer: Fix invalid release reference
mattdrayer: Update django-wiki reference to latest release
saleem-latif: Update Theme storages to work with Caching, Pipeline and collectstatic
saleem-latif: Incorporate feedback changes
mattdrayer: Pylint violation fix
mattdrayer: Fix broken pavelib test
2016-03-28 14:57:01 -04:00

97 lines
3.6 KiB
Python

"""
Static file finders for Django.
https://docs.djangoproject.com/en/1.8/ref/settings/#std:setting-STATICFILES_FINDERS
Yes, this interface is private and undocumented, but we need to access it anyway.
In order to deploy Open edX in production, it's important to be able to collect
and process static assets: images, CSS, JS, fonts, etc. Django's collectstatic
system is the accepted way to do that in Django-based projects, but that system
doesn't handle every kind of collection and processing that web developers need.
Other open source projects like `Django-Pipeline`_ and `Django-Require`_ hook
into Django's collectstatic system to provide features like minification,
compression, Sass pre-processing, and require.js optimization for assets before
they are pushed to production. To make sure that themed assets are collected
and served by the system (in addition to core assets), we need to extend this
interface, as well.
.. _Django-Pipeline: http://django-pipeline.readthedocs.org/
.. _Django-Require: https://github.com/etianen/django-require
"""
import os
from collections import OrderedDict
from django.contrib.staticfiles import utils
from django.contrib.staticfiles.finders import BaseFinder
from django.utils import six
from openedx.core.djangoapps.theming.helpers import get_themes
from openedx.core.djangoapps.theming.storage import ThemeStorage
class ThemeFilesFinder(BaseFinder):
"""
A static files finder that looks in the directory of each theme as
specified in the source_dir attribute.
"""
storage_class = ThemeStorage
source_dir = 'static'
def __init__(self, *args, **kwargs):
# The list of themes that are handled
self.themes = []
# Mapping of theme names to storage instances
self.storages = OrderedDict()
themes = get_themes()
for theme in themes:
theme_storage = self.storage_class(
os.path.join(theme.path, self.source_dir),
prefix=theme.theme_dir,
)
self.storages[theme.theme_dir] = theme_storage
if theme.theme_dir not in self.themes:
self.themes.append(theme.theme_dir)
super(ThemeFilesFinder, self).__init__(*args, **kwargs)
def list(self, ignore_patterns):
"""
List all files in all app storages.
"""
for storage in six.itervalues(self.storages):
if storage.exists(''): # check if storage location exists
for path in utils.get_files(storage, ignore_patterns):
yield path, storage
def find(self, path, all=False): # pylint: disable=redefined-builtin
"""
Looks for files in the theme directories.
"""
matches = []
theme_dir = path.split("/", 1)[0]
themes = {t.theme_dir: t for t in get_themes()}
# if path is prefixed by theme name then search in the corresponding storage other wise search all storages.
if theme_dir in themes:
theme = themes[theme_dir]
path = "/".join(path.split("/")[1:])
match = self.find_in_theme(theme.theme_dir, path)
if match:
if not all:
return match
matches.append(match)
return matches
def find_in_theme(self, theme, path):
"""
Find a requested static file in an theme's static locations.
"""
storage = self.storages.get(theme, None)
if storage:
# only try to find a file if the source dir actually exists
if storage.exists(path):
matched_path = storage.path(path)
if matched_path:
return matched_path