Ejemplo n.º 1
0
    def __init__(self, project, load_plugins=True):
        self.project = project
        self.root_path = os.path.abspath(project.tree)

        self.jinja_env = CustomJinjaEnvironment(
            autoescape=self.select_jinja_autoescape,
            extensions=["jinja2.ext.autoescape", "jinja2.ext.with_"],
            loader=jinja2.FileSystemLoader(os.path.join(self.root_path, "templates")),
        )

        from lektor.db import F

        self.jinja_env.filters.update(
            tojson=tojson_filter,
            latformat=lambda x, secs=True: format_lat_long(lat=x, secs=secs),
            longformat=lambda x, secs=True: format_lat_long(long=x, secs=secs),
            latlongformat=lambda x, secs=True: format_lat_long(secs=secs, *x),
            # By default filters need to be side-effect free.  This is not
            # the case for this one, so we need to make it as a dummy
            # context filter so that jinja2 will not inline it.
            url=jinja2.contextfilter(lambda ctx, *a, **kw: url_to(*a, **kw)),
            asseturl=jinja2.contextfilter(lambda ctx, *a, **kw: get_asset_url(*a, **kw)),
            markdown=jinja2.contextfilter(lambda ctx, *a, **kw: Markdown(*a, **kw)),
        )
        self.jinja_env.globals.update(
            F=F,
            url_to=url_to,
            site=site_proxy,
            config=config_proxy,
            bag=lookup_from_bag,
            get_random_id=lambda: uuid.uuid4().hex,
        )
        self.jinja_env.filters.update(
            datetimeformat=_pass_locale(dates.format_datetime),
            dateformat=_pass_locale(dates.format_date),
            timeformat=_pass_locale(dates.format_time),
        )

        from lektor.types import builtin_types

        self.types = builtin_types.copy()

        from lektor.publisher import builtin_publishers

        self.publishers = builtin_publishers.copy()

        # The plugins that are loaded for this environment.  This is
        # modified by the plugin controller and registry methods on the
        # environment.
        self.plugin_controller = PluginController(self)
        self.plugins = {}
        self.plugin_ids_by_class = {}
        self.build_programs = []
        self.special_file_assets = {}
        self.special_file_suffixes = {}
        self.custom_url_resolvers = []
        self.custom_generators = []

        if load_plugins:
            self.load_plugins()
Ejemplo n.º 2
0
    def __init__(self, project):
        self.project = project
        self.root_path = os.path.abspath(project.tree)

        self.jinja_env = CustomJinjaEnvironment(
            autoescape=self.select_jinja_autoescape,
            extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_'],
            loader=jinja2.FileSystemLoader(
                os.path.join(self.root_path, 'templates'))
        )

        from lektor.db import F
        self.jinja_env.filters.update(
            tojson=tojson_filter,
            # By default filters need to be side-effect free.  This is not
            # the case for this one, so we need to make it as a dummy
            # context filter so that jinja2 will not inline it.
            url=jinja2.contextfilter(
                lambda ctx, *a, **kw: url_to(*a, **kw)),
            asseturl=jinja2.contextfilter(
                lambda ctx, *a, **kw: url_to(get_asset_url(*a, **kw))),
        )
        self.jinja_env.globals.update(
            F=F,
            url_to=url_to,
            site=site_proxy,
            config=config_proxy,
            bag=lookup_from_bag,
            get_random_id=lambda: uuid.uuid4().hex,
        )

        from lektor.types import builtin_types
        self.types = builtin_types.copy()

        # The plugins that are loaded for this environment.  This is
        # modified by the plugin controller and registry methods on the
        # environment.
        self.plugin_controller = PluginController(self)
        self.plugins = {}
        self.build_programs = []
        self.special_file_assets = {}
        self.special_file_suffixes = {}
