diff --git a/pelican/__init__.py b/pelican/__init__.py index 7112fcec..846e2554 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -1,6 +1,9 @@ import argparse import os import time +import pkgutil + +from blinker import signal from pelican.generators import (ArticlesGenerator, PagesGenerator, StaticGenerator, PdfGenerator) @@ -14,7 +17,7 @@ VERSION = "2.7.2" 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. """ @@ -42,6 +45,15 @@ class Pelican(object): self.theme = theme_path else: raise Exception("Impossible to find the theme %s" % theme) + + plugins_path = plugins_path or settings['PLUGINS_PATH'] + if plugins_path: + plugins_path = os.path.abspath(os.path.expanduser(plugins_path)) + self.load_plugins(plugins_path) + else: + self.plugins = None + + signal('pelican_initialized').send(self) def run(self): """Run the generators and return""" @@ -84,6 +96,13 @@ class Pelican(object): def get_writer(self): return Writer(self.output_path, settings=self.settings) + + def load_plugins(self, path): + loaded = [] + for module_loader, name, ispkg in pkgutil.walk_packages(path=[path,]): + loaded.append(module_loader.find_module(name).load_module(name)) + self.plugins = loaded + @@ -103,7 +122,7 @@ def main(): help='the list of markup language to use (rst or md). Please indicate ' 'them separated by commas') parser.add_argument('-s', '--settings', dest='settings', default='', - help='the settings of the application. Default to False.') + help='the settings of the application.') parser.add_argument('-d', '--delete-output-directory', dest='delete_outputdir', action='store_true', help='Delete the output directory.') parser.add_argument('-v', '--verbose', action='store_const', const=log.INFO, dest='verbosity', @@ -117,6 +136,8 @@ def main(): parser.add_argument('-r', '--autoreload', dest='autoreload', action='store_true', help="Relaunch pelican each time a modification occurs on the content" "files") + parser.add_argument('-p', '--plugins', default=None, dest='plugins_path', + help='the path of plugins to use') args = parser.parse_args() log.init(args.verbosity) @@ -134,7 +155,7 @@ def main(): try: pelican = cls(settings, args.path, args.theme, args.output, markup, - args.delete_outputdir) + args.delete_outputdir, args.plugins_path) if args.autoreload: while True: try: diff --git a/pelican/generators.py b/pelican/generators.py index a397c002..b6619d0e 100755 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -8,10 +8,12 @@ import os import math import random +from blinker import signal + from jinja2 import Environment, FileSystemLoader from jinja2.exceptions import TemplateNotFound -from pelican.utils import copy, get_relative_path, process_translations, open +from pelican.utils import copytree, get_relative_path, process_translations, open from pelican.contents import Article, Page, is_valid_content from pelican.readers import read_file from pelican.log import * @@ -98,6 +100,7 @@ class ArticlesGenerator(Generator): self.dates = {} self.tags = defaultdict(list) self.categories = defaultdict(list) + self.signal = {'pelican_article_generate_context' : signal('pelican_article_generate_context')} super(ArticlesGenerator, self).__init__(*args, **kwargs) self.drafts = [] @@ -211,6 +214,7 @@ class ArticlesGenerator(Generator): and self.settings['FALLBACK_ON_FS_DATE']: metadata['date'] = datetime.fromtimestamp(os.stat(f).st_ctime) + self.signal['pelican_article_generate_context'].send(self, metadatas=metadatas) article = Article(content, metadata, settings=self.settings, filename=f) if not is_valid_content(article, f): diff --git a/pelican/settings.py b/pelican/settings.py index 1b32395c..3cc4157a 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -42,7 +42,8 @@ _DEFAULT_CONFIG = {'PATH': None, 'DEFAULT_METADATA': (), 'FILES_TO_COPY': (), 'DEFAULT_STATUS': 'published', - } + 'PLUGINS_PATH': None, + } def read_settings(filename): """Load a Python file into a dictionary. diff --git a/plugins_samples/global_license.py b/plugins_samples/global_license.py new file mode 100644 index 00000000..eeb20965 --- /dev/null +++ b/plugins_samples/global_license.py @@ -0,0 +1,23 @@ +from blinker import signal + +""" +License plugin for Pelican +========================== + +Simply add license variable in article's context, which contain +the license text. + +Settings: +--------- + +Add LICENSE to your settings file to define default license. + +""" + +def add_license(generator, metadatas): + if 'license' not in metadatas.keys()\ + and 'LICENSE' in generator.settings.keys(): + metadatas['license'] = generator.settings['LICENSE'] + + +signal('pelican_article_generate_context').connect(add_license) diff --git a/plugins_samples/gravatar.py b/plugins_samples/gravatar.py new file mode 100644 index 00000000..9887e97e --- /dev/null +++ b/plugins_samples/gravatar.py @@ -0,0 +1,39 @@ +import hashlib + +from blinker import signal +""" +Gravata plugin for Pelican +========================== + +Simply add author_gravatar variable in article's context, which contain +the gravatar url. + +Settings: +--------- + +Add AUTHOR_EMAIL to your settings file to define default author email + +Article metadatas: +------------------ + +:email: article's author email + +If one of them are defined the author_gravatar variable is added to +article's context. +""" + +def add_gravatar(generator, metadatas): + + #first check email + if 'email' not in metadatas.keys()\ + and 'AUTHOR_EMAIL' in generator.settings.keys(): + metadatas['email'] = generator.settings['AUTHOR_EMAIL'] + + #then add gravatar url + if 'email' in metadatas.keys(): + gravatar_url = "http://www.gravatar.com/avatar/" + \ + hashlib.md5(metadatas['email'].lower()).hexdigest() + metadatas["author_gravatar"] = gravatar_url + + +signal('pelican_article_generate_context').connect(add_gravatar) diff --git a/plugins_samples/initialized.py b/plugins_samples/initialized.py new file mode 100644 index 00000000..f104c275 --- /dev/null +++ b/plugins_samples/initialized.py @@ -0,0 +1,7 @@ +from blinker import signal + + +def test(sender): + print "%s initialized !!" % sender + +signal('pelican_initialized').connect(test) diff --git a/setup.py b/setup.py index e2bd4c60..18db914f 100755 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import sys VERSION = "2.7.2" # find a better way to do so. -requires = ['feedgenerator', 'jinja2', 'pygments', 'docutils'] +requires = ['feedgenerator', 'jinja2', 'pygments', 'docutils', 'blinker'] if sys.version_info < (2,7): requires.append('argparse')