From 4336f5f06f61de30ae3fa54650fce63a9d5ef5be Mon Sep 17 00:00:00 2001 From: ttt Date: Sat, 13 May 2017 00:29:47 +0530 Subject: added all server files --- .../django/contrib/staticfiles/__init__.py | 0 .../django/contrib/staticfiles/finders.py | 266 +++++++++++++++++ .../django/contrib/staticfiles/handlers.py | 68 +++++ .../contrib/staticfiles/management/__init__.py | 0 .../staticfiles/management/commands/__init__.py | 0 .../management/commands/collectstatic.py | 319 +++++++++++++++++++++ .../staticfiles/management/commands/findstatic.py | 34 +++ .../staticfiles/management/commands/runserver.py | 29 ++ .../django/contrib/staticfiles/models.py | 0 .../django/contrib/staticfiles/storage.py | 313 ++++++++++++++++++++ .../contrib/staticfiles/templatetags/__init__.py | 0 .../staticfiles/templatetags/staticfiles.py | 37 +++ .../django/contrib/staticfiles/urls.py | 16 ++ .../django/contrib/staticfiles/utils.py | 57 ++++ .../django/contrib/staticfiles/views.py | 41 +++ 15 files changed, 1180 insertions(+) create mode 100644 lib/python2.7/site-packages/django/contrib/staticfiles/__init__.py create mode 100644 lib/python2.7/site-packages/django/contrib/staticfiles/finders.py create mode 100644 lib/python2.7/site-packages/django/contrib/staticfiles/handlers.py create mode 100644 lib/python2.7/site-packages/django/contrib/staticfiles/management/__init__.py create mode 100644 lib/python2.7/site-packages/django/contrib/staticfiles/management/commands/__init__.py create mode 100644 lib/python2.7/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py create mode 100644 lib/python2.7/site-packages/django/contrib/staticfiles/management/commands/findstatic.py create mode 100644 lib/python2.7/site-packages/django/contrib/staticfiles/management/commands/runserver.py create mode 100644 lib/python2.7/site-packages/django/contrib/staticfiles/models.py create mode 100644 lib/python2.7/site-packages/django/contrib/staticfiles/storage.py create mode 100644 lib/python2.7/site-packages/django/contrib/staticfiles/templatetags/__init__.py create mode 100644 lib/python2.7/site-packages/django/contrib/staticfiles/templatetags/staticfiles.py create mode 100644 lib/python2.7/site-packages/django/contrib/staticfiles/urls.py create mode 100644 lib/python2.7/site-packages/django/contrib/staticfiles/utils.py create mode 100644 lib/python2.7/site-packages/django/contrib/staticfiles/views.py (limited to 'lib/python2.7/site-packages/django/contrib/staticfiles') diff --git a/lib/python2.7/site-packages/django/contrib/staticfiles/__init__.py b/lib/python2.7/site-packages/django/contrib/staticfiles/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lib/python2.7/site-packages/django/contrib/staticfiles/finders.py b/lib/python2.7/site-packages/django/contrib/staticfiles/finders.py new file mode 100644 index 0000000..6dfa31b --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/staticfiles/finders.py @@ -0,0 +1,266 @@ +import os +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured +from django.core.files.storage import default_storage, Storage, FileSystemStorage +from django.utils.datastructures import SortedDict +from django.utils.functional import empty, memoize, LazyObject +from django.utils.module_loading import import_by_path +from django.utils._os import safe_join +from django.utils import six + +from django.contrib.staticfiles import utils +from django.contrib.staticfiles.storage import AppStaticStorage + +_finders = SortedDict() + + +class BaseFinder(object): + """ + A base file finder to be used for custom staticfiles finder classes. + """ + def find(self, path, all=False): + """ + Given a relative file path this ought to find an + absolute file path. + + If the ``all`` parameter is ``False`` (default) only + the first found file path will be returned; if set + to ``True`` a list of all found files paths is returned. + """ + raise NotImplementedError() + + def list(self, ignore_patterns): + """ + Given an optional list of paths to ignore, this should return + a two item iterable consisting of the relative path and storage + instance. + """ + raise NotImplementedError() + + +class FileSystemFinder(BaseFinder): + """ + A static files finder that uses the ``STATICFILES_DIRS`` setting + to locate files. + """ + def __init__(self, apps=None, *args, **kwargs): + # List of locations with static files + self.locations = [] + # Maps dir paths to an appropriate storage instance + self.storages = SortedDict() + if not isinstance(settings.STATICFILES_DIRS, (list, tuple)): + raise ImproperlyConfigured( + "Your STATICFILES_DIRS setting is not a tuple or list; " + "perhaps you forgot a trailing comma?") + for root in settings.STATICFILES_DIRS: + if isinstance(root, (list, tuple)): + prefix, root = root + else: + prefix = '' + if settings.STATIC_ROOT and os.path.abspath(settings.STATIC_ROOT) == os.path.abspath(root): + raise ImproperlyConfigured( + "The STATICFILES_DIRS setting should " + "not contain the STATIC_ROOT setting") + if (prefix, root) not in self.locations: + self.locations.append((prefix, root)) + for prefix, root in self.locations: + filesystem_storage = FileSystemStorage(location=root) + filesystem_storage.prefix = prefix + self.storages[root] = filesystem_storage + super(FileSystemFinder, self).__init__(*args, **kwargs) + + def find(self, path, all=False): + """ + Looks for files in the extra locations + as defined in ``STATICFILES_DIRS``. + """ + matches = [] + for prefix, root in self.locations: + matched_path = self.find_location(root, path, prefix) + if matched_path: + if not all: + return matched_path + matches.append(matched_path) + return matches + + def find_location(self, root, path, prefix=None): + """ + Finds a requested static file in a location, returning the found + absolute path (or ``None`` if no match). + """ + if prefix: + prefix = '%s%s' % (prefix, os.sep) + if not path.startswith(prefix): + return None + path = path[len(prefix):] + path = safe_join(root, path) + if os.path.exists(path): + return path + + def list(self, ignore_patterns): + """ + List all files in all locations. + """ + for prefix, root in self.locations: + storage = self.storages[root] + for path in utils.get_files(storage, ignore_patterns): + yield path, storage + + +class AppDirectoriesFinder(BaseFinder): + """ + A static files finder that looks in the directory of each app as + specified in the source_dir attribute of the given storage class. + """ + storage_class = AppStaticStorage + + def __init__(self, apps=None, *args, **kwargs): + # The list of apps that are handled + self.apps = [] + # Mapping of app module paths to storage instances + self.storages = SortedDict() + if apps is None: + apps = settings.INSTALLED_APPS + for app in apps: + app_storage = self.storage_class(app) + if os.path.isdir(app_storage.location): + self.storages[app] = app_storage + if app not in self.apps: + self.apps.append(app) + super(AppDirectoriesFinder, 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): + """ + Looks for files in the app directories. + """ + matches = [] + for app in self.apps: + match = self.find_in_app(app, path) + if match: + if not all: + return match + matches.append(match) + return matches + + def find_in_app(self, app, path): + """ + Find a requested static file in an app's static locations. + """ + storage = self.storages.get(app, None) + if storage: + if storage.prefix: + prefix = '%s%s' % (storage.prefix, os.sep) + if not path.startswith(prefix): + return None + path = path[len(prefix):] + # 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 + + +class BaseStorageFinder(BaseFinder): + """ + A base static files finder to be used to extended + with an own storage class. + """ + storage = None + + def __init__(self, storage=None, *args, **kwargs): + if storage is not None: + self.storage = storage + if self.storage is None: + raise ImproperlyConfigured("The staticfiles storage finder %r " + "doesn't have a storage class " + "assigned." % self.__class__) + # Make sure we have an storage instance here. + if not isinstance(self.storage, (Storage, LazyObject)): + self.storage = self.storage() + super(BaseStorageFinder, self).__init__(*args, **kwargs) + + def find(self, path, all=False): + """ + Looks for files in the default file storage, if it's local. + """ + try: + self.storage.path('') + except NotImplementedError: + pass + else: + if self.storage.exists(path): + match = self.storage.path(path) + if all: + match = [match] + return match + return [] + + def list(self, ignore_patterns): + """ + List all files of the storage. + """ + for path in utils.get_files(self.storage, ignore_patterns): + yield path, self.storage + + +class DefaultStorageFinder(BaseStorageFinder): + """ + A static files finder that uses the default storage backend. + """ + storage = default_storage + + def __init__(self, *args, **kwargs): + super(DefaultStorageFinder, self).__init__(*args, **kwargs) + base_location = getattr(self.storage, 'base_location', empty) + if not base_location: + raise ImproperlyConfigured("The storage backend of the " + "staticfiles finder %r doesn't have " + "a valid location." % self.__class__) + + +def find(path, all=False): + """ + Find a static file with the given path using all enabled finders. + + If ``all`` is ``False`` (default), return the first matching + absolute path (or ``None`` if no match). Otherwise return a list. + """ + matches = [] + for finder in get_finders(): + result = finder.find(path, all=all) + if not all and result: + return result + if not isinstance(result, (list, tuple)): + result = [result] + matches.extend(result) + if matches: + return matches + # No match. + return [] if all else None + + +def get_finders(): + for finder_path in settings.STATICFILES_FINDERS: + yield get_finder(finder_path) + + +def _get_finder(import_path): + """ + Imports the staticfiles finder class described by import_path, where + import_path is the full Python path to the class. + """ + Finder = import_by_path(import_path) + if not issubclass(Finder, BaseFinder): + raise ImproperlyConfigured('Finder "%s" is not a subclass of "%s"' % + (Finder, BaseFinder)) + return Finder() +get_finder = memoize(_get_finder, _finders, 1) diff --git a/lib/python2.7/site-packages/django/contrib/staticfiles/handlers.py b/lib/python2.7/site-packages/django/contrib/staticfiles/handlers.py new file mode 100644 index 0000000..e6db3dc --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/staticfiles/handlers.py @@ -0,0 +1,68 @@ +from django.conf import settings +from django.core.handlers.base import get_path_info +from django.core.handlers.wsgi import WSGIHandler +from django.utils.six.moves.urllib.parse import urlparse +from django.utils.six.moves.urllib.request import url2pathname + +from django.contrib.staticfiles import utils +from django.contrib.staticfiles.views import serve + +class StaticFilesHandler(WSGIHandler): + """ + WSGI middleware that intercepts calls to the static files directory, as + defined by the STATIC_URL setting, and serves those files. + """ + def __init__(self, application, base_dir=None): + self.application = application + if base_dir: + self.base_dir = base_dir + else: + self.base_dir = self.get_base_dir() + self.base_url = urlparse(self.get_base_url()) + super(StaticFilesHandler, self).__init__() + + def get_base_dir(self): + return settings.STATIC_ROOT + + def get_base_url(self): + utils.check_settings() + return settings.STATIC_URL + + def _should_handle(self, path): + """ + Checks if the path should be handled. Ignores the path if: + + * the host is provided as part of the base_url + * the request's path isn't under the media path (or equal) + """ + return path.startswith(self.base_url[2]) and not self.base_url[1] + + def file_path(self, url): + """ + Returns the relative path to the media file on disk for the given URL. + """ + relative_url = url[len(self.base_url[2]):] + return url2pathname(relative_url) + + def serve(self, request): + """ + Actually serves the request path. + """ + return serve(request, self.file_path(request.path), insecure=True) + + def get_response(self, request): + from django.http import Http404 + + if self._should_handle(request.path): + try: + return self.serve(request) + except Http404 as e: + if settings.DEBUG: + from django.views import debug + return debug.technical_404_response(request, e) + return super(StaticFilesHandler, self).get_response(request) + + def __call__(self, environ, start_response): + if not self._should_handle(get_path_info(environ)): + return self.application(environ, start_response) + return super(StaticFilesHandler, self).__call__(environ, start_response) diff --git a/lib/python2.7/site-packages/django/contrib/staticfiles/management/__init__.py b/lib/python2.7/site-packages/django/contrib/staticfiles/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lib/python2.7/site-packages/django/contrib/staticfiles/management/commands/__init__.py b/lib/python2.7/site-packages/django/contrib/staticfiles/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lib/python2.7/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py b/lib/python2.7/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py new file mode 100644 index 0000000..90552b1 --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py @@ -0,0 +1,319 @@ +from __future__ import unicode_literals + +import os +import sys +from optparse import make_option + +from django.core.files.storage import FileSystemStorage +from django.core.management.base import CommandError, NoArgsCommand +from django.utils.encoding import smart_text +from django.utils.datastructures import SortedDict +from django.utils.functional import LazyObject +from django.utils.six.moves import input + +from django.contrib.staticfiles import finders, storage + + +class Command(NoArgsCommand): + """ + Command that allows to copy or symlink static files from different + locations to the settings.STATIC_ROOT. + """ + option_list = NoArgsCommand.option_list + ( + make_option('--noinput', + action='store_false', dest='interactive', default=True, + help="Do NOT prompt the user for input of any kind."), + make_option('--no-post-process', + action='store_false', dest='post_process', default=True, + help="Do NOT post process collected files."), + make_option('-i', '--ignore', action='append', default=[], + dest='ignore_patterns', metavar='PATTERN', + help="Ignore files or directories matching this glob-style " + "pattern. Use multiple times to ignore more."), + make_option('-n', '--dry-run', + action='store_true', dest='dry_run', default=False, + help="Do everything except modify the filesystem."), + make_option('-c', '--clear', + action='store_true', dest='clear', default=False, + help="Clear the existing files using the storage " + "before trying to copy or link the original file."), + make_option('-l', '--link', + action='store_true', dest='link', default=False, + help="Create a symbolic link to each file instead of copying."), + make_option('--no-default-ignore', action='store_false', + dest='use_default_ignore_patterns', default=True, + help="Don't ignore the common private glob-style patterns 'CVS', " + "'.*' and '*~'."), + ) + help = "Collect static files in a single location." + requires_model_validation = False + + def __init__(self, *args, **kwargs): + super(NoArgsCommand, self).__init__(*args, **kwargs) + self.copied_files = [] + self.symlinked_files = [] + self.unmodified_files = [] + self.post_processed_files = [] + self.storage = storage.staticfiles_storage + try: + self.storage.path('') + except NotImplementedError: + self.local = False + else: + self.local = True + + def set_options(self, **options): + """ + Set instance variables based on an options dict + """ + self.interactive = options['interactive'] + self.verbosity = int(options.get('verbosity', 1)) + self.symlink = options['link'] + self.clear = options['clear'] + self.dry_run = options['dry_run'] + ignore_patterns = options['ignore_patterns'] + if options['use_default_ignore_patterns']: + ignore_patterns += ['CVS', '.*', '*~'] + self.ignore_patterns = list(set(ignore_patterns)) + self.post_process = options['post_process'] + + def collect(self): + """ + Perform the bulk of the work of collectstatic. + + Split off from handle_noargs() to facilitate testing. + """ + if self.symlink: + if sys.platform == 'win32': + raise CommandError("Symlinking is not supported by this " + "platform (%s)." % sys.platform) + if not self.local: + raise CommandError("Can't symlink to a remote destination.") + + if self.clear: + self.clear_dir('') + + if self.symlink: + handler = self.link_file + else: + handler = self.copy_file + + found_files = SortedDict() + for finder in finders.get_finders(): + for path, storage in finder.list(self.ignore_patterns): + # Prefix the relative path if the source storage contains it + if getattr(storage, 'prefix', None): + prefixed_path = os.path.join(storage.prefix, path) + else: + prefixed_path = path + + if prefixed_path not in found_files: + found_files[prefixed_path] = (storage, path) + handler(path, prefixed_path, storage) + + # Here we check if the storage backend has a post_process + # method and pass it the list of modified files. + if self.post_process and hasattr(self.storage, 'post_process'): + processor = self.storage.post_process(found_files, + dry_run=self.dry_run) + for original_path, processed_path, processed in processor: + if isinstance(processed, Exception): + self.stderr.write("Post-processing '%s' failed!" % original_path) + # Add a blank line before the traceback, otherwise it's + # too easy to miss the relevant part of the error message. + self.stderr.write("") + raise processed + if processed: + self.log("Post-processed '%s' as '%s'" % + (original_path, processed_path), level=1) + self.post_processed_files.append(original_path) + else: + self.log("Skipped post-processing '%s'" % original_path) + + return { + 'modified': self.copied_files + self.symlinked_files, + 'unmodified': self.unmodified_files, + 'post_processed': self.post_processed_files, + } + + def handle_noargs(self, **options): + self.set_options(**options) + + message = ['\n'] + if self.dry_run: + message.append( + 'You have activated the --dry-run option so no files will be modified.\n\n' + ) + + message.append( + 'You have requested to collect static files at the destination\n' + 'location as specified in your settings' + ) + + if self.is_local_storage() and self.storage.location: + destination_path = self.storage.location + message.append(':\n\n %s\n\n' % destination_path) + else: + destination_path = None + message.append('.\n\n') + + if self.clear: + message.append('This will DELETE EXISTING FILES!\n') + else: + message.append('This will overwrite existing files!\n') + + message.append( + 'Are you sure you want to do this?\n\n' + "Type 'yes' to continue, or 'no' to cancel: " + ) + + if self.interactive and input(''.join(message)) != 'yes': + raise CommandError("Collecting static files cancelled.") + + collected = self.collect() + modified_count = len(collected['modified']) + unmodified_count = len(collected['unmodified']) + post_processed_count = len(collected['post_processed']) + + if self.verbosity >= 1: + template = ("\n%(modified_count)s %(identifier)s %(action)s" + "%(destination)s%(unmodified)s%(post_processed)s.\n") + summary = template % { + 'modified_count': modified_count, + 'identifier': 'static file' + ('' if modified_count == 1 else 's'), + 'action': 'symlinked' if self.symlink else 'copied', + 'destination': (" to '%s'" % destination_path if destination_path else ''), + 'unmodified': (', %s unmodified' % unmodified_count if collected['unmodified'] else ''), + 'post_processed': (collected['post_processed'] and + ', %s post-processed' + % post_processed_count or ''), + } + self.stdout.write(summary) + + def log(self, msg, level=2): + """ + Small log helper + """ + if self.verbosity >= level: + self.stdout.write(msg) + + def is_local_storage(self): + if issubclass(self.storage.__class__, LazyObject): + storage = self.storage._wrapped + else: + storage = self.storage + return isinstance(storage, FileSystemStorage) + + def clear_dir(self, path): + """ + Deletes the given relative path using the destination storage backend. + """ + dirs, files = self.storage.listdir(path) + for f in files: + fpath = os.path.join(path, f) + if self.dry_run: + self.log("Pretending to delete '%s'" % + smart_text(fpath), level=1) + else: + self.log("Deleting '%s'" % smart_text(fpath), level=1) + self.storage.delete(fpath) + for d in dirs: + self.clear_dir(os.path.join(path, d)) + + def delete_file(self, path, prefixed_path, source_storage): + """ + Checks if the target file should be deleted if it already exists + """ + if self.storage.exists(prefixed_path): + try: + # When was the target file modified last time? + target_last_modified = \ + self.storage.modified_time(prefixed_path) + except (OSError, NotImplementedError, AttributeError): + # The storage doesn't support ``modified_time`` or failed + pass + else: + try: + # When was the source file modified last time? + source_last_modified = source_storage.modified_time(path) + except (OSError, NotImplementedError, AttributeError): + pass + else: + # The full path of the target file + if self.local: + full_path = self.storage.path(prefixed_path) + else: + full_path = None + # Skip the file if the source file is younger + # Avoid sub-second precision (see #14665, #19540) + if (target_last_modified.replace(microsecond=0) + >= source_last_modified.replace(microsecond=0)): + if not ((self.symlink and full_path + and not os.path.islink(full_path)) or + (not self.symlink and full_path + and os.path.islink(full_path))): + if prefixed_path not in self.unmodified_files: + self.unmodified_files.append(prefixed_path) + self.log("Skipping '%s' (not modified)" % path) + return False + # Then delete the existing file if really needed + if self.dry_run: + self.log("Pretending to delete '%s'" % path) + else: + self.log("Deleting '%s'" % path) + self.storage.delete(prefixed_path) + return True + + def link_file(self, path, prefixed_path, source_storage): + """ + Attempt to link ``path`` + """ + # Skip this file if it was already copied earlier + if prefixed_path in self.symlinked_files: + return self.log("Skipping '%s' (already linked earlier)" % path) + # Delete the target file if needed or break + if not self.delete_file(path, prefixed_path, source_storage): + return + # The full path of the source file + source_path = source_storage.path(path) + # Finally link the file + if self.dry_run: + self.log("Pretending to link '%s'" % source_path, level=1) + else: + self.log("Linking '%s'" % source_path, level=1) + full_path = self.storage.path(prefixed_path) + try: + os.makedirs(os.path.dirname(full_path)) + except OSError: + pass + os.symlink(source_path, full_path) + if prefixed_path not in self.symlinked_files: + self.symlinked_files.append(prefixed_path) + + def copy_file(self, path, prefixed_path, source_storage): + """ + Attempt to copy ``path`` with storage + """ + # Skip this file if it was already copied earlier + if prefixed_path in self.copied_files: + return self.log("Skipping '%s' (already copied earlier)" % path) + # Delete the target file if needed or break + if not self.delete_file(path, prefixed_path, source_storage): + return + # The full path of the source file + source_path = source_storage.path(path) + # Finally start copying + if self.dry_run: + self.log("Pretending to copy '%s'" % source_path, level=1) + else: + self.log("Copying '%s'" % source_path, level=1) + if self.local: + full_path = self.storage.path(prefixed_path) + try: + os.makedirs(os.path.dirname(full_path)) + except OSError: + pass + with source_storage.open(path) as source_file: + self.storage.save(prefixed_path, source_file) + if not prefixed_path in self.copied_files: + self.copied_files.append(prefixed_path) diff --git a/lib/python2.7/site-packages/django/contrib/staticfiles/management/commands/findstatic.py b/lib/python2.7/site-packages/django/contrib/staticfiles/management/commands/findstatic.py new file mode 100644 index 0000000..eaf63f7 --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/staticfiles/management/commands/findstatic.py @@ -0,0 +1,34 @@ +from __future__ import unicode_literals + +import os +from optparse import make_option +from django.core.management.base import LabelCommand +from django.utils.encoding import force_text + +from django.contrib.staticfiles import finders + +class Command(LabelCommand): + help = "Finds the absolute paths for the given static file(s)." + args = "[file ...]" + label = 'static file' + option_list = LabelCommand.option_list + ( + make_option('--first', action='store_false', dest='all', default=True, + help="Only return the first match for each static file."), + ) + + def handle_label(self, path, **options): + verbosity = int(options.get('verbosity', 1)) + result = finders.find(path, all=options['all']) + path = force_text(path) + if result: + if not isinstance(result, (list, tuple)): + result = [result] + result = (force_text(os.path.realpath(path)) for path in result) + if verbosity >= 1: + output = '\n '.join(result) + return "Found '%s' here:\n %s" % (path, output) + else: + return '\n'.join(result) + else: + if verbosity >= 1: + self.stderr.write("No matching file found for '%s'." % path) diff --git a/lib/python2.7/site-packages/django/contrib/staticfiles/management/commands/runserver.py b/lib/python2.7/site-packages/django/contrib/staticfiles/management/commands/runserver.py new file mode 100644 index 0000000..0f9e39f --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/staticfiles/management/commands/runserver.py @@ -0,0 +1,29 @@ +from optparse import make_option + +from django.conf import settings +from django.core.management.commands.runserver import Command as RunserverCommand + +from django.contrib.staticfiles.handlers import StaticFilesHandler + +class Command(RunserverCommand): + option_list = RunserverCommand.option_list + ( + make_option('--nostatic', action="store_false", dest='use_static_handler', default=True, + help='Tells Django to NOT automatically serve static files at STATIC_URL.'), + make_option('--insecure', action="store_true", dest='insecure_serving', default=False, + help='Allows serving static files even if DEBUG is False.'), + ) + help = "Starts a lightweight Web server for development and also serves static files." + + def get_handler(self, *args, **options): + """ + Returns the static files serving handler wrapping the default handler, + if static files should be served. Otherwise just returns the default + handler. + + """ + handler = super(Command, self).get_handler(*args, **options) + use_static_handler = options.get('use_static_handler', True) + insecure_serving = options.get('insecure_serving', False) + if use_static_handler and (settings.DEBUG or insecure_serving): + return StaticFilesHandler(handler) + return handler diff --git a/lib/python2.7/site-packages/django/contrib/staticfiles/models.py b/lib/python2.7/site-packages/django/contrib/staticfiles/models.py new file mode 100644 index 0000000..e69de29 diff --git a/lib/python2.7/site-packages/django/contrib/staticfiles/storage.py b/lib/python2.7/site-packages/django/contrib/staticfiles/storage.py new file mode 100644 index 0000000..7e0b8f0 --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/staticfiles/storage.py @@ -0,0 +1,313 @@ +from __future__ import unicode_literals +import hashlib +import os +import posixpath +import re + +from django.conf import settings +from django.core.cache import (get_cache, InvalidCacheBackendError, + cache as default_cache) +from django.core.exceptions import ImproperlyConfigured +from django.core.files.base import ContentFile +from django.core.files.storage import FileSystemStorage, get_storage_class +from django.utils.datastructures import SortedDict +from django.utils.encoding import force_bytes, force_text +from django.utils.functional import LazyObject +from django.utils.importlib import import_module +from django.utils.six.moves.urllib.parse import unquote, urlsplit, urlunsplit, urldefrag +from django.utils._os import upath + +from django.contrib.staticfiles.utils import check_settings, matches_patterns + + +class StaticFilesStorage(FileSystemStorage): + """ + Standard file system storage for static files. + + The defaults for ``location`` and ``base_url`` are + ``STATIC_ROOT`` and ``STATIC_URL``. + """ + 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 + check_settings(base_url) + super(StaticFilesStorage, self).__init__(location, base_url, + *args, **kwargs) + # FileSystemStorage fallbacks to MEDIA_ROOT when location + # is empty, so we restore the empty value. + if not location: + self.base_location = None + self.location = None + + def path(self, name): + if not self.location: + raise ImproperlyConfigured("You're using the staticfiles app " + "without having set the STATIC_ROOT " + "setting to a filesystem path.") + return super(StaticFilesStorage, self).path(name) + + +class CachedFilesMixin(object): + default_template = """url("%s")""" + patterns = ( + ("*.css", ( + r"""(url\(['"]{0,1}\s*(.*?)["']{0,1}\))""", + (r"""(@import\s*["']\s*(.*?)["'])""", """@import url("%s")"""), + )), + ) + + def __init__(self, *args, **kwargs): + super(CachedFilesMixin, self).__init__(*args, **kwargs) + try: + self.cache = get_cache('staticfiles') + except InvalidCacheBackendError: + # Use the default backend + self.cache = default_cache + self._patterns = SortedDict() + for extension, patterns in self.patterns: + for pattern in patterns: + if isinstance(pattern, (tuple, list)): + pattern, template = pattern + else: + template = self.default_template + compiled = re.compile(pattern, re.IGNORECASE) + self._patterns.setdefault(extension, []).append((compiled, template)) + + def file_hash(self, name, content=None): + """ + Retuns a hash of the file with the given name and optional content. + """ + if content is None: + return None + md5 = hashlib.md5() + for chunk in content.chunks(): + md5.update(chunk) + return md5.hexdigest()[:12] + + def hashed_name(self, name, content=None): + parsed_name = urlsplit(unquote(name)) + clean_name = parsed_name.path.strip() + opened = False + if content is None: + if not self.exists(clean_name): + raise ValueError("The file '%s' could not be found with %r." % + (clean_name, self)) + try: + content = self.open(clean_name) + except IOError: + # Handle directory paths and fragments + return name + opened = True + try: + file_hash = self.file_hash(clean_name, content) + finally: + if opened: + content.close() + path, filename = os.path.split(clean_name) + root, ext = os.path.splitext(filename) + if file_hash is not None: + file_hash = ".%s" % file_hash + hashed_name = os.path.join(path, "%s%s%s" % + (root, file_hash, ext)) + unparsed_name = list(parsed_name) + unparsed_name[2] = hashed_name + # Special casing for a @font-face hack, like url(myfont.eot?#iefix") + # http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax + if '?#' in name and not unparsed_name[3]: + unparsed_name[2] += '?' + return urlunsplit(unparsed_name) + + def cache_key(self, name): + return 'staticfiles:%s' % hashlib.md5(force_bytes(name)).hexdigest() + + def url(self, name, force=False): + """ + Returns the real URL in DEBUG mode. + """ + if settings.DEBUG and not force: + hashed_name, fragment = name, '' + else: + clean_name, fragment = urldefrag(name) + if urlsplit(clean_name).path.endswith('/'): # don't hash paths + hashed_name = name + else: + cache_key = self.cache_key(name) + hashed_name = self.cache.get(cache_key) + if hashed_name is None: + hashed_name = self.hashed_name(clean_name).replace('\\', '/') + # set the cache if there was a miss + # (e.g. if cache server goes down) + self.cache.set(cache_key, hashed_name) + + final_url = super(CachedFilesMixin, self).url(hashed_name) + + # Special casing for a @font-face hack, like url(myfont.eot?#iefix") + # http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax + query_fragment = '?#' in name # [sic!] + if fragment or query_fragment: + urlparts = list(urlsplit(final_url)) + if fragment and not urlparts[4]: + urlparts[4] = fragment + if query_fragment and not urlparts[3]: + urlparts[2] += '?' + final_url = urlunsplit(urlparts) + + return unquote(final_url) + + def url_converter(self, name, template=None): + """ + Returns the custom URL converter for the given file name. + """ + if template is None: + template = self.default_template + + def converter(matchobj): + """ + Converts the matched URL depending on the parent level (`..`) + and returns the normalized and hashed URL using the url method + of the storage. + """ + matched, url = matchobj.groups() + # Completely ignore http(s) prefixed URLs, + # fragments and data-uri URLs + if url.startswith(('#', 'http:', 'https:', 'data:', '//')): + return matched + name_parts = name.split(os.sep) + # Using posix normpath here to remove duplicates + url = posixpath.normpath(url) + url_parts = url.split('/') + parent_level, sub_level = url.count('..'), url.count('/') + if url.startswith('/'): + sub_level -= 1 + url_parts = url_parts[1:] + if parent_level or not url.startswith('/'): + start, end = parent_level + 1, parent_level + else: + if sub_level: + if sub_level == 1: + parent_level -= 1 + start, end = parent_level, 1 + else: + start, end = 1, sub_level - 1 + joined_result = '/'.join(name_parts[:-start] + url_parts[end:]) + hashed_url = self.url(unquote(joined_result), force=True) + file_name = hashed_url.split('/')[-1:] + relative_url = '/'.join(url.split('/')[:-1] + file_name) + + # Return the hashed version to the file + return template % unquote(relative_url) + + return converter + + def post_process(self, paths, dry_run=False, **options): + """ + Post process the given SortedDict of files (called from collectstatic). + + Processing is actually two separate operations: + + 1. renaming files to include a hash of their content for cache-busting, + and copying those files to the target storage. + 2. adjusting files which contain references to other files so they + refer to the cache-busting filenames. + + If either of these are performed on a file, then that file is considered + post-processed. + """ + # don't even dare to process the files if we're in dry run mode + if dry_run: + return + + # where to store the new paths + hashed_paths = {} + + # build a list of adjustable files + matches = lambda path: matches_patterns(path, self._patterns.keys()) + adjustable_paths = [path for path in paths if matches(path)] + + # then sort the files by the directory level + path_level = lambda name: len(name.split(os.sep)) + for name in sorted(paths.keys(), key=path_level, reverse=True): + + # use the original, local file, not the copied-but-unprocessed + # file, which might be somewhere far away, like S3 + storage, path = paths[name] + with storage.open(path) as original_file: + + # generate the hash with the original content, even for + # adjustable files. + hashed_name = self.hashed_name(name, original_file) + + # then get the original's file content.. + if hasattr(original_file, 'seek'): + original_file.seek(0) + + hashed_file_exists = self.exists(hashed_name) + processed = False + + # ..to apply each replacement pattern to the content + if name in adjustable_paths: + content = original_file.read().decode(settings.FILE_CHARSET) + for patterns in self._patterns.values(): + for pattern, template in patterns: + converter = self.url_converter(name, template) + try: + content = pattern.sub(converter, content) + except ValueError as exc: + yield name, None, exc + if hashed_file_exists: + self.delete(hashed_name) + # then save the processed result + content_file = ContentFile(force_bytes(content)) + saved_name = self._save(hashed_name, content_file) + hashed_name = force_text(saved_name.replace('\\', '/')) + processed = True + else: + # or handle the case in which neither processing nor + # a change to the original file happened + if not hashed_file_exists: + processed = True + saved_name = self._save(hashed_name, original_file) + hashed_name = force_text(saved_name.replace('\\', '/')) + + # and then set the cache accordingly + hashed_paths[self.cache_key(name.replace('\\', '/'))] = hashed_name + yield name, hashed_name, processed + + # Finally set the cache + self.cache.set_many(hashed_paths) + + +class CachedStaticFilesStorage(CachedFilesMixin, StaticFilesStorage): + """ + A static file system storage backend which also saves + hashed copies of the files it saves. + """ + pass + + +class AppStaticStorage(FileSystemStorage): + """ + A file system storage backend that takes an app module and works + for the ``static`` directory of it. + """ + prefix = None + source_dir = 'static' + + def __init__(self, app, *args, **kwargs): + """ + Returns a static file storage if available in the given app. + """ + # app is the actual app module + mod = import_module(app) + mod_path = os.path.dirname(upath(mod.__file__)) + location = os.path.join(mod_path, self.source_dir) + super(AppStaticStorage, self).__init__(location, *args, **kwargs) + + +class ConfiguredStorage(LazyObject): + def _setup(self): + self._wrapped = get_storage_class(settings.STATICFILES_STORAGE)() + +staticfiles_storage = ConfiguredStorage() diff --git a/lib/python2.7/site-packages/django/contrib/staticfiles/templatetags/__init__.py b/lib/python2.7/site-packages/django/contrib/staticfiles/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lib/python2.7/site-packages/django/contrib/staticfiles/templatetags/staticfiles.py b/lib/python2.7/site-packages/django/contrib/staticfiles/templatetags/staticfiles.py new file mode 100644 index 0000000..ab92275 --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/staticfiles/templatetags/staticfiles.py @@ -0,0 +1,37 @@ +from django import template +from django.templatetags.static import StaticNode +from django.contrib.staticfiles.storage import staticfiles_storage + +register = template.Library() + + +class StaticFilesNode(StaticNode): + + def url(self, context): + path = self.path.resolve(context) + return staticfiles_storage.url(path) + + +@register.tag('static') +def do_static(parser, token): + """ + A template tag that returns the URL to a file + using staticfiles' storage backend + + Usage:: + + {% static path [as varname] %} + + Examples:: + + {% static "myapp/css/base.css" %} + {% static variable_with_path %} + {% static "myapp/css/base.css" as admin_base_css %} + {% static variable_with_path as varname %} + + """ + return StaticFilesNode.handle_token(parser, token) + + +def static(path): + return staticfiles_storage.url(path) diff --git a/lib/python2.7/site-packages/django/contrib/staticfiles/urls.py b/lib/python2.7/site-packages/django/contrib/staticfiles/urls.py new file mode 100644 index 0000000..04062c1 --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/staticfiles/urls.py @@ -0,0 +1,16 @@ +from django.conf import settings +from django.conf.urls.static import static + +urlpatterns = [] + +def staticfiles_urlpatterns(prefix=None): + """ + Helper function to return a URL pattern for serving static files. + """ + if prefix is None: + prefix = settings.STATIC_URL + return static(prefix, view='django.contrib.staticfiles.views.serve') + +# Only append if urlpatterns are empty +if settings.DEBUG and not urlpatterns: + urlpatterns += staticfiles_urlpatterns() diff --git a/lib/python2.7/site-packages/django/contrib/staticfiles/utils.py b/lib/python2.7/site-packages/django/contrib/staticfiles/utils.py new file mode 100644 index 0000000..f500ed6 --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/staticfiles/utils.py @@ -0,0 +1,57 @@ +import os +import fnmatch +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured + +def matches_patterns(path, patterns=None): + """ + Return True or False depending on whether the ``path`` should be + ignored (if it matches any pattern in ``ignore_patterns``). + """ + if patterns is None: + patterns = [] + for pattern in patterns: + if fnmatch.fnmatchcase(path, pattern): + return True + return False + +def get_files(storage, ignore_patterns=None, location=''): + """ + Recursively walk the storage directories yielding the paths + of all files that should be copied. + """ + if ignore_patterns is None: + ignore_patterns = [] + directories, files = storage.listdir(location) + for fn in files: + if matches_patterns(fn, ignore_patterns): + continue + if location: + fn = os.path.join(location, fn) + yield fn + for dir in directories: + if matches_patterns(dir, ignore_patterns): + continue + if location: + dir = os.path.join(location, dir) + for fn in get_files(storage, ignore_patterns, dir): + yield fn + +def check_settings(base_url=None): + """ + Checks if the staticfiles settings have sane values. + + """ + if base_url is None: + base_url = settings.STATIC_URL + if not base_url: + raise ImproperlyConfigured( + "You're using the staticfiles app " + "without having set the required STATIC_URL setting.") + if settings.MEDIA_URL == base_url: + raise ImproperlyConfigured("The MEDIA_URL and STATIC_URL " + "settings must have different values") + if ((settings.MEDIA_ROOT and settings.STATIC_ROOT) and + (settings.MEDIA_ROOT == settings.STATIC_ROOT)): + raise ImproperlyConfigured("The MEDIA_ROOT and STATIC_ROOT " + "settings must have different values") diff --git a/lib/python2.7/site-packages/django/contrib/staticfiles/views.py b/lib/python2.7/site-packages/django/contrib/staticfiles/views.py new file mode 100644 index 0000000..a7f9b0d --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/staticfiles/views.py @@ -0,0 +1,41 @@ +""" +Views and functions for serving static files. These are only to be used during +development, and SHOULD NOT be used in a production setting. + +""" +import os +import posixpath + +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured +from django.http import Http404 +from django.utils.six.moves.urllib.parse import unquote +from django.views import static + +from django.contrib.staticfiles import finders + +def serve(request, path, insecure=False, **kwargs): + """ + Serve static files below a given point in the directory structure or + from locations inferred from the staticfiles finders. + + To use, put a URL pattern such as:: + + (r'^(?P.*)$', 'django.contrib.staticfiles.views.serve') + + in your URLconf. + + It uses the django.views.static view to serve the found files. + """ + if not settings.DEBUG and not insecure: + raise ImproperlyConfigured("The staticfiles view can only be used in " + "debug mode or if the --insecure " + "option of 'runserver' is used") + normalized_path = posixpath.normpath(unquote(path)).lstrip('/') + absolute_path = finders.find(normalized_path) + if not absolute_path: + if path.endswith('/') or path == '': + raise Http404("Directory indexes are not allowed here.") + raise Http404("'%s' could not be found" % path) + document_root, path = os.path.split(absolute_path) + return static.serve(request, path, document_root=document_root, **kwargs) -- cgit