Ejemplo n.º 3
0
    def __init__(self, project, load_plugins=True):
        self.project = project
        self.root_path = os.path.abspath(project.tree)

        self.theme_paths = [os.path.join(self.root_path, 'themes', theme)
                            for theme in self.project.themes]

        if not self.theme_paths:
            # load the directories in the themes directory as the themes
            try:
                for fname in os.listdir(os.path.join(self.root_path, 'themes')):
                    f = os.path.join(self.root_path, 'themes', fname)
                    if os.path.isdir(f):
                        self.theme_paths.append(f)
            except OSError:
                pass

        template_paths = [os.path.join(path, 'templates')
                          for path in [self.root_path] + self.theme_paths]

        self.jinja_env = CustomJinjaEnvironment(
            autoescape=self.select_jinja_autoescape,
            extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_'],
            loader=jinja2.FileSystemLoader(
                template_paths)
        )

        from lektor.db import F, get_alts
        self.jinja_env.filters.update(
            tojson=tojson_filter,
            latformat=lambda x, secs=True: format_lat_long(lat=x, secs=secs),
            longformat=lambda x, secs=True: format_lat_long(long=x, secs=secs),
            latlongformat=lambda x, secs=True: format_lat_long(secs=secs, *x),
            # By default filters need to be side-effect free.  This is not
            # the case for this one, so we need to make it as a dummy
            # context filter so that jinja2 will not inline it.
            url=jinja2.contextfilter(
                lambda ctx, *a, **kw: url_to(*a, **kw)),
            asseturl=jinja2.contextfilter(
                lambda ctx, *a, **kw: get_asset_url(*a, **kw)),
            markdown=jinja2.contextfilter(
                lambda ctx, *a, **kw: Markdown(*a, **kw)),
        )
        self.jinja_env.globals.update(
            F=F,
            url_to=url_to,
            site=site_proxy,
            config=config_proxy,
            bag=lookup_from_bag,
            get_alts=get_alts,
            get_random_id=lambda: uuid.uuid4().hex,
        )
        self.jinja_env.filters.update(
            datetimeformat=_pass_locale(dates.format_datetime),
            dateformat=_pass_locale(dates.format_date),
            timeformat=_pass_locale(dates.format_time),
        )

        from lektor.types import builtin_types
        self.types = builtin_types.copy()

        from lektor.publisher import builtin_publishers
        self.publishers = builtin_publishers.copy()

        # The plugins that are loaded for this environment.  This is
        # modified by the plugin controller and registry methods on the
        # environment.
        self.plugin_controller = PluginController(self)
        self.plugins = {}
        self.plugin_ids_by_class = {}
        self.build_programs = []
        self.special_file_assets = {}
        self.special_file_suffixes = {}
        self.custom_url_resolvers = []
        self.custom_generators = []
        self.virtual_sources = {}

        if load_plugins:
            self.load_plugins()

        from lektor.db import siblings_resolver
        self.virtualpathresolver('siblings')(siblings_resolver)
