mirror of
https://github.com/getpelican/pelican.git
synced 2025-10-15 20:28:56 +02:00
Merge remote-tracking branch 'ametaireau/plugins' into plugins
Conflicts: docs/settings.rst pelican/__init__.py pelican/generators.py pelican/settings.py setup.py
This commit is contained in:
commit
4fe67b8947
14 changed files with 368 additions and 3 deletions
|
|
@ -60,6 +60,8 @@ A French version of the documentation is available at :doc:`fr/index`.
|
||||||
getting_started
|
getting_started
|
||||||
settings
|
settings
|
||||||
themes
|
themes
|
||||||
|
pelican-themes
|
||||||
|
plugins
|
||||||
internals
|
internals
|
||||||
pelican-themes
|
pelican-themes
|
||||||
importer
|
importer
|
||||||
|
|
|
||||||
119
docs/plugins.rst
Normal file
119
docs/plugins.rst
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
.. _plugins:
|
||||||
|
|
||||||
|
Plugins
|
||||||
|
#######
|
||||||
|
|
||||||
|
Since version 2.8, pelican manages plugins. Plugins are a way to add feature 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 a them in your settings file. You have two
|
||||||
|
ways to do so: 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 plugins introduces a new depencency, you have to install feedparser
|
||||||
|
if you want to use it, these are some ways to do it::
|
||||||
|
|
||||||
|
apt-get install python-feedparser # on debian based distributions like ubuntu
|
||||||
|
sudo easy_install feedparser
|
||||||
|
sudo pip install feedparser
|
||||||
|
|
||||||
|
To enable it set in your pelican config file the GITHUB_ACTIVITY_FEED
|
||||||
|
parameter pointing to your github activity feed.
|
||||||
|
|
||||||
|
for example my personal activity feed is::
|
||||||
|
|
||||||
|
https://github.com/kpanic.atom
|
||||||
|
|
||||||
|
and the config line could be::
|
||||||
|
|
||||||
|
GITHUB_ACTIVITY_FEED = 'https://github.com/kpanic.atom'
|
||||||
|
|
||||||
|
in your template just write a for in jinja2 syntax against the
|
||||||
|
github_activity variable, like for example::
|
||||||
|
|
||||||
|
{% if GITHUB_ACTIVITY_FEED %}
|
||||||
|
<div class="social">
|
||||||
|
<h2>Github Activity</h2>
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
{% for entry in github_activity %}
|
||||||
|
<li><b>{{ entry[0] }}</b><br /> {{ entry[1] }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div><!-- /.github_activity -->
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
github_activity is a list containing a list. The first element is the title and
|
||||||
|
the second element is the raw html from github so you can include it directly
|
||||||
|
in your (for example base.html) template and style it in a way that your prefer
|
||||||
|
using your css skills
|
||||||
|
|
@ -59,6 +59,7 @@ Setting name (default value) What does it do?
|
||||||
`PDF_GENERATOR` (``False``) Set to True if you want to have PDF versions
|
`PDF_GENERATOR` (``False``) Set to True if you want to have PDF versions
|
||||||
of your documents. You will need to install
|
of your documents. You will need to install
|
||||||
`rst2pdf`.
|
`rst2pdf`.
|
||||||
|
`PLUGINS` (``[]``) The list of plugins to load. See :ref:`plugins`.
|
||||||
`RELATIVE_URLS` (``True``) Defines whether Pelican should use relative URLs or
|
`RELATIVE_URLS` (``True``) Defines whether Pelican should use relative URLs or
|
||||||
not.
|
not.
|
||||||
`SITENAME` (``'A Pelican Blog'``) Your site name
|
`SITENAME` (``'A Pelican Blog'``) Your site name
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import sys
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from pelican import signals
|
||||||
|
|
||||||
from pelican.generators import (ArticlesGenerator, PagesGenerator,
|
from pelican.generators import (ArticlesGenerator, PagesGenerator,
|
||||||
StaticGenerator, PdfGenerator)
|
StaticGenerator, PdfGenerator)
|
||||||
from pelican.settings import read_settings, _DEFAULT_CONFIG
|
from pelican.settings import read_settings, _DEFAULT_CONFIG
|
||||||
|
|
@ -18,7 +20,7 @@ __version__ = "{0}.{1}".format(__major__, __minor__)
|
||||||
|
|
||||||
class Pelican(object):
|
class Pelican(object):
|
||||||
def __init__(self, settings=None, path=None, theme=None, output_path=None,
|
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
|
"""Read the settings, and performs some checks on the environment
|
||||||
before doing anything else.
|
before doing anything else.
|
||||||
"""
|
"""
|
||||||
|
|
@ -54,6 +56,20 @@ class Pelican(object):
|
||||||
else:
|
else:
|
||||||
raise Exception("Impossible to find the theme %s" % theme)
|
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, str):
|
||||||
|
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):
|
def _handle_deprecation(self):
|
||||||
|
|
||||||
if self.settings.get('CLEAN_URLS', False):
|
if self.settings.get('CLEAN_URLS', False):
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ from pelican.contents import Article, Page, Category, is_valid_content
|
||||||
from pelican.log import warning, error, debug, info
|
from pelican.log import warning, error, debug, info
|
||||||
from pelican.readers import read_file
|
from pelican.readers import read_file
|
||||||
from pelican.utils import copy, process_translations, open
|
from pelican.utils import copy, process_translations, open
|
||||||
|
from pelican import signals
|
||||||
|
|
||||||
|
|
||||||
class Generator(object):
|
class Generator(object):
|
||||||
|
|
@ -114,6 +115,7 @@ class ArticlesGenerator(Generator):
|
||||||
self.authors = defaultdict(list)
|
self.authors = defaultdict(list)
|
||||||
super(ArticlesGenerator, self).__init__(*args, **kwargs)
|
super(ArticlesGenerator, self).__init__(*args, **kwargs)
|
||||||
self.drafts = []
|
self.drafts = []
|
||||||
|
signals.article_generator_init.send(self)
|
||||||
|
|
||||||
def generate_feeds(self, writer):
|
def generate_feeds(self, writer):
|
||||||
"""Generate the feeds from the current context, and output files."""
|
"""Generate the feeds from the current context, and output files."""
|
||||||
|
|
@ -242,6 +244,7 @@ class ArticlesGenerator(Generator):
|
||||||
metadata['date'] = datetime.datetime.fromtimestamp(
|
metadata['date'] = datetime.datetime.fromtimestamp(
|
||||||
os.stat(f).st_ctime)
|
os.stat(f).st_ctime)
|
||||||
|
|
||||||
|
signals.article_generate_context.send(self, metadata=metadata)
|
||||||
article = Article(content, metadata, settings=self.settings,
|
article = Article(content, metadata, settings=self.settings,
|
||||||
filename=f)
|
filename=f)
|
||||||
if not is_valid_content(article, f):
|
if not is_valid_content(article, f):
|
||||||
|
|
|
||||||
0
pelican/plugins/__init__.py
Normal file
0
pelican/plugins/__init__.py
Normal file
85
pelican/plugins/github_activity.py
Normal file
85
pelican/plugins/github_activity.py
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Copyright (c) Marco Milanesi <kpanic@gnufunk.org>
|
||||||
|
|
||||||
|
A plugin to list your Github Activity
|
||||||
|
To enable it set in your pelican config file the GITHUB_ACTIVITY_FEED
|
||||||
|
parameter pointing to your github activity feed.
|
||||||
|
|
||||||
|
for example my personal activity feed is:
|
||||||
|
|
||||||
|
https://github.com/kpanic.atom
|
||||||
|
|
||||||
|
in your template just write a for in jinja2 syntax against the
|
||||||
|
github_activity variable.
|
||||||
|
|
||||||
|
i.e.
|
||||||
|
|
||||||
|
<div class="social">
|
||||||
|
<h2>Github Activity</h2>
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
{% for entry in github_activity %}
|
||||||
|
<li><b>{{ entry[0] }}</b><br /> {{ entry[1] }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div><!-- /.github_activity -->
|
||||||
|
|
||||||
|
github_activity is a list containing a list. The first element is the title
|
||||||
|
and the second element is the raw html from github
|
||||||
|
"""
|
||||||
|
|
||||||
|
from pelican import signals
|
||||||
|
|
||||||
|
|
||||||
|
class GitHubActivity():
|
||||||
|
"""
|
||||||
|
A class created to fetch github activity with feedparser
|
||||||
|
"""
|
||||||
|
def __init__(self, generator):
|
||||||
|
try:
|
||||||
|
import feedparser
|
||||||
|
self.activities = feedparser.parse(
|
||||||
|
generator.settings['GITHUB_ACTIVITY_FEED'])
|
||||||
|
except ImportError:
|
||||||
|
raise Exception("Unable to find feedparser")
|
||||||
|
|
||||||
|
def fetch(self):
|
||||||
|
"""
|
||||||
|
returns a list of html snippets fetched from github actitivy feed
|
||||||
|
"""
|
||||||
|
|
||||||
|
entries = []
|
||||||
|
for activity in self.activities['entries']:
|
||||||
|
entries.append(
|
||||||
|
[element for element in [activity['title'],
|
||||||
|
activity['content'][0]['value']]])
|
||||||
|
|
||||||
|
return entries
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_github_activity(gen, metadata):
|
||||||
|
"""
|
||||||
|
registered handler for the github activity plugin
|
||||||
|
it puts in generator.context the html needed to be displayed on a
|
||||||
|
template
|
||||||
|
"""
|
||||||
|
|
||||||
|
if 'GITHUB_ACTIVITY_FEED' in gen.settings.keys():
|
||||||
|
gen.context['github_activity'] = gen.plugin_instance.fetch()
|
||||||
|
|
||||||
|
|
||||||
|
def feed_parser_initialization(generator):
|
||||||
|
"""
|
||||||
|
Initialization of feed parser
|
||||||
|
"""
|
||||||
|
|
||||||
|
generator.plugin_instance = GitHubActivity(generator)
|
||||||
|
|
||||||
|
|
||||||
|
def register():
|
||||||
|
"""
|
||||||
|
Plugin registration
|
||||||
|
"""
|
||||||
|
signals.article_generator_init.connect(feed_parser_initialization)
|
||||||
|
signals.article_generate_context.connect(fetch_github_activity)
|
||||||
23
pelican/plugins/global_license.py
Normal file
23
pelican/plugins/global_license.py
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
from pelican import signals
|
||||||
|
|
||||||
|
"""
|
||||||
|
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, metadata):
|
||||||
|
if 'license' not in metadata.keys()\
|
||||||
|
and 'LICENSE' in generator.settings.keys():
|
||||||
|
metadata['license'] = generator.settings['LICENSE']
|
||||||
|
|
||||||
|
def register():
|
||||||
|
signals.article_generate_context.connect(add_license)
|
||||||
40
pelican/plugins/gravatar.py
Normal file
40
pelican/plugins/gravatar.py
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
from pelican import signals
|
||||||
|
"""
|
||||||
|
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 metadata:
|
||||||
|
------------------
|
||||||
|
|
||||||
|
: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, metadata):
|
||||||
|
|
||||||
|
#first check email
|
||||||
|
if 'email' not in metadata.keys()\
|
||||||
|
and 'AUTHOR_EMAIL' in generator.settings.keys():
|
||||||
|
metadata['email'] = generator.settings['AUTHOR_EMAIL']
|
||||||
|
|
||||||
|
#then add gravatar url
|
||||||
|
if 'email' in metadata.keys():
|
||||||
|
gravatar_url = "http://www.gravatar.com/avatar/" + \
|
||||||
|
hashlib.md5(metadata['email'].lower()).hexdigest()
|
||||||
|
metadata["author_gravatar"] = gravatar_url
|
||||||
|
|
||||||
|
|
||||||
|
def register():
|
||||||
|
signals.article_generate_context.connect(add_gravatar)
|
||||||
63
pelican/plugins/html_rst_directive.py
Normal file
63
pelican/plugins/html_rst_directive.py
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
from docutils import nodes
|
||||||
|
from docutils.parsers.rst import directives, Directive
|
||||||
|
from pelican import log
|
||||||
|
|
||||||
|
"""
|
||||||
|
HTML tags for reStructuredText
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Directives
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. html::
|
||||||
|
|
||||||
|
(HTML code)
|
||||||
|
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
|
||||||
|
A search engine:
|
||||||
|
|
||||||
|
.. html::
|
||||||
|
<form action="http://seeks.fr/search" method="GET">
|
||||||
|
<input type="text" value="Pelican v2" title="Search" maxlength="2048" name="q" autocomplete="on" />
|
||||||
|
<input type="hidden" name="lang" value="en" />
|
||||||
|
<input type="submit" value="Seeks !" id="search_button" />
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
A contact form:
|
||||||
|
|
||||||
|
.. html::
|
||||||
|
|
||||||
|
<form method="GET" action="mailto:some email">
|
||||||
|
<p>
|
||||||
|
<input type="text" placeholder="Subject" name="subject">
|
||||||
|
<br />
|
||||||
|
<textarea name="body" placeholder="Message">
|
||||||
|
</textarea>
|
||||||
|
<br />
|
||||||
|
<input type="reset"><input type="submit">
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class RawHtml(Directive):
|
||||||
|
required_arguments = 0
|
||||||
|
optional_arguments = 0
|
||||||
|
final_argument_whitespace = True
|
||||||
|
has_content = True
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
html = u' '.join(self.content)
|
||||||
|
node = nodes.raw('', html, format='html')
|
||||||
|
return [node]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def register():
|
||||||
|
directives.register_directive('html', RawHtml)
|
||||||
|
|
||||||
7
pelican/plugins/initialized.py
Normal file
7
pelican/plugins/initialized.py
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
from pelican import signals
|
||||||
|
|
||||||
|
def test(sender):
|
||||||
|
print "%s initialized !!" % sender
|
||||||
|
|
||||||
|
def register():
|
||||||
|
signals.initialized.connect(test)
|
||||||
|
|
@ -63,6 +63,7 @@ _DEFAULT_CONFIG = {'PATH': None,
|
||||||
'DEFAULT_STATUS': 'published',
|
'DEFAULT_STATUS': 'published',
|
||||||
'ARTICLE_PERMALINK_STRUCTURE': '',
|
'ARTICLE_PERMALINK_STRUCTURE': '',
|
||||||
'TYPOGRIFY': False,
|
'TYPOGRIFY': False,
|
||||||
|
'PLUGINS': [],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
5
pelican/signals.py
Normal file
5
pelican/signals.py
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
from blinker import signal
|
||||||
|
|
||||||
|
initialized = signal('pelican_initialized')
|
||||||
|
article_generate_context = signal('article_generate_context')
|
||||||
|
article_generator_init = signal('article_generator_init')
|
||||||
4
setup.py
4
setup.py
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
requires = ['feedgenerator', 'jinja2', 'pygments', 'docutils', 'pytz']
|
requires = ['feedgenerator', 'jinja2', 'pygments', 'docutils', 'pytz', 'blinker']
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import argparse
|
import argparse
|
||||||
|
|
@ -25,7 +25,7 @@ setup(
|
||||||
author_email = 'alexis@notmyidea.org',
|
author_email = 'alexis@notmyidea.org',
|
||||||
description = "A tool to generate a static blog from reStructuredText or Markdown input files.",
|
description = "A tool to generate a static blog from reStructuredText or Markdown input files.",
|
||||||
long_description=open('README.rst').read(),
|
long_description=open('README.rst').read(),
|
||||||
packages = ['pelican', 'pelican.tools'],
|
packages = ['pelican', 'pelican.tools', 'pelican.plugins'],
|
||||||
include_package_data = True,
|
include_package_data = True,
|
||||||
install_requires = requires,
|
install_requires = requires,
|
||||||
entry_points = entry_points,
|
entry_points = entry_points,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue