<s> from __future__ import unicode_literals <EOL> import hashlib <EOL> import os <EOL> import posixpath <EOL> import re <EOL> from django . conf import settings <EOL> from django . core . cache import ( get_cache , InvalidCacheBackendError , <EOL> cache as default_cache ) <EOL> from django . core . exceptions import ImproperlyConfigured <EOL> from django . core . files . base import ContentFile <EOL> from django . core . files . storage import FileSystemStorage , get_storage_class <EOL> from django . utils . datastructures import SortedDict <EOL> from django . utils . encoding import force_bytes , force_text <EOL> from django . utils . functional import LazyObject <EOL> from django . utils . importlib import import_module <EOL> from django . utils . six . moves . urllib . parse import unquote , urlsplit , urlunsplit , urldefrag <EOL> from django . utils . _os import upath <EOL> from django . contrib . staticfiles . utils import check_settings , matches_patterns <EOL> class StaticFilesStorage ( FileSystemStorage ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , location = None , base_url = None , * args , ** kwargs ) : <EOL> if location is None : <EOL> location = settings . STATIC_ROOT <EOL> if base_url is None : <EOL> base_url = settings . STATIC_URL <EOL> check_settings ( base_url ) <EOL> super ( StaticFilesStorage , self ) . __init__ ( location , base_url , <EOL> * args , ** kwargs ) <EOL> if not location : <EOL> self . base_location = None <EOL> self . location = None <EOL> def path ( self , name ) : <EOL> if not self . location : <EOL> raise ImproperlyConfigured ( "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" ) <EOL> return super ( StaticFilesStorage , self ) . path ( name ) <EOL> class CachedFilesMixin ( object ) : <EOL> default_template = """<STR_LIT>""" <EOL> patterns = ( <EOL> ( "<STR_LIT>" , ( <EOL> r"""<STR_LIT>""" , <EOL> ( r"""<STR_LIT>""" , """<STR_LIT>""" ) , <EOL> ) ) , <EOL> ) <EOL> def __init__ ( self , * args , ** kwargs ) : <EOL> super ( CachedFilesMixin , self ) . __init__ ( * args , ** kwargs ) <EOL> try : <EOL> self . cache = get_cache ( '<STR_LIT>' ) <EOL> except InvalidCacheBackendError : <EOL> self . cache = default_cache <EOL> self . _patterns = SortedDict ( ) <EOL> for extension , patterns in self . patterns : <EOL> for pattern in patterns : <EOL> if isinstance ( pattern , ( tuple , list ) ) : <EOL> pattern , template = pattern <EOL> else : <EOL> template = self . default_template <EOL> compiled = re . compile ( pattern , re . IGNORECASE ) <EOL> self . _patterns . setdefault ( extension , [ ] ) . append ( ( compiled , template ) ) <EOL> def file_hash ( self , name , content = None ) : <EOL> """<STR_LIT>""" <EOL> if content is None : <EOL> return None <EOL> md5 = hashlib . md5 ( ) <EOL> for chunk in content . chunks ( ) : <EOL> md5 . update ( chunk ) <EOL> return md5 . hexdigest ( ) [ : <NUM_LIT:12> ] <EOL> def hashed_name ( self , name , content = None ) : <EOL> parsed_name = urlsplit ( unquote ( name ) ) <EOL> clean_name = parsed_name . path . strip ( ) <EOL> opened = False <EOL> if content is None : <EOL> if not self . exists ( clean_name ) : <EOL> raise ValueError ( "<STR_LIT>" % <EOL> ( clean_name , self ) ) <EOL> try : <EOL> content = self . open ( clean_name ) <EOL> except IOError : <EOL> return name <EOL> opened = True <EOL> try : <EOL> file_hash = self . file_hash ( clean_name , content ) <EOL> finally : <EOL> if opened : <EOL> content . close ( ) <EOL> path , filename = os . path . split ( clean_name ) <EOL> root , ext = os . path . splitext ( filename ) <EOL> if file_hash is not None : <EOL> file_hash = "<STR_LIT>" % file_hash <EOL> hashed_name = os . path . join ( path , "<STR_LIT>" % <EOL> ( root , file_hash , ext ) ) <EOL> unparsed_name = list ( parsed_name ) <EOL> unparsed_name [ <NUM_LIT:2> ] = hashed_name <EOL> if '<STR_LIT>' in name and not unparsed_name [ <NUM_LIT:3> ] : <EOL> unparsed_name [ <NUM_LIT:2> ] += '<STR_LIT:?>' <EOL> return urlunsplit ( unparsed_name ) <EOL> def cache_key ( self , name ) : <EOL> return '<STR_LIT>' % hashlib . md5 ( force_bytes ( name ) ) . hexdigest ( ) <EOL> def url ( self , name , force = False ) : <EOL> """<STR_LIT>""" <EOL> if settings . DEBUG and not force : <EOL> hashed_name , fragment = name , '<STR_LIT>' <EOL> else : <EOL> clean_name , fragment = urldefrag ( name ) <EOL> if urlsplit ( clean_name ) . path . endswith ( '<STR_LIT:/>' ) : <EOL> hashed_name = name <EOL> else : <EOL> cache_key = self . cache_key ( name ) <EOL> hashed_name = self . cache . get ( cache_key ) <EOL> if hashed_name is None : <EOL> hashed_name = self . hashed_name ( clean_name ) . replace ( '<STR_LIT:\\>' , '<STR_LIT:/>' ) <EOL> self . cache . set ( cache_key , hashed_name ) <EOL> final_url = super ( CachedFilesMixin , self ) . url ( hashed_name ) <EOL> query_fragment = '<STR_LIT>' in name <EOL> if fragment or query_fragment : <EOL> urlparts = list ( urlsplit ( final_url ) ) <EOL> if fragment and not urlparts [ <NUM_LIT:4> ] : <EOL> urlparts [ <NUM_LIT:4> ] = fragment <EOL> if query_fragment and not urlparts [ <NUM_LIT:3> ] : <EOL> urlparts [ <NUM_LIT:2> ] += '<STR_LIT:?>' <EOL> final_url = urlunsplit ( urlparts ) <EOL> return unquote ( final_url ) <EOL> def url_converter ( self , name , template = None ) : <EOL> """<STR_LIT>""" <EOL> if template is None : <EOL> template = self . default_template <EOL> def converter ( matchobj ) : <EOL> """<STR_LIT>""" <EOL> matched , url = matchobj . groups ( ) <EOL> if url . startswith ( ( '<STR_LIT:#>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ) ) : <EOL> return matched <EOL> name_parts = name . split ( os . sep ) <EOL> url = posixpath . normpath ( url ) <EOL> url_parts = url . split ( '<STR_LIT:/>' ) <EOL> parent_level , sub_level = url . count ( '<STR_LIT:..>' ) , url . count ( '<STR_LIT:/>' ) <EOL> if url . startswith ( '<STR_LIT:/>' ) : <EOL> sub_level -= <NUM_LIT:1> <EOL> url_parts = url_parts [ <NUM_LIT:1> : ] <EOL> if parent_level or not url . startswith ( '<STR_LIT:/>' ) : <EOL> start , end = parent_level + <NUM_LIT:1> , parent_level <EOL> else : <EOL> if sub_level : <EOL> if sub_level == <NUM_LIT:1> : <EOL> parent_level -= <NUM_LIT:1> <EOL> start , end = parent_level , <NUM_LIT:1> <EOL> else : <EOL> start , end = <NUM_LIT:1> , sub_level - <NUM_LIT:1> <EOL> joined_result = '<STR_LIT:/>' . join ( name_parts [ : - start ] + url_parts [ end : ] ) <EOL> hashed_url = self . url ( unquote ( joined_result ) , force = True ) <EOL> file_name = hashed_url . split ( '<STR_LIT:/>' ) [ - <NUM_LIT:1> : ] <EOL> relative_url = '<STR_LIT:/>' . join ( url . split ( '<STR_LIT:/>' ) [ : - <NUM_LIT:1> ] + file_name ) <EOL> return template % unquote ( relative_url ) <EOL> return converter <EOL> def post_process ( self , paths , dry_run = False , ** options ) : <EOL> """<STR_LIT>""" <EOL> if dry_run : <EOL> return <EOL> hashed_paths = { } <EOL> matches = lambda path : matches_patterns ( path , self . _patterns . keys ( ) ) <EOL> adjustable_paths = [ path for path in paths if matches ( path ) ] <EOL> path_level = lambda name : len ( name . split ( os . sep ) ) <EOL> for name in sorted ( paths . keys ( ) , key = path_level , reverse = True ) : <EOL> storage , path = paths [ name ] <EOL> with storage . open ( path ) as original_file : <EOL> hashed_name = self . hashed_name ( name , original_file ) <EOL> if hasattr ( original_file , '<STR_LIT>' ) : <EOL> original_file . seek ( <NUM_LIT:0> ) <EOL> hashed_file_exists = self . exists ( hashed_name ) <EOL> processed = False <EOL> if name in adjustable_paths : <EOL> content = original_file . read ( ) . decode ( settings . FILE_CHARSET ) <EOL> for patterns in self . _patterns . values ( ) : <EOL> for pattern , template in patterns : <EOL> converter = self . url_converter ( name , template ) <EOL> try : <EOL> content = pattern . sub ( converter , content ) <EOL> except ValueError as exc : <EOL> yield name , None , exc <EOL> if hashed_file_exists : <EOL> self . delete ( hashed_name ) <EOL> content_file = ContentFile ( force_bytes ( content ) ) <EOL> saved_name = self . _save ( hashed_name , content_file ) <EOL> hashed_name = force_text ( saved_name . replace ( '<STR_LIT:\\>' , '<STR_LIT:/>' ) ) <EOL> processed = True <EOL> else : <EOL> if not hashed_file_exists : <EOL> processed = True <EOL> saved_name = self . _save ( hashed_name , original_file ) <EOL> hashed_name = force_text ( saved_name . replace ( '<STR_LIT:\\>' , '<STR_LIT:/>' ) ) <EOL> hashed_paths [ self . cache_key ( name . replace ( '<STR_LIT:\\>' , '<STR_LIT:/>' ) ) ] = hashed_name <EOL> yield name , hashed_name , processed <EOL> self . cache . set_many ( hashed_paths ) <EOL> class CachedStaticFilesStorage ( CachedFilesMixin , StaticFilesStorage ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class AppStaticStorage ( FileSystemStorage ) : <EOL> """<STR_LIT>""" <EOL> prefix = None <EOL> source_dir = '<STR_LIT>' <EOL> def __init__ ( self , app , * args , ** kwargs ) : <EOL> """<STR_LIT>""" <EOL> mod = import_module ( app ) <EOL> mod_path = os . path . dirname ( upath ( mod . __file__ ) ) <EOL> location = os . path . join ( mod_path , self . source_dir ) <EOL> super ( AppStaticStorage , self ) . __init__ ( location , * args , ** kwargs ) <EOL> class ConfiguredStorage ( LazyObject ) : <EOL> def _setup ( self ) : <EOL> self . _wrapped = get_storage_class ( settings . STATICFILES_STORAGE ) ( ) <EOL> staticfiles_storage = ConfiguredStorage ( ) </s>