Ejemplo n.º 4
0
class Environment(object):

    def __init__(self, project, load_plugins=True):
        self.project = project
        self.root_path = os.path.abspath(project.tree)

        self.theme_paths = [os.path.join(self.root_path, 'themes', theme)
                            for theme in self.project.themes]

        if not self.theme_paths:
            # load the directories in the themes directory as the themes
            try:
                for fname in os.listdir(os.path.join(self.root_path, 'themes')):
                    f = os.path.join(self.root_path, 'themes', fname)
                    if os.path.isdir(f):
                        self.theme_paths.append(f)
            except OSError:
                pass

        template_paths = [os.path.join(path, 'templates')
                          for path in [self.root_path] + self.theme_paths]

        self.jinja_env = CustomJinjaEnvironment(
            autoescape=self.select_jinja_autoescape,
            extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_'],
            loader=jinja2.FileSystemLoader(
                template_paths)
        )

        from lektor.db import F, get_alts
        self.jinja_env.filters.update(
            tojson=tojson_filter,
            latformat=lambda x, secs=True: format_lat_long(lat=x, secs=secs),
            longformat=lambda x, secs=True: format_lat_long(long=x, secs=secs),
            latlongformat=lambda x, secs=True: format_lat_long(secs=secs, *x),
            # By default filters need to be side-effect free.  This is not
            # the case for this one, so we need to make it as a dummy
            # context filter so that jinja2 will not inline it.
            url=jinja2.contextfilter(
                lambda ctx, *a, **kw: url_to(*a, **kw)),
            asseturl=jinja2.contextfilter(
                lambda ctx, *a, **kw: get_asset_url(*a, **kw)),
            markdown=jinja2.contextfilter(
                lambda ctx, *a, **kw: Markdown(*a, **kw)),
        )
        self.jinja_env.globals.update(
            F=F,
            url_to=url_to,
            site=site_proxy,
            config=config_proxy,
            bag=lookup_from_bag,
            get_alts=get_alts,
            get_random_id=lambda: uuid.uuid4().hex,
        )
        self.jinja_env.filters.update(
            datetimeformat=_pass_locale(dates.format_datetime),
            dateformat=_pass_locale(dates.format_date),
            timeformat=_pass_locale(dates.format_time),
        )

        from lektor.types import builtin_types
        self.types = builtin_types.copy()

        from lektor.publisher import builtin_publishers
        self.publishers = builtin_publishers.copy()

        # The plugins that are loaded for this environment.  This is
        # modified by the plugin controller and registry methods on the
        # environment.
        self.plugin_controller = PluginController(self)
        self.plugins = {}
        self.plugin_ids_by_class = {}
        self.build_programs = []
        self.special_file_assets = {}
        self.special_file_suffixes = {}
        self.custom_url_resolvers = []
        self.custom_generators = []
        self.virtual_sources = {}

        if load_plugins:
            self.load_plugins()

        from lektor.db import siblings_resolver
        self.virtualpathresolver('siblings')(siblings_resolver)

    @property
    def asset_path(self):
        return os.path.join(self.root_path, 'assets')

    @property
    def temp_path(self):
        return os.path.join(self.root_path, 'temp')

    def load_plugins(self):
        """Loads the plugins."""
        from .packages import load_packages
        from .pluginsystem import initialize_plugins
        load_packages(self)
        initialize_plugins(self)

    def load_config(self):
        """Loads the current config."""
        return Config(self.project.project_file)

    def new_pad(self):
        """Convenience function to create a database and pad."""
        from lektor.db import Database
        return Database(self).new_pad()

    def is_uninteresting_source_name(self, filename):
        """These files are ignored when sources are built into artifacts."""
        fn = filename.lower()
        if fn in SPECIAL_ARTIFACTS:
            return False

        proj = self.project
        if any_fnmatch(filename, INCLUDED_ASSETS + proj.included_assets):
            # Included by the user's project config, thus not uninteresting.
            return False
        return any_fnmatch(filename, EXCLUDED_ASSETS + proj.excluded_assets)

    def is_ignored_artifact(self, asset_name):
        """This is used by the prune tool to figure out which files in the
        artifact folder should be ignored.
        """
        fn = asset_name.lower()
        if fn in SPECIAL_ARTIFACTS:
            return False
        return fn[:1] == '.' or fn in IGNORED_FILES

    def render_template(self, name, pad=None, this=None, values=None, alt=None):
        ctx = self.make_default_tmpl_values(pad, this, values, alt,
                                            template=name)
        return self.jinja_env.get_or_select_template(name).render(ctx)

    def make_default_tmpl_values(self, pad=None, this=None, values=None, alt=None,
                                 template=None):
        values = dict(values or ())

        # If not provided, pick the alt from the provided "this" object.
        # As there is no mandatory format for it, we make sure that we can
        # deal with a bad attribute there.
        if alt is None:
            if this is not None:
                alt = getattr(this, 'alt', None)
                if not isinstance(alt, string_types):
                    alt = None
            if alt is None:
                alt = PRIMARY_ALT

        # This is already a global variable but we can inject it as a
        # local override if available.
        if pad is None:
            ctx = get_ctx()
            if ctx is not None:
                pad = ctx.pad
        if pad is not None:
            values['site'] = pad
        if this is not None:
            values['this'] = this
        if alt is not None:
            values['alt'] = alt
        self.plugin_controller.emit('process-template-context',
                                    context=values, template=template)
        return values

    def select_jinja_autoescape(self, filename):
        if filename is None:
            return False
        return filename.endswith(('.html', '.htm', '.xml', '.xhtml'))

    def resolve_custom_url_path(self, obj, url_path):
        for resolver in self.custom_url_resolvers:
            rv = resolver(obj, url_path)
            if rv is not None:
                return rv
        return None

    # -- methods for the plugin system

    def add_build_program(self, cls, program):
        self.build_programs.append((cls, program))

    def add_asset_type(self, asset_cls, build_program):
        self.build_programs.append((asset_cls, build_program))
        self.special_file_assets[asset_cls.source_extension] = asset_cls
        if asset_cls.artifact_extension:
            cext = asset_cls.source_extension + asset_cls.artifact_extension
            self.special_file_suffixes[cext] = asset_cls.source_extension

    def add_publisher(self, scheme, publisher):
        if scheme in self.publishers:
            raise RuntimeError('Scheme "%s" is already registered.' % scheme)
        self.publishers[scheme] = publisher

    def add_type(self, type):
        name = type.name
        if name in self.types:
            raise RuntimeError('Type "%s" is already registered.' % name)
        self.types[name] = type

    def virtualpathresolver(self, prefix):
        def decorator(func):
            if prefix in self.virtual_sources:
                raise RuntimeError('Prefix "%s" is already registered.'
                                   % prefix)
            self.virtual_sources[prefix] = func
            return func
        return decorator

    def urlresolver(self, func):
        self.custom_url_resolvers.append(func)
        return func

    def generator(self, func):
        self.custom_generators.append(func)
        return func
