Ticket #15213: Enabled-compression-of-static-files-using-an-external-programs.patch
File Enabled-compression-of-static-files-using-an-external-programs.patch, 6.4 KB (added by , 14 years ago) |
---|
-
django/conf/global_settings.py
From 7432380f5cff8abd8a389b4227440c87a272052d Mon Sep 17 00:00:00 2001 From: Sebastian Noack <sebastian.noack@gmail.com> Date: Wed, 2 Feb 2011 12:47:16 +0100 Subject: [PATCH] Enabled compression of static files using an external program (e.g. yui-compressor). --- django/conf/global_settings.py | 4 ++ .../management/commands/collectstatic.py | 52 ++++++++++++++++++++ django/core/files/base.py | 16 +++--- 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index 0017f46..7676f5a 100644
a b STATICFILES_FINDERS = ( 579 579 # 'django.contrib.staticfiles.finders.DefaultStorageFinder', 580 580 ) 581 581 582 # Mapping from filename extensions to external programs (e.g. yui-compressor) 583 # used to compress static files with that extension. 584 STATICFILES_COMPRESSORS = {} 585 582 586 # URL prefix for admin media -- CSS, JavaScript and images. 583 587 # Make sure to use a trailing slash. 584 588 # Examples: "http://foo.com/static/admin/", "/static/admin/". -
django/contrib/staticfiles/management/commands/collectstatic.py
diff --git a/django/contrib/staticfiles/management/commands/collectstatic.py b/django/contrib/staticfiles/management/commands/collectstatic.py index 54eaab0..2bb8332 100644
a b 1 1 import os 2 2 import sys 3 3 import shutil 4 import subprocess 4 5 from optparse import make_option 5 6 6 7 from django.conf import settings 8 from django.core.files.base import File 7 9 from django.core.files.storage import get_storage_class 8 10 from django.core.management.base import CommandError, NoArgsCommand 9 11 … … class Command(NoArgsCommand): 29 31 dest='use_default_ignore_patterns', default=True, 30 32 help="Don't ignore the common private glob-style patterns 'CVS', " 31 33 "'.*' and '*~'."), 34 make_option('--no-compress', action='store_false', 35 dest='compress', default=True, 36 help="Don't compress files, using the programs configured by the " 37 "STATICFILES_COMPRESSORS setting."), 32 38 ) 33 39 help = "Collect static files from apps and other locations in a single location." 34 40 … … class Command(NoArgsCommand): 36 42 super(NoArgsCommand, self).__init__(*args, **kwargs) 37 43 self.copied_files = [] 38 44 self.symlinked_files = [] 45 self.compressed_files = [] 39 46 self.unmodified_files = [] 40 47 self.storage = get_storage_class(settings.STATICFILES_STORAGE)() 41 48 try: … … class Command(NoArgsCommand): 49 56 50 57 def handle_noargs(self, **options): 51 58 symlink = options['link'] 59 compress = options['compress'] 52 60 ignore_patterns = options['ignore_patterns'] 53 61 if options['use_default_ignore_patterns']: 54 62 ignore_patterns += ['CVS', '.*', '*~'] … … Type 'yes' to continue, or 'no' to cancel: """ % settings.STATIC_ROOT) 82 90 prefixed_path = os.path.join(storage.prefix, path) 83 91 else: 84 92 prefixed_path = path 93 94 if compress: 95 ext = os.path.splitext(path)[1][len(os.path.extsep):] 96 compressor = settings.STATICFILES_COMPRESSORS.get(ext) 97 if compressor is not None: 98 self.compress_file(path, prefixed_path, storage, compressor, **options) 99 continue 100 85 101 if symlink: 86 102 self.link_file(path, prefixed_path, storage, **options) 87 103 else: … … Type 'yes' to continue, or 'no' to cancel: """ % settings.STATIC_ROOT) 200 216 self.storage.save(prefixed_path, source_file) 201 217 if not prefixed_path in self.copied_files: 202 218 self.copied_files.append(prefixed_path) 219 220 def compress_file(self, path, prefixed_path, source_storage, compressor, **options): 221 """ 222 Attempt to put a compressed version to ``path`` with storage 223 """ 224 # Skip this file if it was already compressed earlier 225 if prefixed_path in self.compressed_files: 226 return self.log("Skipping '%s' (already compressed earlier)" % path) 227 # Delete the target file if needed or break 228 if not self.delete_file(path, prefixed_path, source_storage, **options): 229 return 230 # The full path of the source file 231 source_path = source_storage.path(path) 232 # Finally compress the file 233 if options['dry_run']: 234 self.log("Pretending to compress '%s'" % source_path, level=1) 235 else: 236 self.log("Compressing '%s'" % source_path, level=1) 237 if self.local: 238 full_path = self.storage.path(prefixed_path) 239 try: 240 os.makedirs(os.path.dirname(full_path)) 241 except OSError: 242 pass 243 subprocess.Popen(compressor, shell=True, 244 stdin=open(source_path, 'rb'), 245 stdout=open(full_path, 'wb')).wait() 246 shutil.copystat(source_path, full_path) 247 else: 248 process = subprocess.Popen(compressor, shell=True, 249 stdin=open(source_path, 'rb'), 250 stdout=subprocess.PIPE) 251 self.storage.save(prefixed_path, File(process.stdout)) 252 process.wait() 253 if prefixed_path not in self.compressed_files: 254 self.compressed_files.append(prefixed_path) -
django/core/files/base.py
diff --git a/django/core/files/base.py b/django/core/files/base.py index 6204d71..95231f2 100644
a b class File(FileProxyMixin): 59 59 if not chunk_size: 60 60 chunk_size = self.DEFAULT_CHUNK_SIZE 61 61 62 if hasattr(self, 'seek'):62 try: 63 63 self.seek(0) 64 # Assume the pointer is at zero... 65 counter = self.size 66 67 while counter > 0: 68 yield self.read(chunk_size) 69 counter -= chunk_size 64 except (AttributeError, IOError): 65 pass 66 67 while True: 68 data = self.read(chunk_size) 69 if not data: 70 break 71 yield data 70 72 71 73 def multiple_chunks(self, chunk_size=None): 72 74 """