Exemple #1
0
    def __get_parser(self, engine):
        if engine == "jinja2":
            from compressor.offline.jinja2 import Jinja2Parser
            env = settings.COMPRESS_JINJA2_GET_ENVIRONMENT()
            parser = Jinja2Parser(charset=settings.FILE_CHARSET, env=env)
        elif engine == "django":
            from compressor.offline.django import DjangoParser
            parser = DjangoParser(charset=settings.FILE_CHARSET)
        else:
            raise OfflineGenerationError("Invalid templating engine specified.")

        return parser
Exemple #2
0
 def render_offline(self, context):
     """
     If enabled and in offline mode, and not forced check the offline cache
     and return the result if given
     """
     key = get_offline_hexdigest(self.get_original_content(context))
     offline_manifest = get_offline_manifest()
     if key in offline_manifest:
         return offline_manifest[key]
     else:
         raise OfflineGenerationError('You have offline compression '
             'enabled but key "%s" is missing from offline manifest. '
             'You may need to run "python manage.py compress".' % key)
Exemple #3
0
 def render_offline(self, kind, mode, compressor, forced, nodelist_string):
     """
     If enabled and in offline mode, and not forced or in debug mode
     check the offline cache and return the result if given
     """
     if (settings.COMPRESS_ENABLED
             and settings.COMPRESS_OFFLINE) and not forced:
         key = get_offline_jinja_hexdigest(nodelist_string)
         offline_manifest = get_offline_manifest()
         if key in offline_manifest:
             return offline_manifest[key]
         else:
             raise OfflineGenerationError(
                 'You have offline compression enabled but key "%s" is missing from offline manifest. You may need to run "python manage.py compress".'
                 % key)
Exemple #4
0
 def render_offline(self, context):
     """
     If enabled and in offline mode, and not forced check the offline cache
     and return the result if given
     """
     original_content = self.get_original_content(context)
     key = get_offline_hexdigest(original_content)
     offline_manifest = get_offline_manifest()
     if key in offline_manifest:
         return offline_manifest[key].replace(
             settings.COMPRESS_URL_PLACEHOLDER, settings.COMPRESS_URL)
     else:
         raise OfflineGenerationError(
             'You have offline compression '
             'enabled but key "%s" is missing from offline manifest. '
             'You may need to run "python manage.py compress". Here '
             'is the original content:\n\n%s' % (key, original_content))
Exemple #5
0
 def render_offline(self, context, mode):
     """
     If enabled and in offline mode, and not forced check the offline cache
     and return the result if given
     """
     original_content = self.get_original_content(context)
     key = get_offline_hexdigest(original_content)
     offline_manifest = get_offline_manifest()
     if key in offline_manifest:
         return offline_manifest[key][mode].replace(
             settings.COMPRESS_URL_PLACEHOLDER,
             # Cast ``settings.COMPRESS_URL`` to a string to allow it to be
             # a string-alike object to e.g. add ``SCRIPT_NAME`` WSGI param
             # as a *path prefix* to the output URL.
             # See https://code.djangoproject.com/ticket/25598.
             six.text_type(settings.COMPRESS_URL))
     else:
         raise OfflineGenerationError(
             'You have offline compression '
             'enabled but key "%s" is missing from offline manifest. '
             'You may need to run "python manage.py compress". Here '
             'is the original content:\n\n%s' % (key, original_content))