Ejemplo n.º 5
0
class Environment:
    def __init__(self, project, load_plugins=True, extra_flags=None):
        self.project = project
        self.root_path = os.path.abspath(project.tree)

        self.theme_paths = [
            os.path.join(self.root_path, "themes", theme)
            for theme in self.project.themes
        ]

        if not self.theme_paths:
            # load the directories in the themes directory as the themes
            try:
                for fname in os.listdir(os.path.join(self.root_path, "themes")):
                    f = os.path.join(self.root_path, "themes", fname)
                    if os.path.isdir(f):
                        self.theme_paths.append(f)
            except OSError:
                pass

        template_paths = [
            os.path.join(path, "templates")
            for path in [self.root_path] + self.theme_paths
        ]

        self.jinja_env = CustomJinjaEnvironment(
            autoescape=self.select_jinja_autoescape,
            extensions=["jinja2.ext.autoescape", "jinja2.ext.with_", "jinja2.ext.do"],
            loader=jinja2.FileSystemLoader(template_paths),
        )

        from lektor.db import F, get_alts  # pylint: disable=import-outside-toplevel

        self.jinja_env.filters.update(
            tojson=tojson_filter,
            latformat=lambda x, secs=True: format_lat_long(lat=x, secs=secs),
            longformat=lambda x, secs=True: format_lat_long(long=x, secs=secs),
            latlongformat=lambda x, secs=True: format_lat_long(secs=secs, *x),
            # By default filters need to be side-effect free.  This is not
            # the case for this one, so we need to make it as a dummy
            # context filter so that jinja2 will not inline it.
            url=jinja2.contextfilter(lambda ctx, *a, **kw: url_to(*a, **kw)),
            asseturl=jinja2.contextfilter(
                lambda ctx, *a, **kw: get_asset_url(*a, **kw)
            ),
            markdown=jinja2.contextfilter(lambda ctx, *a, **kw: Markdown(*a, **kw)),
        )
        self.jinja_env.globals.update(
            F=F,
            url_to=url_to,
            site=site_proxy,
            config=config_proxy,
            bag=lookup_from_bag,
            get_alts=get_alts,
            get_random_id=lambda: uuid.uuid4().hex,
        )
        self.jinja_env.filters.update(
            datetimeformat=_pass_locale(dates.format_datetime),
            dateformat=_pass_locale(dates.format_date),
            timeformat=_pass_locale(dates.format_time),
        )

        self.types = builtin_types.copy()

        self.publishers = builtin_publishers.copy()

        # The plugins that are loaded for this environment.  This is
        # modified by the plugin controller and registry methods on the
        # environment.
        self.plugin_controller = PluginController(self, extra_flags)
        self.plugins = {}
        self.plugin_ids_by_class = {}
        self.build_programs = []
        self.special_file_assets = {}
        self.special_file_suffixes = {}
        self.custom_url_resolvers = []
        self.custom_generators = []
        self.virtual_sources = {}

        if load_plugins:
            self.load_plugins()
        # pylint: disable=import-outside-toplevel
        from lektor.db import siblings_resolver

        self.virtualpathresolver("siblings")(siblings_resolver)

    @property
    def asset_path(self):
        return os.path.join(self.root_path, "assets")

    @property
    def temp_path(self):
        return os.path.join(self.root_path, "temp")

    def load_plugins(self):
        """Loads the plugins."""
        load_packages(self)
        initialize_plugins(self)

    def load_config(self):
        """Loads the current config."""
        return Config(self.project.project_file)

    def new_pad(self):
        """Convenience function to create a database and pad."""
        from lektor.db import Database  # pylint: disable=import-outside-toplevel

        return Database(self).new_pad()

    def is_uninteresting_source_name(self, filename):
        """These files are ignored when sources are built into artifacts."""
        fn = filename.lower()
        if fn in SPECIAL_ARTIFACTS:
            return False

        proj = self.project
        if any_fnmatch(filename, INCLUDED_ASSETS + proj.included_assets):
            # Included by the user's project config, thus not uninteresting.
            return False
        return any_fnmatch(filename, EXCLUDED_ASSETS + proj.excluded_assets)

    @staticmethod
    def is_ignored_artifact(asset_name):
        """This is used by the prune tool to figure out which files in the
        artifact folder should be ignored.
        """
        fn = asset_name.lower()
        if fn in SPECIAL_ARTIFACTS:
            return False
        return fn[:1] == "." or fn in IGNORED_FILES

    def render_template(self, name, pad=None, this=None, values=None, alt=None):
        ctx = self.make_default_tmpl_values(pad, this, values, alt, template=name)
        return self.jinja_env.get_or_select_template(name).render(ctx)

    def make_default_tmpl_values(
        self, pad=None, this=None, values=None, alt=None, template=None
    ):
        values = dict(values or ())

        # If not provided, pick the alt from the provided "this" object.
        # As there is no mandatory format for it, we make sure that we can
        # deal with a bad attribute there.
        if alt is None:
            if this is not None:
                alt = getattr(this, "alt", None)
                if not isinstance(alt, str):
                    alt = None
            if alt is None:
                alt = PRIMARY_ALT

        # This is already a global variable but we can inject it as a
        # local override if available.
        if pad is None:
            ctx = get_ctx()
            if ctx is not None:
                pad = ctx.pad
        if pad is not None:
            values["site"] = pad
        if this is not None:
            values["this"] = this
        if alt is not None:
            values["alt"] = alt
        self.plugin_controller.emit(
            "process-template-context", context=values, template=template
        )
        return values

    @staticmethod
    def select_jinja_autoescape(filename):
        if filename is None:
            return False
        return filename.endswith((".html", ".htm", ".xml", ".xhtml"))

    def resolve_custom_url_path(self, obj, url_path):
        for resolver in self.custom_url_resolvers:
            rv = resolver(obj, url_path)
            if rv is not None:
                return rv
        return None

    # -- methods for the plugin system

    def add_build_program(self, cls, program):
        self.build_programs.append((cls, program))

    def add_asset_type(self, asset_cls, build_program):
        self.build_programs.append((asset_cls, build_program))
        self.special_file_assets[asset_cls.source_extension] = asset_cls
        if asset_cls.artifact_extension:
            cext = asset_cls.source_extension + asset_cls.artifact_extension
            self.special_file_suffixes[cext] = asset_cls.source_extension

    def add_publisher(self, scheme, publisher):
        if scheme in self.publishers:
            raise RuntimeError('Scheme "%s" is already registered.' % scheme)
        self.publishers[scheme] = publisher

    def add_type(self, type):
        name = type.name
        if name in self.types:
            raise RuntimeError('Type "%s" is already registered.' % name)
        self.types[name] = type

    def virtualpathresolver(self, prefix):
        def decorator(func):
            if prefix in self.virtual_sources:
                raise RuntimeError('Prefix "%s" is already registered.' % prefix)
            self.virtual_sources[prefix] = func
            return func

        return decorator

    def urlresolver(self, func):
        self.custom_url_resolvers.append(func)
        return func

    def generator(self, func):
        self.custom_generators.append(func)
        return func
