diff --git a/docs/index.rst b/docs/index.rst index 6ad22670..34a1355c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -61,6 +61,7 @@ A French version of the documentation is available at :doc:`fr/index`. getting_started settings themes + plugins internals pelican-themes importer diff --git a/docs/plugins.rst b/docs/plugins.rst new file mode 100644 index 00000000..db5a4bfc --- /dev/null +++ b/docs/plugins.rst @@ -0,0 +1,108 @@ +.. _plugins: + +Plugins +####### + +Since version 3.0, pelican manages plugins. Plugins are a way to add features +to pelican without having to directly hack pelican code. + +Pelican is shipped with a set of core plugins, but you can easily implement +your own (and this page describes how). + +How to use plugins? +==================== + +To load plugins, you have to specify them in your settings file. You have two +ways to do so. +Either by specifying strings with the path to the callables:: + + PLUGINS = ['pelican.plugins.gravatar',] + +Or by importing them and adding them to the list:: + + from pelican.plugins import gravatar + PLUGINS = [gravatar, ] + +If your plugins are not in an importable path, you can specify a `PLUGIN_PATH` +in the settings:: + + PLUGIN_PATH = "plugins" + PLUGINS = ["list", "of", "plugins"] + +How to create plugins? +====================== + +Plugins are based on the concept of signals. Pelican sends signals and plugins +subscribe to those signals. The list of signals are defined in a following +section. + +The only rule to follow for plugins is to define a `register` callable, in +which you map the signals to your plugin logic. Let's take a simple exemple:: + + from pelican import signals + + def test(sender): + print "%s initialized !!" % sender + + def register(): + signals.initialized.connect(test) + + +List of signals +=============== + +Here is the list of currently implemented signals: + +========================= ============================ ========================================= +Signal Arguments Description +========================= ============================ ========================================= +initialized pelican object +article_generate_context article_generator, metadata +article_generator_init article_generator invoked in the ArticlesGenerator.__init__ +========================= ============================ ========================================= + +The list is currently small, don't hesitate to add signals and make a pull +request if you need them! + +List of plugins +=============== + +Not all the list are described here, but a few of them have been extracted from +pelican core and provided in pelican.plugins. They are described here: + +Tag cloud +--------- + +Translation +----------- + +Github Activity +--------------- + +This plugin makes use of the ``feedparser`` library that you'll need to +install. + +Set the GITHUB_ACTIVITY_FEED parameter to your github activity feed. +For example, my setting would look like:: + + GITHUB_ACTIVITY_FEED = 'https://github.com/kpanic.atom' + +On the templates side, you just have to iterate over the ``github_activity`` +variable, as in the example:: + + {% if GITHUB_ACTIVITY_FEED %} +
+ {% endif %} + + + +``github_activity`` is a list of lists. The first element is the title +and the second element is the raw html from github. diff --git a/docs/settings.rst b/docs/settings.rst index 582cd9d4..b36c9953 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -61,6 +61,7 @@ Setting name (default value) What doe `rst2pdf`. `RELATIVE_URLS` (``True``) Defines whether Pelican should use relative URLs or not. +`PLUGINS` (``[]``) The list of plugins to load. See :ref:`plugins`. `SITENAME` (``'A Pelican Blog'``) Your site name `SITEURL` Base URL of your website. Not defined by default, which means the base URL is assumed to be "/" with a diff --git a/pelican/__init__.py b/pelican/__init__.py index 7e546b29..e942393c 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -5,6 +5,8 @@ import time import logging import argparse +from pelican import signals + from pelican.generators import (ArticlesGenerator, PagesGenerator, StaticGenerator, PdfGenerator, LessCSSGenerator) from pelican.log import init @@ -22,7 +24,7 @@ logger = logging.getLogger(__name__) class Pelican(object): def __init__(self, settings=None, path=None, theme=None, output_path=None, - markup=None, delete_outputdir=False): + markup=None, delete_outputdir=False, plugin_path=None): """Read the settings, and performs some checks on the environment before doing anything else. """ @@ -58,6 +60,20 @@ class Pelican(object): else: raise Exception("Impossible to find the theme %s" % theme) + self.init_plugins() + signals.initialized.send(self) + + def init_plugins(self): + self.plugins = self.settings['PLUGINS'] + for plugin in self.plugins: + # if it's a string, then import it + if isinstance(plugin, basestring): + log.debug("Loading plugin `{0}' ...".format(plugin)) + plugin = __import__(plugin, globals(), locals(), 'module') + + log.debug("Registering plugin `{0}' ...".format(plugin.__name__)) + plugin.register() + def _handle_deprecation(self): if self.settings.get('CLEAN_URLS', False): diff --git a/pelican/generators.py b/pelican/generators.py index e37de9e9..1ddc13c2 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -17,6 +17,7 @@ from jinja2.exceptions import TemplateNotFound from pelican.contents import Article, Page, Category, is_valid_content from pelican.readers import read_file from pelican.utils import copy, process_translations, open +from pelican import signals logger = logging.getLogger(__name__) @@ -118,6 +119,7 @@ class ArticlesGenerator(Generator): self.authors = defaultdict(list) super(ArticlesGenerator, self).__init__(*args, **kwargs) self.drafts = [] + signals.article_generator_init.send(self) def generate_feeds(self, writer): """Generate the feeds from the current context, and output files.""" @@ -274,6 +276,7 @@ class ArticlesGenerator(Generator): metadata['date'] = datetime.datetime.fromtimestamp( os.stat(f).st_ctime) + signals.article_generate_context.send(self, metadata=metadata) article = Article(content, metadata, settings=self.settings, filename=f) if not is_valid_content(article, f): diff --git a/pelican/plugins/__init__.py b/pelican/plugins/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pelican/plugins/github_activity.py b/pelican/plugins/github_activity.py new file mode 100644 index 00000000..f2ba1da7 --- /dev/null +++ b/pelican/plugins/github_activity.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +""" + Copyright (c) Marco Milanesi