<s> from __future__ import unicode_literals <EOL> import hashlib <EOL> import json <EOL> import os <EOL> import posixpath <EOL> import re <EOL> from collections import OrderedDict <EOL> from django . conf import settings <EOL> from django . contrib . staticfiles . utils import check_settings , matches_patterns <EOL> from django . core . cache import ( <EOL> InvalidCacheBackendError , cache as default_cache , caches , <EOL> ) <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 . encoding import force_bytes , force_text <EOL> from django . utils . functional import LazyObject <EOL> from django . utils . six import iteritems <EOL> from django . utils . six . moves . urllib . parse import ( <EOL> unquote , urldefrag , urlsplit , urlunsplit , <EOL> ) <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 HashedFilesMixin ( 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 ( HashedFilesMixin , self ) . __init__ ( * args , ** kwargs ) <EOL> self . _patterns = OrderedDict ( ) <EOL> self . hashed_files = { } <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 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> hashed_name = self . stored_name ( clean_name ) <EOL> final_url = super ( HashedFilesMixin , 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> if url . startswith ( '<STR_LIT:/>' ) and not url . startswith ( settings . STATIC_URL ) : <EOL> return matched <EOL> url_path , fragment = urldefrag ( url ) <EOL> if url_path . startswith ( '<STR_LIT:/>' ) : <EOL> assert url_path . startswith ( settings . STATIC_URL ) <EOL> target_name = url_path [ len ( settings . STATIC_URL ) : ] <EOL> else : <EOL> source_name = name if os . sep == '<STR_LIT:/>' else name . replace ( os . sep , '<STR_LIT:/>' ) <EOL> target_name = posixpath . join ( posixpath . dirname ( source_name ) , url_path ) <EOL> hashed_url = self . url ( unquote ( target_name ) , force = True ) <EOL> transformed_url = '<STR_LIT:/>' . join ( url_path . split ( '<STR_LIT:/>' ) [ : - <NUM_LIT:1> ] + hashed_url . split ( '<STR_LIT:/>' ) [ - <NUM_LIT:1> : ] ) <EOL> if fragment : <EOL> transformed_url += ( '<STR_LIT>' if '<STR_LIT>' in url else '<STR_LIT:#>' ) + fragment <EOL> return template % unquote ( transformed_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_files = OrderedDict ( ) <EOL> adjustable_paths = [ <EOL> path for path in paths <EOL> if matches_patterns ( path , self . _patterns . keys ( ) ) <EOL> ] <EOL> def path_level ( name ) : <EOL> return 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 extension , patterns in iteritems ( self . _patterns ) : <EOL> if matches_patterns ( path , ( extension , ) ) : <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 ( self . clean_name ( saved_name ) ) <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 ( self . clean_name ( saved_name ) ) <EOL> hashed_files [ self . hash_key ( name ) ] = hashed_name <EOL> yield name , hashed_name , processed <EOL> self . hashed_files . update ( hashed_files ) <EOL> def clean_name ( self , name ) : <EOL> return name . replace ( '<STR_LIT:\\>' , '<STR_LIT:/>' ) <EOL> def hash_key ( self , name ) : <EOL> return name <EOL> def stored_name ( self , name ) : <EOL> hash_key = self . hash_key ( name ) <EOL> cache_name = self . hashed_files . get ( hash_key ) <EOL> if cache_name is None : <EOL> cache_name = self . clean_name ( self . hashed_name ( name ) ) <EOL> self . hashed_files [ hash_key ] = cache_name <EOL> return cache_name <EOL> class ManifestFilesMixin ( HashedFilesMixin ) : <EOL> manifest_version = '<STR_LIT:1.0>' <EOL> manifest_name = '<STR_LIT>' <EOL> def __init__ ( self , * args , ** kwargs ) : <EOL> super ( ManifestFilesMixin , self ) . __init__ ( * args , ** kwargs ) <EOL> self . hashed_files = self . load_manifest ( ) <EOL> def read_manifest ( self ) : <EOL> try : <EOL> with self . open ( self . manifest_name ) as manifest : <EOL> return manifest . read ( ) . decode ( '<STR_LIT:utf-8>' ) <EOL> except IOError : <EOL> return None <EOL> def load_manifest ( self ) : <EOL> content = self . read_manifest ( ) <EOL> if content is None : <EOL> return OrderedDict ( ) <EOL> try : <EOL> stored = json . loads ( content , object_pairs_hook = OrderedDict ) <EOL> except ValueError : <EOL> pass <EOL> else : <EOL> version = stored . get ( '<STR_LIT:version>' ) <EOL> if version == '<STR_LIT:1.0>' : <EOL> return stored . get ( '<STR_LIT>' , OrderedDict ( ) ) <EOL> raise ValueError ( "<STR_LIT>" % <EOL> ( self . manifest_name , self . manifest_version ) ) <EOL> def post_process ( self , * args , ** kwargs ) : <EOL> self . hashed_files = OrderedDict ( ) <EOL> all_post_processed = super ( ManifestFilesMixin , <EOL> self ) . post_process ( * args , ** kwargs ) <EOL> for post_processed in all_post_processed : <EOL> yield post_processed <EOL> self . save_manifest ( ) <EOL> def save_manifest ( self ) : <EOL> payload = { '<STR_LIT>' : self . hashed_files , '<STR_LIT:version>' : self . manifest_version } <EOL> if self . exists ( self . manifest_name ) : <EOL> self . delete ( self . manifest_name ) <EOL> contents = json . dumps ( payload ) . encode ( '<STR_LIT:utf-8>' ) <EOL> self . _save ( self . manifest_name , ContentFile ( contents ) ) <EOL> class _MappingCache ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , cache ) : <EOL> self . cache = cache <EOL> def __setitem__ ( self , key , value ) : <EOL> self . cache . set ( key , value ) <EOL> def __getitem__ ( self , key ) : <EOL> value = self . cache . get ( key ) <EOL> if value is None : <EOL> raise KeyError ( "<STR_LIT>" % key ) <EOL> return value <EOL> def clear ( self ) : <EOL> self . cache . clear ( ) <EOL> def update ( self , data ) : <EOL> self . cache . set_many ( data ) <EOL> def get ( self , key , default = None ) : <EOL> try : <EOL> return self [ key ] <EOL> except KeyError : <EOL> return default <EOL> class CachedFilesMixin ( HashedFilesMixin ) : <EOL> def __init__ ( self , * args , ** kwargs ) : <EOL> super ( CachedFilesMixin , self ) . __init__ ( * args , ** kwargs ) <EOL> try : <EOL> self . hashed_files = _MappingCache ( caches [ '<STR_LIT>' ] ) <EOL> except InvalidCacheBackendError : <EOL> self . hashed_files = _MappingCache ( default_cache ) <EOL> def hash_key ( self , name ) : <EOL> key = hashlib . md5 ( force_bytes ( self . clean_name ( name ) ) ) . hexdigest ( ) <EOL> return '<STR_LIT>' % key <EOL> class CachedStaticFilesStorage ( CachedFilesMixin , StaticFilesStorage ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class ManifestStaticFilesStorage ( ManifestFilesMixin , StaticFilesStorage ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class ConfiguredStorage ( LazyObject ) : <EOL> def _setup ( self ) : <EOL> self . _wrapped = get_storage_class ( settings . STATICFILES_STORAGE ) ( ) <EOL> staticfiles_storage = ConfiguredStorage ( ) </s>