Ejemplo n.º 6
0
    def __init__(self, project, load_plugins=True, extra_flags=None):
        self.project = project
        self.root_path = os.path.abspath(project.tree)

        self.theme_paths = [
            os.path.join(self.root_path, "themes", theme)
            for theme in self.project.themes
        ]

        if not self.theme_paths:
            # load the directories in the themes directory as the themes
            try:
                for fname in os.listdir(os.path.join(self.root_path, "themes")):
                    f = os.path.join(self.root_path, "themes", fname)
                    if os.path.isdir(f):
                        self.theme_paths.append(f)
            except OSError:
                pass

        template_paths = [
            os.path.join(path, "templates")
            for path in [self.root_path] + self.theme_paths
        ]

        self.jinja_env = CustomJinjaEnvironment(
            autoescape=self.select_jinja_autoescape,
            extensions=["jinja2.ext.autoescape", "jinja2.ext.with_", "jinja2.ext.do"],
            loader=jinja2.FileSystemLoader(template_paths),
        )

        from lektor.db import F, get_alts

        self.jinja_env.filters.update(
            tojson=tojson_filter,
            latformat=lambda x, secs=True: format_lat_long(lat=x, secs=secs),
            longformat=lambda x, secs=True: format_lat_long(long=x, secs=secs),
            latlongformat=lambda x, secs=True: format_lat_long(secs=secs, *x),
            # By default filters need to be side-effect free.  This is not
            # the case for this one, so we need to make it as a dummy
            # context filter so that jinja2 will not inline it.
            url=jinja2.contextfilter(lambda ctx, *a, **kw: url_to(*a, **kw)),
            asseturl=jinja2.contextfilter(
                lambda ctx, *a, **kw: get_asset_url(*a, **kw)
            ),
            markdown=jinja2.contextfilter(lambda ctx, *a, **kw: Markdown(*a, **kw)),
        )
        self.jinja_env.globals.update(
            F=F,
            url_to=url_to,
            site=site_proxy,
            config=config_proxy,
            bag=lookup_from_bag,
            get_alts=get_alts,
            get_random_id=lambda: uuid.uuid4().hex,
        )
        self.jinja_env.filters.update(
            datetimeformat=_pass_locale(dates.format_datetime),
            dateformat=_pass_locale(dates.format_date),
            timeformat=_pass_locale(dates.format_time),
        )

        from lektor.types import builtin_types

        self.types = builtin_types.copy()

        from lektor.publisher import builtin_publishers

        self.publishers = builtin_publishers.copy()

        # The plugins that are loaded for this environment.  This is
        # modified by the plugin controller and registry methods on the
        # environment.
        self.plugin_controller = PluginController(self, extra_flags)
        self.plugins = {}
        self.plugin_ids_by_class = {}
        self.build_programs = []
        self.special_file_assets = {}
        self.special_file_suffixes = {}
        self.custom_url_resolvers = []
        self.custom_generators = []
        self.virtual_sources = {}

        if load_plugins:
            self.load_plugins()

        from lektor.db import siblings_resolver

        self.virtualpathresolver("siblings")(siblings_resolver)
