Example #1
0
class Command(BaseCommand):  # pragma: no cover
    help = ("Compresses css and js assets defined in settings.MINIFY_BUNDLES")
    option_list = BaseCommand.option_list + (make_option(
        '-u',
        '--update-only',
        action='store_true',
        dest='do_update_only',
        help='Updates the hash only'), )
    requires_model_validation = False
    do_update_only = False

    checked_hash = {}
    bundle_hashes = {}

    missing_files = 0
    minify_skipped = 0
    cmd_errors = False
    ext_media_path = os.path.join(get_media_root(), 'external')

    def update_hashes(self, update=False):
        def media_git_id(media_path):
            id = git.repo.Repo(path(media_path)).log('-1')[0].id_abbrev
            if update:
                # Adds a time based hash on to the build id.
                return '%s-%s' % (id, hex(int(time.time()))[2:])
            return id

        build_id_file = os.path.realpath(
            os.path.join(settings.ROOT, 'build.py'))
        with open(build_id_file, 'w') as f:
            f.write('BUILD_ID_CSS = "%s"\n' % media_git_id('css'))
            f.write('BUILD_ID_JS = "%s"\n' % media_git_id('js'))
            f.write('BUILD_ID_IMG = "%s"\n' % media_git_id('img'))
            f.write('BUNDLE_HASHES = %s\n' % self.bundle_hashes)

    def handle(self, **options):
        if options.get('do_update_only', False):
            self.update_hashes(update=True)
            return

        jar_path = (os.path.dirname(__file__), '..', '..', 'bin',
                    'yuicompressor-2.4.7.jar')
        self.path_to_jar = os.path.realpath(os.path.join(*jar_path))

        self.v = '-v' if options.get('verbosity', False) == '2' else ''

        cachebust_imgs = getattr(settings, 'CACHEBUST_IMGS', False)
        if not cachebust_imgs:
            print "To turn on cache busting, use settings.CACHEBUST_IMGS"

        # This will loop through every bundle, and do the following:
        # - Concat all files into one
        # - Cache bust all images in CSS files
        # - Minify the concatted files

        for ftype, bundle in settings.MINIFY_BUNDLES.iteritems():
            for name, files in bundle.iteritems():
                # Set the paths to the files.
                concatted_file = path(ftype, '%s-all.%s' % (
                    name,
                    ftype,
                ))
                compressed_file = path(ftype, '%s-min.%s' % (
                    name,
                    ftype,
                ))

                files_all = []
                for fn in files:
                    processed = self._preprocess_file(fn)
                    # If the file can't be processed, we skip it.
                    if processed is not None:
                        files_all.append(processed)

                # Concat all the files.
                tmp_concatted = '%s.tmp' % concatted_file
                if len(files_all) == 0:
                    raise CommandError(
                        'No input files specified in ' +
                        'MINIFY_BUNDLES["%s"]["%s"] in settings.py!' %
                        (ftype, name))
                self._call("cat %s > %s" %
                           (' '.join(files_all), tmp_concatted),
                           shell=True)

                # Cache bust individual images in the CSS.
                if cachebust_imgs and ftype == "css":
                    bundle_hash = self._cachebust(tmp_concatted, name)
                    self.bundle_hashes["%s:%s" % (ftype, name)] = bundle_hash

                # Compresses the concatenations.
                is_changed = self._is_changed(concatted_file)
                self._clean_tmp(concatted_file)
                if is_changed:
                    self._minify(ftype, concatted_file, compressed_file)
                elif self.v:
                    print "File unchanged, skipping minification of %s" % (
                        concatted_file)
                else:
                    self.minify_skipped += 1

        # Write out the hashes
        self.update_hashes()

        if not self.v and self.minify_skipped:
            print "Unchanged files skipped for minification: %s" % (
                self.minify_skipped)
        if self.cmd_errors:
            raise CommandError('one or more minify commands exited with a '
                               'non-zero status. See output above for errors.')

    def _call(self, *args, **kw):
        exit = call(*args, **kw)
        if exit != 0:
            print '%s exited with a non-zero status.' % args
            self.cmd_errors = True
        return exit

    def _get_url_or_path(self, item):
        """
        Determine whether this is a URL or a relative path.
        """
        if item.startswith('//'):
            return 'http:%s' % item
        elif item.startswith(('http', 'https')):
            return item
        return None

    def _preprocess_file(self, filename):
        """Preprocess files and return new filenames."""
        url = self._get_url_or_path(filename)
        if url:
            # External files from URLs are placed into a subdirectory.
            if not os.path.exists(self.ext_media_path):
                os.makedirs(self.ext_media_path)

            filename = os.path.basename(url)
            if filename.endswith(('.js', '.css', '.less', '.styl')):
                fp = path(filename.lstrip('/'))
                file_path = '%s/%s' % (self.ext_media_path, filename)

                try:
                    req = urllib2.urlopen(url)
                    print ' - Fetching %s ...' % url
                except urllib2.HTTPError, e:
                    print ' - HTTP Error %s for %s, %s' % (url, filename,
                                                           str(e.code))
                    return None
                except urllib2.URLError, e:
                    print ' - Invalid URL %s for %s, %s' % (url, filename,
                                                            str(e.reason))
                    return None

                with open(file_path, 'w+') as fp:
                    try:
                        shutil.copyfileobj(req, fp)
                    except shutil.Error:
                        print ' - Could not copy file %s' % filename
                filename = os.path.join('external', filename)
            else:
import os
import re
import shutil
import time
import urllib2
from subprocess import call, PIPE

from django.conf import settings
from django.core.management.base import BaseCommand, CommandError

import git

from jingo_minify.helpers import get_media_root


path = lambda *a: os.path.join(get_media_root(), *a)


class Command(BaseCommand):  # pragma: no cover
    help = ("Compresses css and js assets defined in settings.MINIFY_BUNDLES")
    option_list = BaseCommand.option_list + (
        make_option('-u', '--update-only', action='store_true',
                    dest='do_update_only', help='Updates the hash only'),
        make_option('-t', '--add-timestamp', action='store_true',
                    dest='add_timestamp', help='Add timestamp to hash'),
    )
    requires_model_validation = False
    do_update_only = False

    checked_hash = {}
    bundle_hashes = {}
Example #3
0
from optparse import make_option
import os
import re
import shutil
import time
import urllib2
from subprocess import call, PIPE

from django.conf import settings
from django.core.management.base import BaseCommand, CommandError

import git

from jingo_minify.helpers import get_media_root

path = lambda *a: os.path.join(get_media_root(), *a)


class Command(BaseCommand):  # pragma: no cover
    help = ("Compresses css and js assets defined in settings.MINIFY_BUNDLES")
    option_list = BaseCommand.option_list + (make_option(
        '-u',
        '--update-only',
        action='store_true',
        dest='do_update_only',
        help='Updates the hash only'), )
    requires_model_validation = False
    do_update_only = False

    checked_hash = {}
    bundle_hashes = {}
Example #4
0
def test_static_override():
    """Overriding to False uses MEDIA versions."""
    eq_(get_media_root(), 'media')
    eq_(get_media_url(), 'http://example.com/media')
Example #5
0
def test_no_override():
    """No override uses STATIC versions."""
    eq_(get_media_root(), 'static')
    eq_(get_media_url(), 'http://example.com/static')
Example #6
0
def test_static_override():
    """Overriding to False uses MEDIA versions."""
    eq_(get_media_root(), 'media')
    eq_(get_media_url(), 'http://example.com/media')
Example #7
0
def test_no_override():
    """No override uses STATIC versions."""
    eq_(get_media_root(), 'static')
    eq_(get_media_url(), 'http://example.com/static')