Exemple #6
0
    def compress(self, log=None, **options):
        """
        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!).
        """
        engine = options.get("engine", "django")
        extensions = options.get('extensions')
        extensions = self.handle_extensions(extensions or ['html'])
        verbosity = int(options.get("verbosity", 0))
        if not log:
            log = StringIO()
        if not self.get_loaders():
            raise OfflineGenerationError("No template loaders defined. You "
                                         "must set TEMPLATE_LOADERS in your "
                                         "settings or set 'loaders' in your "
                                         "TEMPLATES dictionary.")
        templates = set()
        if engine == 'django':
            paths = set()
            for loader in self.get_loaders():
                try:
                    module = import_module(loader.__module__)
                    get_template_sources = getattr(module,
                        '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(''))
                except (ImportError, AttributeError, TypeError):
                    # Yeah, this didn't work out so well, let's move on
                    pass

            if not paths:
                raise OfflineGenerationError("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("Considering paths:\n\t" + "\n\t".join(paths) + "\n")

            for path in paths:
                for root, dirs, files in os.walk(path,
                        followlinks=options.get('followlinks', False)):
                    templates.update(os.path.join(root, name)
                        for name in files if not name.startswith('.') and
                            any(fnmatch(name, "*%s" % glob) for glob in extensions))
        elif engine == 'jinja2':
            env = settings.COMPRESS_JINJA2_GET_ENVIRONMENT()
            if env and hasattr(env, '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("No templates found. Make sure your "
                                         "TEMPLATE_LOADERS and TEMPLATE_DIRS "
                                         "settings are correct.")
        if verbosity > 1:
            log.write("Found templates:\n\t" + "\n\t".join(templates) + "\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("Couldn't import offline context function %s: %s" %
                                  (settings.COMPRESS_OFFLINE_CONTEXT, e))
        elif not isinstance(contexts, (list, tuple)):
            contexts = [contexts]
        contexts = list(contexts) # evaluate generator

        parser = self.__get_parser(engine)
        compressor_nodes = OrderedDict()
        for template_name in templates:
            try:
                template = parser.parse(template_name)
            except IOError:  # unreadable file -> ignore
                if verbosity > 0:
                    log.write("Unreadable template at: %s\n" % template_name)
                continue
            except TemplateSyntaxError as e:  # broken template -> ignore
                if verbosity > 0:
                    log.write("Invalid template %s: %s\n" % (template_name, smart_text(e)))
                continue
            except TemplateDoesNotExist:  # non existent template -> ignore
                if verbosity > 0:
                    log.write("Non-existent template at: %s\n" % template_name)
                continue
            except UnicodeDecodeError:
                if verbosity > 0:
                    log.write("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:
                    # Could be an error in some base template
                    if verbosity > 0:
                        log.write("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(
                "No 'compress' template tags found in templates."
                "Try running compress command with --follow-links and/or"
                "--extension=EXTENSIONS")

        if verbosity > 0:
            log.write("Found 'compress' tags in:\n\t" +
                      "\n\t".join((t.template_name
                                   for t in compressor_nodes.keys())) + "\n")

        log.write("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("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("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
Exemple #7
0
class Command(NoArgsCommand):
    help = "Compress content outside of the request/response cycle"
    option_list = NoArgsCommand.option_list + (
        make_option('--extension',
                    '-e',
                    action='append',
                    dest='extensions',
                    help='The file extension(s) to examine (default: ".html", '
                    'separate multiple extensions with commas, or use -e '
                    'multiple times)'),
        make_option(
            '-f',
            '--force',
            default=False,
            action='store_true',
            help="Force the generation of compressed content even if the "
            "COMPRESS_ENABLED setting is not True.",
            dest='force'),
        make_option(
            '--follow-links',
            default=False,
            action='store_true',
            help="Follow symlinks when traversing the COMPRESS_ROOT "
            "(which defaults to MEDIA_ROOT). Be aware that using this "
            "can lead to infinite recursion if a link points to a parent "
            "directory of itself.",
            dest='follow_links'),
    )

    requires_model_validation = False

    def get_loaders(self):
        from django.template.loader import template_source_loaders
        if template_source_loaders is None:
            try:
                from django.template.loader import (find_template as
                                                    finder_func)
            except ImportError:
                from django.template.loader import (find_template_source as
                                                    finder_func)
            try:
                source, name = finder_func('test')
            except TemplateDoesNotExist:
                pass
            from django.template.loader import template_source_loaders
        loaders = []
        # If template loader is CachedTemplateLoader, return the loaders
        # that it wraps around. So if we have
        # TEMPLATE_LOADERS = (
        #    ('django.template.loaders.cached.Loader', (
        #        'django.template.loaders.filesystem.Loader',
        #        'django.template.loaders.app_directories.Loader',
        #    )),
        # )
        # The loaders will return django.template.loaders.filesystem.Loader
        # and django.template.loaders.app_directories.Loader
        for loader in template_source_loaders:
            if CachedLoader is not None and isinstance(loader, CachedLoader):
                loaders.extend(loader.loaders)
            else:
                loaders.append(loader)
        return loaders

    def compress(self, log=None, **options):
        """
        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!).
        """
        extensions = options.get('extensions')
        extensions = self.handle_extensions(extensions or ['html'])
        verbosity = int(options.get("verbosity", 0))
        if not log:
            log = StringIO()
        if not settings.TEMPLATE_LOADERS:
            raise OfflineGenerationError("No template loaders defined. You "
                                         "must set TEMPLATE_LOADERS in your "
                                         "settings.")
        paths = set()
        for loader in self.get_loaders():
            try:
                module = import_module(loader.__module__)
                get_template_sources = getattr(module, 'get_template_sources',
                                               None)
                if get_template_sources is None:
                    get_template_sources = loader.get_template_sources
                paths.update(list(get_template_sources('')))
            except (ImportError, AttributeError):
                # Yeah, this didn't work out so well, let's move on
                pass
        if not paths:
            raise OfflineGenerationError("No template paths found. None of "
                                         "the configured template loaders "
                                         "provided template paths. See "
                                         "http://django.me/template-loaders "
                                         "for more information on template "
                                         "loaders.")
        if verbosity > 1:
            log.write("Considering paths:\n\t" + "\n\t".join(paths) + "\n")
        templates = set()
        for path in paths:
            for root, dirs, files in walk(path,
                                          followlinks=options.get(
                                              'followlinks', False)):
                templates.update(
                    os.path.join(root, name) for name in files
                    if not name.startswith('.') and any(
                        fnmatch(name, "*%s" % glob) for glob in extensions))
        if not templates:
            raise OfflineGenerationError("No templates found. Make sure your "
                                         "TEMPLATE_LOADERS and TEMPLATE_DIRS "
                                         "settings are correct.")
        if verbosity > 1:
            log.write("Found templates:\n\t" + "\n\t".join(templates) + "\n")

        compressor_nodes = SortedDict()
        for template_name in templates:
            try:
                template_file = open(template_name)
                try:
                    template = Template(template_file.read().decode(
                        settings.FILE_CHARSET))
                finally:
                    template_file.close()
            except IOError:  # unreadable file -> ignore
                if verbosity > 0:
                    log.write("Unreadable template at: %s\n" % template_name)
                continue
            except TemplateSyntaxError:  # broken template -> try jinja -> ignore if still broken
                try:
                    template_file = open(template_name)
                    template = jinja_env.parse(template_file.read().decode(
                        settings.FILE_CHARSET))
                    template.is_jinja = True
                    template.name = template_name
                except jinja2.exceptions.TemplateSyntaxError:
                    if verbosity > 0:
                        log.write("Invalid template at: %s\n" % template_name)
                    continue
                finally:
                    template_file.close()
            except UnicodeDecodeError:
                if verbosity > 0:
                    log.write("UnicodeDecodeError while trying to read "
                              "template %s\n" % template_name)
            if getattr(template, 'is_jinja', False):
                nodes = template.find_all(jinja2.nodes.CallBlock)
                for node in nodes:
                    try:
                        compress_node = node.call.node
                        if (compress_node.identifier ==
                                'compressor.contrib.jinja2ext.CompressorExtension'
                                and compress_node.name == '_compress'):
                            template.template_name = template_name
                            compressor_nodes.setdefault(template,
                                                        []).append(node)
                    except AttributeError, IndexError:
                        pass
            else:
                nodes = list(self.walk_nodes(template))
                if nodes:
                    template.template_name = template_name
                    compressor_nodes.setdefault(template, []).extend(nodes)

        if not compressor_nodes:
            raise OfflineGenerationError(
                "No 'compress' template tags found in templates.")

        if verbosity > 0:
            log.write("Found 'compress' tags in:\n\t" +
                      "\n\t".join((t.template_name
                                   for t in compressor_nodes.keys())) + "\n")

        log.write("Compressing... ")
        count = 0
        results = []
        offline_manifest = {}
        for template, nodes in compressor_nodes.iteritems():
            if getattr(template, 'is_jinja', False):
                for node in nodes:
                    context = settings.COMPRESS_OFFLINE_CONTEXT.copy()
                    old_forced = getattr(jinja_env,
                                         '_django_compressor_offline_forced',
                                         None)
                    jinja_env._django_compressor_offline_forced = True
                    nodelist = node.body
                    key = get_offline_jinja_hexdigest(nodelist)
                    result = render_jinja_node(node, context, jinja_env)
                    if old_forced is not None:
                        jinja_env._django_compressor_offline_forced = old_forced
                    offline_manifest[key] = result
                    results.append(result)
                    count += 1
                continue

            context = Context(settings.COMPRESS_OFFLINE_CONTEXT)
            extra_context = {}
            firstnode = template.nodelist[0]
            if isinstance(firstnode, ExtendsNode):
                # If this template has a ExtendsNode, we apply our patch to
                # generate the necessary context, and then use it for all the
                # nodes in it, just in case (we don't know which nodes were
                # in a block)
                firstnode._old_get_parent = firstnode.get_parent
                firstnode.get_parent = MethodType(patched_get_parent,
                                                  firstnode)
                extra_context = firstnode.render(context)
                context.render_context = extra_context.render_context
            for node in nodes:
                context.push()
                if extra_context and node._block_name:
                    context['block'] = context.render_context[
                        BLOCK_CONTEXT_KEY].pop(node._block_name)
                    if context['block']:
                        context['block'].context = context
                key = get_offline_hexdigest(node.nodelist)
                result = node.render(context, forced=True)
                offline_manifest[key] = result
                context.pop()
                results.append(result)
                count += 1

        write_offline_manifest(offline_manifest)

        log.write("done\nCompressed %d block(s) from %d template(s).\n" %
                  (count, len(compressor_nodes)))
        return count, results
Exemple #8
0
    def compress(self, log=None, **options):
        """
        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!).
        """
        extensions = options.get('extensions')
        extensions = self.handle_extensions(extensions or ['html'])
        verbosity = int(options.get("verbosity", 0))
        if not log:
            log = StringIO()
        if not settings.TEMPLATE_LOADERS:
            raise OfflineGenerationError("No template loaders defined. You "
                                         "must set TEMPLATE_LOADERS in your "
                                         "settings.")
        paths = set()
        for loader in self.get_loaders():
            try:
                module = import_module(loader.__module__)
                get_template_sources = getattr(module, 'get_template_sources',
                                               None)
                if get_template_sources is None:
                    get_template_sources = loader.get_template_sources
                paths.update(list(get_template_sources('')))
            except (ImportError, AttributeError):
                # Yeah, this didn't work out so well, let's move on
                pass
        if not paths:
            raise OfflineGenerationError("No template paths found. None of "
                                         "the configured template loaders "
                                         "provided template paths. See "
                                         "http://django.me/template-loaders "
                                         "for more information on template "
                                         "loaders.")
        if verbosity > 1:
            log.write("Considering paths:\n\t" + "\n\t".join(paths) + "\n")
        templates = set()
        for path in paths:
            for root, dirs, files in walk(path,
                                          followlinks=options.get(
                                              'followlinks', False)):
                templates.update(
                    os.path.join(root, name) for name in files
                    if not name.startswith('.') and any(
                        fnmatch(name, "*%s" % glob) for glob in extensions))
        if not templates:
            raise OfflineGenerationError("No templates found. Make sure your "
                                         "TEMPLATE_LOADERS and TEMPLATE_DIRS "
                                         "settings are correct.")
        if verbosity > 1:
            log.write("Found templates:\n\t" + "\n\t".join(templates) + "\n")

        compressor_nodes = SortedDict()
        for template_name in templates:
            try:
                template_file = open(template_name)
                try:
                    template = Template(template_file.read().decode(
                        settings.FILE_CHARSET))
                finally:
                    template_file.close()
            except IOError:  # unreadable file -> ignore
                if verbosity > 0:
                    log.write("Unreadable template at: %s\n" % template_name)
                continue
            except TemplateSyntaxError:  # broken template -> try jinja -> ignore if still broken
                try:
                    template_file = open(template_name)
                    template = jinja_env.parse(template_file.read().decode(
                        settings.FILE_CHARSET))
                    template.is_jinja = True
                    template.name = template_name
                except jinja2.exceptions.TemplateSyntaxError:
                    if verbosity > 0:
                        log.write("Invalid template at: %s\n" % template_name)
                    continue
                finally:
                    template_file.close()
            except UnicodeDecodeError:
                if verbosity > 0:
                    log.write("UnicodeDecodeError while trying to read "
                              "template %s\n" % template_name)
            if getattr(template, 'is_jinja', False):
                nodes = template.find_all(jinja2.nodes.CallBlock)
                for node in nodes:
                    try:
                        compress_node = node.call.node
                        if (compress_node.identifier ==
                                'compressor.contrib.jinja2ext.CompressorExtension'
                                and compress_node.name == '_compress'):
                            template.template_name = template_name
                            compressor_nodes.setdefault(template,
                                                        []).append(node)
                    except AttributeError, IndexError:
                        pass
            else:
                nodes = list(self.walk_nodes(template))
                if nodes:
                    template.template_name = template_name
                    compressor_nodes.setdefault(template, []).extend(nodes)
Exemple #9
0
    def compress(self, log=None, **options):
        """
        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!).
        """
        extensions = options.get('extensions')
        extensions = self.handle_extensions(extensions or ['html'])
        verbosity = int(options.get("verbosity", 0))
        if not log:
            log = StringIO()
        if not settings.TEMPLATE_LOADERS:
            raise OfflineGenerationError("No template loaders defined. You "
                                         "must set TEMPLATE_LOADERS in your "
                                         "settings.")
        paths = set()
        for loader in self.get_loaders():
            try:
                module = import_module(loader.__module__)
                get_template_sources = getattr(module,
                    'get_template_sources', None)
                if get_template_sources is None:
                    get_template_sources = loader.get_template_sources
                paths.update(list(get_template_sources('')))
            except (ImportError, AttributeError):
                # Yeah, this didn't work out so well, let's move on
                pass
        if not paths:
            raise OfflineGenerationError("No template paths found. None of "
                                         "the configured template loaders "
                                         "provided template paths. See "
                                         "http://django.me/template-loaders "
                                         "for more information on template "
                                         "loaders.")
        if verbosity > 1:
            log.write("Considering paths:\n\t" + "\n\t".join(paths) + "\n")
        templates = set()
        for path in paths:
            for root, dirs, files in walk(path,
                    followlinks=options.get('followlinks', False)):
                templates.update(os.path.join(root, name)
                    for name in files if not name.startswith('.') and
                        any(fnmatch(name, "*%s" % glob) for glob in extensions))
        if not templates:
            raise OfflineGenerationError("No templates found. Make sure your "
                                         "TEMPLATE_LOADERS and TEMPLATE_DIRS "
                                         "settings are correct.")
        if verbosity > 1:
            log.write("Found templates:\n\t" + "\n\t".join(templates) + "\n")

        compressor_nodes = SortedDict()
        for template_name in templates:
            try:
                template_file = open(template_name)
                try:
                    template = Template(template_file.read().decode(
                                        settings.FILE_CHARSET))
                finally:
                    template_file.close()
            except IOError: # unreadable file -> ignore
                if verbosity > 0:
                    log.write("Unreadable template at: %s\n" % template_name)
                continue
            except TemplateSyntaxError: # broken template -> ignore
                if verbosity > 0:
                    log.write("Invalid template at: %s\n" % template_name)
                continue
            except UnicodeDecodeError:
                if verbosity > 0:
                    log.write("UnicodeDecodeError while trying to read "
                              "template %s\n" % template_name)
            nodes = list(self.walk_nodes(template))
            if nodes:
                compressor_nodes.setdefault(template_name, []).extend(nodes)

        if not compressor_nodes:
            raise OfflineGenerationError(
                "No 'compress' template tags found in templates.")

        if verbosity > 0:
            log.write("Found 'compress' tags in:\n\t" +
                      "\n\t".join(compressor_nodes.keys()) + "\n")

        log.write("Compressing... ")
        count = 0
        results = []
        context = Context(settings.COMPRESS_OFFLINE_CONTEXT)
        for nodes in compressor_nodes.values():
            for node in nodes:
                key = get_offline_cachekey(node.nodelist)
                try:
                    result = node.render(context, forced=True)
                except Exception, e:
                    raise CommandError("An error occured during rending: "
                                       "%s" % e)
                cache.set(key, result, settings.COMPRESS_OFFLINE_TIMEOUT)
                results.append(result)
                count += 1
Exemple #10
0
    def compress(self, log=None, **options):
        """
        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!).
        """
        extensions = options.get('extensions')
        extensions = self.handle_extensions(extensions or ['html'])
        verbosity = int(options.get("verbosity", 0))
        if not log:
            log = StringIO()
        if not settings.TEMPLATE_LOADERS:
            raise OfflineGenerationError("No template loaders defined. You "
                                         "must set TEMPLATE_LOADERS in your "
                                         "settings.")
        #from jingo import env

        paths = set()
        for loader in self.get_loaders():
            try:
                module = import_module(loader.__module__)
                get_template_sources = getattr(module, 'get_template_sources',
                                               None)
                if get_template_sources is None:
                    get_template_sources = loader.get_template_sources
                paths.update(list(get_template_sources('')))
            except (ImportError, AttributeError):
                # Yeah, this didn't work out so well, let's move on
                pass
        if not paths:
            raise OfflineGenerationError("No template paths found. None of "
                                         "the configured template loaders "
                                         "provided template paths. See "
                                         "http://django.me/template-loaders "
                                         "for more information on template "
                                         "loaders.")
        if verbosity > 1:
            log.write("Considering paths:\n\t" + "\n\t".join(paths) + "\n")
        templates = set()
        for path in paths:
            for root, dirs, files in walk(path,
                                          followlinks=options.get(
                                              'followlinks', False)):
                templates.update(
                    os.path.join(root, name) for name in files
                    if not name.startswith('.') and any(
                        fnmatch(name, "*%s" % glob) for glob in extensions))

        if not templates:
            raise OfflineGenerationError("No templates found. Make sure your "
                                         "TEMPLATE_LOADERS and TEMPLATE_DIRS "
                                         "settings are correct.")
        if verbosity > 1:
            log.write("Found templates:\n\t" + "\n\t".join(templates) + "\n")

        #from compressor.contrib.jinja2ext import CompressorExtension
        from jingo_offline_compressor.jinja2ext import CompressorExtension
        env.add_extension(CompressorExtension)

        compressor_nodes = SortedDict()
        for template_name in templates:
            try:
                #template_content = env.loader.get_source(env, template_name)[0]
                template_content = open(template_name).read()
                template = env.parse(template_content)
            except IOError:  # unreadable file -> ignore
                if verbosity > 0:
                    log.write("Unreadable template at: %s\n" % template_name)
                continue
            except TemplateSyntaxError, e:  # broken template -> ignore
                if verbosity > 0:
                    log.write("Invalid template %s: %s\n" % (template_name, e))
                continue
            except TemplateDoesNotExist:  # non existent template -> ignore
                if verbosity > 0:
                    log.write("Non-existent template at: %s\n" % template_name)
                continue
Exemple #11
0
            except TemplateDoesNotExist:  # non existent template -> ignore
                if verbosity > 0:
                    log.write("Non-existent template at: %s\n" % template_name)
                continue
            except UnicodeDecodeError:
                if verbosity > 0:
                    log.write("UnicodeDecodeError while trying to read "
                              "template %s\n" % template_name)
            nodes = list(self.walk_nodes(template))
            if nodes:
                template.template_name = template_name
                compressor_nodes.setdefault(template, []).extend(nodes)

        if not compressor_nodes:
            raise OfflineGenerationError(
                "No 'compress' template tags found in templates."
                "Try running compress command with --follow-links and/or"
                "--extension=EXTENSIONS")

        if verbosity > 0:
            log.write("Found 'compress' tags in:\n\t" +
                      "\n\t".join((t.template_name
                                   for t in compressor_nodes.keys())) + "\n")

        log.write("Compressing... ")
        count = 0
        results = []
        offline_manifest = SortedDict()
        for template, nodes in compressor_nodes.iteritems():
            context = Context(settings.COMPRESS_OFFLINE_CONTEXT)
            template._log = log
            template._log_verbosity = verbosity
Exemple #12
0
    def compress(self, log=None, **options):
        """
        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!).
        """
        extensions = options.get('extensions')
        extensions = self.handle_extensions(extensions or ['html'])
        verbosity = int(options.get("verbosity", 0))
        if not log:
            log = StringIO()
        if not settings.TEMPLATE_LOADERS:
            raise OfflineGenerationError("No template loaders defined. You "
                                         "must set TEMPLATE_LOADERS in your "
                                         "settings.")
        paths = set()
        for loader in self.get_loaders():
            try:
                module = import_module(loader.__module__)
                get_template_sources = getattr(module, 'get_template_sources',
                                               None)
                if get_template_sources is None:
                    get_template_sources = loader.get_template_sources
                paths.update(list(get_template_sources('')))
            except (ImportError, AttributeError):
                # Yeah, this didn't work out so well, let's move on
                pass
        if not paths:
            raise OfflineGenerationError("No template paths found. None of "
                                         "the configured template loaders "
                                         "provided template paths. See "
                                         "http://django.me/template-loaders "
                                         "for more information on template "
                                         "loaders.")
        if verbosity > 1:
            log.write("Considering paths:\n\t" + "\n\t".join(paths) + "\n")
        templates = set()
        for path in paths:
            for root, dirs, files in os.walk(path,
                                             followlinks=options.get(
                                                 'followlinks', False)):
                templates.update(
                    os.path.join(root, name) for name in files
                    if not name.startswith('.') and any(
                        fnmatch(name, "*%s" % glob) for glob in extensions))
        if not templates:
            raise OfflineGenerationError("No templates found. Make sure your "
                                         "TEMPLATE_LOADERS and TEMPLATE_DIRS "
                                         "settings are correct.")
        if verbosity > 1:
            log.write("Found templates:\n\t" + "\n\t".join(templates) + "\n")

        engine = options.get("engine", "django")
        parser = self.__get_parser(engine)

        compressor_nodes = SortedDict()
        for template_name in templates:
            try:
                template = parser.parse(template_name)
            except IOError:  # unreadable file -> ignore
                if verbosity > 0:
                    log.write("Unreadable template at: %s\n" % template_name)
                continue
            except TemplateSyntaxError as e:  # broken template -> ignore
                if verbosity > 0:
                    log.write("Invalid template %s: %s\n" % (template_name, e))
                continue
            except TemplateDoesNotExist:  # non existent template -> ignore
                if verbosity > 0:
                    log.write("Non-existent template at: %s\n" % template_name)
                continue
            except UnicodeDecodeError:
                if verbosity > 0:
                    log.write("UnicodeDecodeError while trying to read "
                              "template %s\n" % template_name)
            try:
                nodes = list(parser.walk_nodes(template))
            except (TemplateDoesNotExist, TemplateSyntaxError) as e:
                # Could be an error in some base template
                if verbosity > 0:
                    log.write("Error parsing template %s: %s\n" %
                              (template_name, e))
                continue
            if nodes:
                template.template_name = template_name
                compressor_nodes.setdefault(template, []).extend(nodes)

        if not compressor_nodes:
            raise OfflineGenerationError(
                "No 'compress' template tags found in templates."
                "Try running compress command with --follow-links and/or"
                "--extension=EXTENSIONS")

        if verbosity > 0:
            log.write("Found 'compress' tags in:\n\t" +
                      "\n\t".join((t.template_name
                                   for t in compressor_nodes.keys())) + "\n")

        log.write("Compressing... ")
        count = 0
        results = []
        offline_manifest = SortedDict()
        init_context = parser.get_init_context(
            settings.COMPRESS_OFFLINE_CONTEXT)

        for template, nodes in compressor_nodes.items():
            context = Context(init_context)
            template._log = log
            template._log_verbosity = verbosity

            if not parser.process_template(template, context):
                continue

            for node in nodes:
                context.push()
                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("An error occured during rendering %s: "
                                       "%s" % (template.template_name, e))
                offline_manifest[key] = result
                context.pop()
                results.append(result)
                count += 1

        write_offline_manifest(offline_manifest)

        log.write("done\nCompressed %d block(s) from %d template(s).\n" %
                  (count, len(compressor_nodes)))
        return count, results
    def compress(self, engine, extensions, verbosity, follow_links, log):
        """
        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!).
        """

        if not self.get_loaders():
            raise OfflineGenerationError("No template loaders defined. You "
                                         "must set TEMPLATE_LOADERS in your "
                                         "settings or set 'loaders' in your "
                                         "TEMPLATES dictionary.")
        templates = set()
        if engine == 'django':
            paths = set()
            for loader in self.get_loaders():
                try:
                    module = import_module(loader.__module__)
                    get_template_sources = getattr(module,
                                                   'get_template_sources',
                                                   None)
                    if get_template_sources is None:
                        get_template_sources = loader.get_template_sources
                    paths.update(
                        smart_str(origin)
                        for origin in get_template_sources(''))
                except (ImportError, AttributeError, TypeError):
                    # Yeah, this didn't work out so well, let's move on
                    pass

            if not paths:
                raise OfflineGenerationError(
                    "No template paths found. None of "
                    "the configured template loaders "
                    "provided template paths. See "
                    "https://docs.djangoproject.com/en/2.1/topics/templates/ "
                    "for more information on template "
                    "loaders.")
            if verbosity >= 2:
                log.write("Considering paths:\n\t" + "\n\t".join(paths) + "\n")

            for path in paths:
                for root, dirs, files in os.walk(path,
                                                 followlinks=follow_links):
                    templates.update(
                        os.path.relpath(os.path.join(root, name), path)
                        for name in files if not name.startswith('.') and any(
                            fnmatch(name, "*%s" % glob)
                            for glob in extensions))
        elif engine == 'jinja2':
            env = settings.COMPRESS_JINJA2_GET_ENVIRONMENT()
            if env and hasattr(env, '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("No templates found. Make sure your "
                                         "TEMPLATE_LOADERS and TEMPLATE_DIRS "
                                         "settings are correct.")
        if verbosity >= 2:
            log.write("Found templates:\n\t" + "\n\t".join(templates) + "\n")

        contexts = settings.COMPRESS_OFFLINE_CONTEXT
        if isinstance(contexts, str):
            try:
                module, function = get_mod_func(contexts)
                contexts = getattr(import_module(module), function)()
            except (AttributeError, ImportError, TypeError) as e:
                raise ImportError(
                    "Couldn't import offline context function %s: %s" %
                    (settings.COMPRESS_OFFLINE_CONTEXT, e))
        elif not isinstance(contexts, (list, tuple)):
            contexts = [contexts]

        parser = self.__get_parser(engine)
        fine_templates = []

        if verbosity >= 1:
            log.write("Compressing... ")

        for template_name in templates:
            try:
                template = parser.parse(template_name)
                template.template_name = template_name
                fine_templates.append(template)
            except IOError:  # unreadable file -> ignore
                if verbosity >= 1:
                    log.write("Unreadable template at: %s\n" % template_name)
                continue
            except TemplateSyntaxError as e:  # broken template -> ignore
                if verbosity >= 1:
                    log.write("Invalid template %s: %s\n" %
                              (template_name, smart_str(e)))
                continue
            except TemplateDoesNotExist:  # non existent template -> ignore
                if verbosity >= 1:
                    log.write("Non-existent template at: %s\n" % template_name)
                continue
            except UnicodeDecodeError:
                if verbosity >= 1:
                    log.write("UnicodeDecodeError while trying to read "
                              "template %s\n" % template_name)
                continue

        contexts_count = 0
        nodes_count = 0
        offline_manifest = OrderedDict()
        errors = []

        for context_dict in contexts:
            compressor_nodes = OrderedDict()
            for template in fine_templates:
                context = Context(parser.get_init_context(context_dict))

                try:
                    nodes = list(parser.walk_nodes(template, context=context))
                except (TemplateDoesNotExist, TemplateSyntaxError) as e:
                    # Could be an error in some base template
                    if verbosity >= 1:
                        log.write("Error parsing template %s: %s\n" %
                                  (template.template_name, smart_str(e)))
                    continue

                if nodes:
                    template_nodes = compressor_nodes.setdefault(
                        template, OrderedDict())
                    for node in nodes:
                        nodes_count += 1
                        template_nodes.setdefault(node, []).append(context)

            pool = concurrent.futures.ThreadPoolExecutor(max_workers=4)
            for template, nodes in compressor_nodes.items():
                template._log = log
                template._log_verbosity = verbosity

                pool.submit(self._compress_template, offline_manifest, nodes,
                            parser, template, errors)

            pool.shutdown(wait=True)
            contexts_count += 1

        # If errors exist, raise the first one in the list
        if errors:
            raise errors[0]
        elif not nodes_count:
            raise OfflineGenerationError(
                "No 'compress' template tags found in templates."
                "Try running compress command with --follow-links and/or"
                "--extension=EXTENSIONS")

        if verbosity >= 1:
            log.write(
                "done\nCompressed %d block(s) from %d template(s) for %d context(s).\n"
                % (len(offline_manifest), nodes_count, contexts_count))
        return offline_manifest, len(
            offline_manifest), offline_manifest.values()
Exemple #14
0
    def compress(self, log=None, **options):
        """
        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!).
        """
        extensions = options.get('extensions')
        extensions = self.handle_extensions(extensions or ['html'])
        verbosity = int(options.get("verbosity", 0))
        if not log:
            log = StringIO()
        if not settings.TEMPLATE_LOADERS:
            raise OfflineGenerationError("No template loaders defined. You "
                                         "must set TEMPLATE_LOADERS in your "
                                         "settings.")
        paths = set()
        for loader in self.get_loaders():
            try:
                module = import_module(loader.__module__)
                get_template_sources = getattr(module, 'get_template_sources',
                                               None)
                if get_template_sources is None:
                    get_template_sources = loader.get_template_sources
                paths.update(list(get_template_sources('')))
            except (ImportError, AttributeError):
                # Yeah, this didn't work out so well, let's move on
                pass
        if not paths:
            raise OfflineGenerationError("No template paths found. None of "
                                         "the configured template loaders "
                                         "provided template paths. See "
                                         "http://django.me/template-loaders "
                                         "for more information on template "
                                         "loaders.")
        if verbosity > 1:
            log.write("Considering paths:\n\t" + "\n\t".join(paths) + "\n")
        templates = set()
        for path in paths:
            for root, dirs, files in walk(path,
                                          followlinks=options.get(
                                              'followlinks', False)):
                templates.update(
                    os.path.join(root, name) for name in files
                    if not name.startswith('.') and any(
                        fnmatch(name, "*%s" % glob) for glob in extensions))
        if not templates:
            raise OfflineGenerationError("No templates found. Make sure your "
                                         "TEMPLATE_LOADERS and TEMPLATE_DIRS "
                                         "settings are correct.")
        if verbosity > 1:
            log.write("Found templates:\n\t" + "\n\t".join(templates) + "\n")

        compressor_nodes = SortedDict()
        for template_name in templates:
            try:
                template_file = open(template_name)
                try:
                    template = Template(template_file.read().decode(
                        settings.FILE_CHARSET))
                finally:
                    template_file.close()
            except IOError:  # unreadable file -> ignore
                if verbosity > 0:
                    log.write("Unreadable template at: %s\n" % template_name)
                continue
            except TemplateSyntaxError:  # broken template -> ignore
                if verbosity > 0:
                    log.write("Invalid template at: %s\n" % template_name)
                continue
            except UnicodeDecodeError:
                if verbosity > 0:
                    log.write("UnicodeDecodeError while trying to read "
                              "template %s\n" % template_name)
            nodes = list(self.walk_nodes(template))
            if nodes:
                template.template_name = template_name
                compressor_nodes.setdefault(template, []).extend(nodes)

        if not compressor_nodes:
            raise OfflineGenerationError(
                "No 'compress' template tags found in templates.")

        if verbosity > 0:
            log.write("Found 'compress' tags in:\n\t" +
                      "\n\t".join((t.template_name
                                   for t in compressor_nodes.keys())) + "\n")

        log.write("Compressing... ")
        count = 0
        results = []
        offline_manifest = {}
        for template, nodes in compressor_nodes.iteritems():
            context = Context(settings.COMPRESS_OFFLINE_CONTEXT)
            extra_context = {}
            firstnode = template.nodelist[0]
            if isinstance(firstnode, ExtendsNode):
                # If this template has a ExtendsNode, we apply our patch to
                # generate the necessary context, and then use it for all the
                # nodes in it, just in case (we don't know which nodes were
                # in a block)
                firstnode._old_get_parent = firstnode.get_parent
                firstnode.get_parent = MethodType(patched_get_parent,
                                                  firstnode)
                extra_context = firstnode.render(context)
                context.render_context = extra_context.render_context
            for node in nodes:
                context.push()
                if extra_context and node._block_name:
                    context['block'] = context.render_context[
                        BLOCK_CONTEXT_KEY].pop(node._block_name)
                    if context['block']:
                        context['block'].context = context
                key = get_offline_hexdigest(node.nodelist)
                try:
                    result = node.render(context, forced=True)
                except Exception, e:
                    raise CommandError("An error occured during rendering: "
                                       "%s" % e)
                offline_manifest[key] = result
                context.pop()
                results.append(result)
                count += 1
Exemple #15
0
    def compress(self, log=None, **options):
        """
        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!).
        """
        extensions = options.get('extensions')
        extensions = self.handle_extensions(extensions or ['mako'])
        verbosity = int(options.get("verbosity", 0))
        if not log:
            log = StringIO()
        if not self.get_loaders():
            raise OfflineGenerationError("No template loaders defined. You "
                                         "must set TEMPLATE_LOADERS in your "
                                         "settings or set 'loaders' in your "
                                         "TEMPLATES dictionary.")
        templates = set()
        for path in self.get_loaders()[0].directories:
            for root, dirs, files in os.walk(path,
                                             followlinks=options.get(
                                                 'followlinks', False)):
                templates.update(
                    os.path.join(root, name)[len(path):] for name in files
                    if not name.startswith('.') and any(
                        fnmatch(name, "*%s" % glob) for glob in extensions))

        if not templates:
            raise OfflineGenerationError("No templates found. Make sure your "
                                         "TEMPLATE_LOADERS and TEMPLATE_DIRS "
                                         "settings are correct.")
        if verbosity > 1:
            log.write("Found templates:\n\t" + "\n\t".join(templates) + "\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(
                    "Couldn't import offline context function %s: %s" %
                    (settings.COMPRESS_OFFLINE_CONTEXT, e))
        elif not isinstance(contexts, (list, tuple)):
            contexts = [contexts]
        contexts = list(contexts)  # evaluate generator

        parser = self.__get_parser()
        for template_name in templates:
            try:
                template = parser.get_template(template_name)
            except IOError:  # unreadable file -> ignore
                if verbosity > 0:
                    log.write("Unreadable template at: %s\n" % template_name)
                continue
            except TemplateSyntaxError as e:  # broken template -> ignore
                if verbosity > 0:
                    log.write("Invalid template %s: %s\n" %
                              (template_name, smart_text(e)))
                continue
            except TemplateDoesNotExist:  # non existent template -> ignore
                if verbosity > 0:
                    log.write("Non-existent template at: %s\n" % template_name)
                continue
            except UnicodeDecodeError:
                if verbosity > 0:
                    log.write("UnicodeDecodeError while trying to read "
                              "template %s\n" % template_name)
                continue

            for context_dict in contexts:
                try:
                    from django.test.client import RequestFactory
                    request = RequestFactory().get('/')
                    context_dict['request'] = request
                    # mako compress tag will compress and upadate manifest
                    template.render(context=context_dict, request=request)
                except (TemplateDoesNotExist, TemplateSyntaxError) as e:
                    # Could be an error in some base template
                    if verbosity > 0:
                        log.write("Error parsing template %s: %s\n" %
                                  (template_name, smart_text(e)))
                    continue