Ejemplo n.º 7
0
    def __init__(self, project, load_plugins=True):
        self.project = project
        self.root_path = os.path.abspath(project.tree)

        self.jinja_env = CustomJinjaEnvironment(
            autoescape=self.select_jinja_autoescape,
            extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_'],
            loader=jinja2.FileSystemLoader(
                os.path.join(self.root_path, 'templates'))
        )

        from lektor.db import F
        self.jinja_env.filters.update(
            tojson=tojson_filter,
            latformat=lambda x, secs=True: format_lat_long(lat=x, secs=secs),
            longformat=lambda x, secs=True: format_lat_long(long=x, secs=secs),
            latlongformat=lambda x, secs=True: format_lat_long(secs=secs, *x),
            # By default filters need to be side-effect free.  This is not
            # the case for this one, so we need to make it as a dummy
            # context filter so that jinja2 will not inline it.
            url=jinja2.contextfilter(
                lambda ctx, *a, **kw: url_to(*a, **kw)),
            asseturl=jinja2.contextfilter(
                lambda ctx, *a, **kw: get_asset_url(*a, **kw)),
            markdown=jinja2.contextfilter(
                lambda ctx, *a, **kw: Markdown(*a, **kw)),
        )
        self.jinja_env.globals.update(
            F=F,
            url_to=url_to,
            site=site_proxy,
            config=config_proxy,
            bag=lookup_from_bag,
            get_random_id=lambda: uuid.uuid4().hex,
        )
        self.jinja_env.filters.update(
            datetimeformat=_pass_locale(dates.format_datetime),
            dateformat=_pass_locale(dates.format_date),
            timeformat=_pass_locale(dates.format_time),
        )

        from lektor.types import builtin_types
        self.types = builtin_types.copy()

        from lektor.publisher import builtin_publishers
        self.publishers = builtin_publishers.copy()

        # The plugins that are loaded for this environment.  This is
        # modified by the plugin controller and registry methods on the
        # environment.
        self.plugin_controller = PluginController(self)
        self.plugins = {}
        self.plugin_ids_by_class = {}
        self.build_programs = []
        self.special_file_assets = {}
        self.special_file_suffixes = {}
        self.custom_url_resolvers = []
        self.custom_generators = []

        if load_plugins:
            self.load_plugins()
