'Searches templates containing \'compress\' nodes and compresses them
"offline" -- outside of the request/response cycle.
The result is cached with a cache-key derived from the content of the
compress nodes (not the content of the possibly linked files!).'

def compress(self, log=None, **options):

    engine = options.get(u'engine', u'django')
    extensions = options.get(u'extensions')
    extensions = self.handle_extensions((extensions or [u'html']))
    verbosity = int(options.get(u'verbosity', 0))
    if (not log):
        log = StringIO()
    if (not self.get_loaders()):
        raise OfflineGenerationError(u"No    template    loaders    defined.    You    must    set    TEMPLATE_LOADERS    in    your    settings    or    set    'loaders'    in    your    TEMPLATES    dictionary.")
    templates = set()
    if (engine == u'django'):
        paths = set()
        for loader in self.get_loaders():
            try:
                module = import_module(loader.__module__)
                get_template_sources = getattr(module, u'get_template_sources', None)
                if (get_template_sources is None):
                    get_template_sources = loader.get_template_sources
                paths.update((smart_text(origin) for origin in get_template_sources(u'')))
            except (ImportError, AttributeError, TypeError):
                pass
        if (not paths):
            raise OfflineGenerationError(u'No    template    paths    found.    None    of    the    configured    template    loaders    provided    template    paths.    See    https://docs.djangoproject.com/en/1.8/topics/templates/    for    more    information    on    template    loaders.')
        if (verbosity > 1):
            log.write(((u'Considering    paths:\n DCTB ' + u'\n DCTB '.join(paths)) + u'\n'))
        for path in paths:
            for (root, dirs, files) in os.walk(path, followlinks=options.get(u'followlinks', False)):
                templates.update((os.path.join(root, name) for name in files if ((not name.startswith(u'.')) and any((fnmatch(name, (u'*%s' % glob)) for glob in extensions)))))
    elif (engine == u'jinja2'):
        env = settings.COMPRESS_JINJA2_GET_ENVIRONMENT()
        if (env and hasattr(env, u'list_templates')):
            templates |= set([env.loader.get_source(env, template)[1] for template in env.list_templates(filter_func=(lambda _path: (os.path.splitext(_path)[(-1)] in extensions)))])
    if (not templates):
        raise OfflineGenerationError(u'No    templates    found.    Make    sure    your    TEMPLATE_LOADERS    and    TEMPLATE_DIRS    settings    are    correct.')
    if (verbosity > 1):
        log.write(((u'Found    templates:\n DCTB ' + u'\n DCTB '.join(templates)) + u'\n'))
    contexts = settings.COMPRESS_OFFLINE_CONTEXT
    if isinstance(contexts, six.string_types):
        try:
            (module, function) = get_mod_func(contexts)
            contexts = getattr(import_module(module), function)()
        except (AttributeError, ImportError, TypeError) as e:
            raise ImportError((u"Couldn't    import    offline    context    function    %s:    %s" % (settings.COMPRESS_OFFLINE_CONTEXT, e)))
    elif (not isinstance(contexts, (list, tuple))):
        contexts = [contexts]
    contexts = list(contexts)
    parser = self.__get_parser(engine)
    compressor_nodes = OrderedDict()
    for template_name in templates:
        try:
            template = parser.parse(template_name)
        except IOError:
            if (verbosity > 0):
                log.write((u'Unreadable    template    at:    %s\n' % template_name))
            continue
        except TemplateSyntaxError as e:
            if (verbosity > 0):
                log.write((u'Invalid    template    %s:    %s\n' % (template_name, smart_text(e))))
            continue
        except TemplateDoesNotExist:
            if (verbosity > 0):
                log.write((u'Non-existent    template    at:    %s\n' % template_name))
            continue
        except UnicodeDecodeError:
            if (verbosity > 0):
                log.write((u'UnicodeDecodeError    while    trying    to    read    template    %s\n' % template_name))
            continue
        for context_dict in contexts:
            context = parser.get_init_context(context_dict)
            context = Context(context)
            try:
                nodes = list(parser.walk_nodes(template, context=context))
            except (TemplateDoesNotExist, TemplateSyntaxError) as e:
                if (verbosity > 0):
                    log.write((u'Error    parsing    template    %s:    %s\n' % (template_name, smart_text(e))))
                continue
            if nodes:
                template.template_name = template_name
                template_nodes = compressor_nodes.setdefault(template, OrderedDict())
                for node in nodes:
                    template_nodes.setdefault(node, []).append(context)
    if (not compressor_nodes):
        raise OfflineGenerationError(u"No    'compress'    template    tags    found    in    templates.Try    running    compress    command    with    --follow-links    and/or--extension=EXTENSIONS")
    if (verbosity > 0):
        log.write(((u"Found    'compress'    tags    in:\n DCTB " + u'\n DCTB '.join((t.template_name for t in compressor_nodes.keys()))) + u'\n'))
    log.write(u'Compressing...    ')
    block_count = 0
    compressed_contexts = []
    results = []
    offline_manifest = OrderedDict()
    for (template, nodes) in compressor_nodes.items():
        template._log = log
        template._log_verbosity = verbosity
        for (node, contexts) in nodes.items():
            for context in contexts:
                if (context not in compressed_contexts):
                    compressed_contexts.append(context)
                context.push()
                if (not parser.process_template(template, context)):
                    continue
                parser.process_node(template, context, node)
                rendered = parser.render_nodelist(template, context, node)
                key = get_offline_hexdigest(rendered)
                if (key in offline_manifest):
                    continue
                try:
                    result = parser.render_node(template, context, node)
                except Exception as e:
                    raise CommandError((u'An    error    occurred    during    rendering    %s:    %s' % (template.template_name, smart_text(e))))
                result = result.replace(settings.COMPRESS_URL, settings.COMPRESS_URL_PLACEHOLDER)
                offline_manifest[key] = result
                context.pop()
                results.append(result)
                block_count += 1
    write_offline_manifest(offline_manifest)
    context_count = len(compressed_contexts)
    log.write((u'done\nCompressed    %d    block(s)    from    %d    template(s)    for    %d    context(s).\n' % (block_count, len(compressor_nodes), context_count)))
    return (block_count, results)