Ejemplo n.º 8
0
class Environment(object):

    def __init__(self, project, load_plugins=True):
        self.project = project
        self.root_path = os.path.abspath(project.tree)

        self.jinja_env = CustomJinjaEnvironment(
            autoescape=self.select_jinja_autoescape,
            extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_'],
            loader=jinja2.FileSystemLoader(
                os.path.join(self.root_path, 'templates'))
        )

        from lektor.db import F
        self.jinja_env.filters.update(
            tojson=tojson_filter,
            latformat=lambda x, secs=True: format_lat_long(lat=x, secs=secs),
            longformat=lambda x, secs=True: format_lat_long(long=x, secs=secs),
            latlongformat=lambda x, secs=True: format_lat_long(secs=secs, *x),
            # By default filters need to be side-effect free.  This is not
            # the case for this one, so we need to make it as a dummy
            # context filter so that jinja2 will not inline it.
            url=jinja2.contextfilter(
                lambda ctx, *a, **kw: url_to(*a, **kw)),
            asseturl=jinja2.contextfilter(
                lambda ctx, *a, **kw: get_asset_url(*a, **kw)),
            markdown=jinja2.contextfilter(
                lambda ctx, *a, **kw: Markdown(*a, **kw)),
        )
        self.jinja_env.globals.update(
            F=F,
            url_to=url_to,
            site=site_proxy,
            config=config_proxy,
            bag=lookup_from_bag,
            get_random_id=lambda: uuid.uuid4().hex,
        )
        self.jinja_env.filters.update(
            datetimeformat=_pass_locale(dates.format_datetime),
            dateformat=_pass_locale(dates.format_date),
            timeformat=_pass_locale(dates.format_time),
        )

        from lektor.types import builtin_types
        self.types = builtin_types.copy()

        from lektor.publisher import builtin_publishers
        self.publishers = builtin_publishers.copy()

        # The plugins that are loaded for this environment.  This is
        # modified by the plugin controller and registry methods on the
        # environment.
        self.plugin_controller = PluginController(self)
        self.plugins = {}
        self.plugin_ids_by_class = {}
        self.build_programs = []
        self.special_file_assets = {}
        self.special_file_suffixes = {}
        self.custom_url_resolvers = []
        self.custom_generators = []

        if load_plugins:
            self.load_plugins()

    @property
    def asset_path(self):
        return os.path.join(self.root_path, 'assets')

    @property
    def temp_path(self):
        return os.path.join(self.root_path, 'temp')

    def load_plugins(self):
        """Loads the plugins."""
        from .packages import load_packages
        from .pluginsystem import initialize_plugins
        load_packages(self)
        initialize_plugins(self)

    def load_config(self):
        """Loads the current config."""
        return Config(self.project.project_file)

    def new_pad(self):
        """Convenience function to create a database and pad."""
        from lektor.db import Database
        return Database(self).new_pad()

    def is_uninteresting_source_name(self, filename):
        """These files are always ignored when sources are built into
        artifacts.
        """
        fn = filename.lower()
        if fn in SPECIAL_ARTIFACTS:
            return False
        return filename[:1] in '._' or fn in IGNORED_FILES

    def is_ignored_artifact(self, asset_name):
        """This is used by the prune tool to figure out which files in the
        artifact folder should be ignored.
        """
        fn = asset_name.lower()
        if fn in SPECIAL_ARTIFACTS:
            return False
        return fn[:1] == '.' or fn in IGNORED_FILES

    def render_template(self, name, pad=None, this=None, values=None, alt=None):
        ctx = self.make_default_tmpl_values(pad, this, values, alt,
                                            template=name)
        return self.jinja_env.get_or_select_template(name).render(ctx)

    def make_default_tmpl_values(self, pad=None, this=None, values=None, alt=None,
                                 template=None):
        values = dict(values or ())

        # If not provided, pick the alt from the provided "this" object.
        # As there is no mandatory format for it, we make sure that we can
        # deal with a bad attribute there.
        if alt is None:
            if this is not None:
                alt = getattr(this, 'alt', None)
                if not isinstance(alt, basestring):
                    alt = None
            if alt is None:
                alt = PRIMARY_ALT

        # This is already a global variable but we can inject it as a
        # local override if available.
        if pad is None:
            ctx = get_ctx()
            if ctx is not None:
                pad = ctx.pad
        if pad is not None:
            values['site'] = pad
        if this is not None:
            values['this'] = this
        if alt is not None:
            values['alt'] = alt
        self.plugin_controller.emit('process-template-context',
                                    context=values, template=template)
        return values

    def select_jinja_autoescape(self, filename):
        if filename is None:
            return False
        return filename.endswith(('.html', '.htm', '.xml', '.xhtml'))

    def resolve_custom_url_path(self, obj, url_path):
        for resolver in self.custom_url_resolvers:
            rv = resolver(obj, url_path)
            if rv is not None:
                return rv

    # -- methods for the plugin system

    def add_build_program(self, cls, program):
        self.build_programs.append((cls, program))

    def add_asset_type(self, asset_cls, build_program):
        self.build_programs.append((asset_cls, build_program))
        self.special_file_assets[asset_cls.source_extension] = asset_cls
        if asset_cls.artifact_extension:
            cext = asset_cls.source_extension + asset_cls.artifact_extension
            self.special_file_suffixes[cext] = asset_cls.source_extension

    def add_publisher(self, scheme, publisher):
        if scheme in self.publishers:
            raise RuntimeError('Scheme "%s" is already registered.' % scheme)
        self.publishers[scheme] = publisher

    def urlresolver(self, func):
        self.custom_url_resolvers.append(func)
        return func

    def generator(self, func):
        self.custom_generators.append(func)
        return func
Ejemplo n.º 9
0
 def test_env_went_away(self):
     env = mock.Mock(name="env", spec=())
     plugin_controller = PluginController(env)
     del env
     with pytest.raises(RuntimeError, match=r"Environment went away"):
         getattr(plugin_controller, "env")
Ejemplo n.º 10
0
 def plugin_controller(self, env, extra_flags):
     return PluginController(env, extra_flags)
Ejemplo n.º 11
0
class Environment(object):

    def __init__(self, project):
        self.project = project
        self.root_path = os.path.abspath(project.tree)

        self.jinja_env = CustomJinjaEnvironment(
            autoescape=self.select_jinja_autoescape,
            extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_'],
            loader=jinja2.FileSystemLoader(
                os.path.join(self.root_path, 'templates'))
        )

        from lektor.db import F
        self.jinja_env.filters.update(
            tojson=tojson_filter,
            # By default filters need to be side-effect free.  This is not
            # the case for this one, so we need to make it as a dummy
            # context filter so that jinja2 will not inline it.
            url=jinja2.contextfilter(
                lambda ctx, *a, **kw: url_to(*a, **kw)),
            asseturl=jinja2.contextfilter(
                lambda ctx, *a, **kw: url_to(get_asset_url(*a, **kw))),
        )
        self.jinja_env.globals.update(
            F=F,
            url_to=url_to,
            site=site_proxy,
            config=config_proxy,
            bag=lookup_from_bag,
            get_random_id=lambda: uuid.uuid4().hex,
        )

        from lektor.types import builtin_types
        self.types = builtin_types.copy()

        # The plugins that are loaded for this environment.  This is
        # modified by the plugin controller and registry methods on the
        # environment.
        self.plugin_controller = PluginController(self)
        self.plugins = {}
        self.build_programs = []
        self.special_file_assets = {}
        self.special_file_suffixes = {}

    @property
    def asset_path(self):
        return os.path.join(self.root_path, 'assets')

    @property
    def temp_path(self):
        return os.path.join(self.root_path, 'temp')

    def load_config(self):
        """Loads the current config."""
        return Config(self.project.project_file)

    def is_uninteresting_source_name(self, filename):
        """These files are always ignored when sources are built into
        artifacts.
        """
        fn = filename.lower()
        if fn in SPECIAL_ARTIFACTS or fn in SPECIAL_SOURCES:
            return False
        return filename[:1] in '._' or fn in IGNORED_FILES

    def is_ignored_artifact(self, asset_name):
        """This is used by the prune tool to figure out which files in the
        artifact folder should be ignored.  This is a bi
        """
        fn = asset_name.lower()
        if fn in SPECIAL_ARTIFACTS:
            return False
        return fn[:1] in '._' or fn in IGNORED_FILES

    def render_template(self, name, pad=None, this=None, values=None, alt=None):
        ctx = self.make_default_tmpl_values(pad, this, values, alt)
        return self.jinja_env.get_or_select_template(name).render(ctx)

    def make_default_tmpl_values(self, pad=None, this=None, values=None, alt=None):
        values = dict(values or ())

        # If not provided, pick the alt from the provided "this" object.
        # As there is no mandatory format for it, we make sure that we can
        # deal with a bad attribute there.
        if alt is None:
            if this is not None:
                alt = getattr(this, 'alt', None)
                if not isinstance(alt, basestring):
                    alt = None
            if alt is None:
                alt = PRIMARY_ALT

        # This is already a global variable but we can inject it as a
        # local override if available.
        if pad is None:
            ctx = get_ctx()
            if ctx is not None:
                pad = ctx.pad
        if pad is not None:
            values['site'] = pad
        if this is not None:
            values['this'] = this
        if alt is not None:
            values['alt'] = alt
        self.plugin_controller.emit('process_template_context', context=values)
        return values

    def select_jinja_autoescape(self, filename):
        if filename is None:
            return False
        return filename.endswith(('.html', '.htm', '.xml', '.xhtml'))

    # -- methods for the plugin system

    def add_asset_type(self, asset_cls, build_program):
        self.build_programs.append((asset_cls, build_program))
        self.special_file_assets[asset_cls.source_extension] = asset_cls
        if asset_cls.artifact_extension:
            cext = asset_cls.source_extension + asset_cls.artifact_extension
            self.special_file_suffixes[cext] = asset_cls.source_extension