Merge branch 'master' of github.com:ametaireau/pelican into tests

This commit is contained in:
Alexis Metaireau 2011-01-12 00:49:19 +01:00
commit e53eea6ecc
7 changed files with 150 additions and 98 deletions

View file

@ -15,6 +15,8 @@ project = u'Pelican'
copyright = u'2010, Alexis Metaireau and contributors' copyright = u'2010, Alexis Metaireau and contributors'
exclude_patterns = ['_build'] exclude_patterns = ['_build']
pygments_style = 'sphinx' pygments_style = 'sphinx'
version = "2"
release = version
# -- Options for HTML output --------------------------------------------------- # -- Options for HTML output ---------------------------------------------------

View file

@ -91,7 +91,39 @@ the menu.
Translations Translations
============ ============
It is possible to translate articles. To do so, you need to add a `Lang` meta It is possible to translate articles. To do so, you need to add a `lang` meta
in your articles/pages, and to set a `DEFAULT_LANG` setting (which is en by in your articles/pages, and to set a `DEFAULT_LANG` setting (which is en by
default). Then, only articles with this default language will be listed, and default).
Then, only articles with this default language will be listed, and
each article will have a translation list. each article will have a translation list.
Pelican uses the "slug" of two articles to compare if they are translations of
each others. So it's possible to define (in restructured text) the slug
directly.
Here is an exemple of two articles (one in english and the other one in
french).
The english one::
Foobar is not dead
##################
:slug: foobar-is-not-dead
:lang: en
That's true, foobar is still alive !
And the french one::
Foobar n'est pas mort !
#######################
:slug: foobar-is-not-dead
:lang: fr
Oui oui, foobar est toujours vivant !
Despite the text quality, you can see that only the slug is the same here.
You're not forced to define the slug that way, and it's completely possible to
have two translations with the same title (which defines the slug)

View file

@ -10,71 +10,79 @@ from pelican.generators import (ArticlesGenerator, PagesGenerator,
VERSION = "2.5.3" VERSION = "2.5.3"
def init_params(settings=None, path=None, theme=None, output_path=None, class Pelican(object):
markup=None, keep=False): def __init__(self, settings=None, path=None, theme=None, output_path=None,
"""Read the settings, and performs some checks on the environment markup=None, keep=False):
before doing anything else. """Read the settings, and performs some checks on the environment
""" before doing anything else.
if settings is None: """
settings = {} self.path = path or settings['PATH']
settings = read_settings(settings) if self.path.endswith('/'):
path = path or settings['PATH'] self.path = path[:-1]
if path.endswith('/'):
path = path[:-1]
# define the default settings # define the default settings
theme = theme or settings['THEME'] self.settings = settings
output_path = output_path or settings['OUTPUT_PATH'] self.theme = theme or settings['THEME']
output_path = os.path.realpath(output_path) self.path = path
markup = markup or settings['MARKUP'] output_path = output_path or settings['OUTPUT_PATH']
keep = keep or settings['KEEP_OUTPUT_DIRECTORY'] self.output_path = os.path.realpath(output_path)
self.markup = markup or settings['MARKUP']
self.keep = keep or settings['KEEP_OUTPUT_DIRECTORY']
# find the theme in pelican.theme if the given one does not exists # find the theme in pelican.theme if the given one does not exists
if not os.path.exists(theme): if not os.path.exists(self.theme):
theme_path = os.sep.join([os.path.dirname( theme_path = os.sep.join([os.path.dirname(
os.path.abspath(__file__)), "themes/%s" % theme]) os.path.abspath(__file__)), "themes/%s" % self.theme])
if os.path.exists(theme_path): if os.path.exists(theme_path):
theme = theme_path self.theme = theme_path
else: else:
raise Exception("Impossible to find the theme %s" % theme) raise Exception("Impossible to find the theme %s" % theme)
# get the list of files to parse # get the list of files to parse
if not path: if not self.path:
raise Exception('you need to specify a path to search the docs on !') raise Exception('you need to specify a path to search the docs on !')
return settings, path, theme, output_path, markup, keep
def run_generators(generators, settings, path, theme, output_path, markup, keep): def run(self):
"""Run the generators and return""" """Run the generators and return"""
context = settings.copy() context = self.settings.copy()
generators = [p(context, settings, path, theme, output_path, markup, keep) generators = [
for p in generators] cls(
context,
self.settings,
self.path,
self.theme,
self.output_path,
self.markup,
self.keep
) for cls in self.get_generator_classes()
]
for p in generators: for p in generators:
if hasattr(p, 'generate_context'): if hasattr(p, 'generate_context'):
p.generate_context() p.generate_context()
# erase the directory if it is not the source # erase the directory if it is not the source
if output_path not in os.path.realpath(path) and not keep: if os.path.realpath(self.path).startswith(self.output_path) and not keep:
clean_output_dir(output_path) clean_output_dir(self.output_path)
writer = Writer(output_path) writer = self.get_writer()
for p in generators: for p in generators:
if hasattr(p, 'generate_output'): if hasattr(p, 'generate_output'):
p.generate_output(writer) p.generate_output(writer)
def run_pelican(settings, path, theme, output_path, markup, delete): def get_generator_classes(self):
"""Run pelican with the given parameters""" generators = [ArticlesGenerator, PagesGenerator, StaticGenerator]
if self.settings['PDF_GENERATOR']:
generators.append(PdfGenerator)
return generators
def get_writer(self):
return Writer(self.output_path)
params = init_params(settings, path, theme, output_path, markup, delete)
generators = [ArticlesGenerator, PagesGenerator, StaticGenerator]
if params[0]['PDF_GENERATOR']: # param[0] is settings
generators.append(PdfGenerator)
run_generators(generators, *params)
def main(): def main():
@ -106,7 +114,18 @@ def main():
# the variable with None. # the variable with None.
markup = [a.strip().lower() for a in args.markup.split(',')] if args.markup else None markup = [a.strip().lower() for a in args.markup.split(',')] if args.markup else None
run_pelican(args.settings, args.path, args.theme, args.output, markup, args.keep) if args.settings is None:
settings = {}
settings = read_settings(args.settings)
cls = settings.get('PELICAN_CLASS')
if isinstance(cls, basestring):
module, cls_name = cls.rsplit('.', 1)
module = __import__(module)
cls = getattr(module, cls_name)
pelican = cls(settings, args.path, args.theme, args.output, markup, args.keep)
pelican.run()
if __name__ == '__main__': if __name__ == '__main__':

View file

@ -8,7 +8,7 @@ import os
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
from jinja2.exceptions import TemplateNotFound from jinja2.exceptions import TemplateNotFound
from pelican.utils import update_dict, copytree, 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.contents import Article, Page, is_valid_content
from pelican.readers import read_file from pelican.readers import read_file
@ -81,8 +81,8 @@ class ArticlesGenerator(Generator):
self.articles = [] # only articles in default language self.articles = [] # only articles in default language
self.translations = [] self.translations = []
self.dates = {} self.dates = {}
self.tags = {} self.tags = defaultdict(list)
self.categories = {} self.categories = defaultdict(list)
super(ArticlesGenerator, self).__init__(*args, **kwargs) super(ArticlesGenerator, self).__init__(*args, **kwargs)
def generate_feeds(self, writer): def generate_feeds(self, writer):
@ -184,14 +184,14 @@ class ArticlesGenerator(Generator):
if hasattr(article, 'tags'): if hasattr(article, 'tags'):
for tag in article.tags: for tag in article.tags:
update_dict(self.tags, tag, article) self.tags[tag].append(article)
all_articles.append(article) all_articles.append(article)
self.articles, self.translations = process_translations(all_articles) self.articles, self.translations = process_translations(all_articles)
for article in self.articles: for article in self.articles:
# only main articles are listed in categories, not translations # only main articles are listed in categories, not translations
update_dict(self.categories, article.category, article) self.categories[article.category].append(article)
# sort the articles by date # sort the articles by date

View file

@ -22,6 +22,7 @@ _DEFAULT_CONFIG = {'PATH': None,
'CLEAN_URLS': False, # use /blah/ instead /blah.html in urls 'CLEAN_URLS': False, # use /blah/ instead /blah.html in urls
'RELATIVE_URLS': True, 'RELATIVE_URLS': True,
'DEFAULT_LANG': 'en', 'DEFAULT_LANG': 'en',
'PELICAN_CLASS': 'pelican.Pelican',
'JINJA_EXTENSIONS': [], 'JINJA_EXTENSIONS': [],
} }

View file

@ -7,17 +7,6 @@ from codecs import open as _open
from itertools import groupby from itertools import groupby
from operator import attrgetter from operator import attrgetter
def update_dict(mapping, key, value):
"""Update a dict intenal list
:param mapping: the mapping to update
:param key: the key of the mapping to update.
:param value: the value to append to the list.
"""
if key not in mapping:
mapping[key] = []
mapping[key].append(value)
def get_date(string): def get_date(string):
"""Return a datetime object from a string. """Return a datetime object from a string.

View file

@ -15,6 +15,25 @@ class Writer(object):
self.output_path = output_path self.output_path = output_path
self.reminder = dict() self.reminder = dict()
def _create_new_feed(self, feed_type, context):
feed_class = Rss201rev2Feed if feed_type == 'rss' else Atom1Feed
feed = feed_class(
title=context['SITENAME'],
link=self.site_url,
feed_url=self.feed_url,
description=context.get('SITESUBTITLE', ''))
return feed
def _add_item_to_the_feed(self, feed, item):
feed.add_item(
title=item.title,
link='%s/%s' % (self.site_url, item.url),
description=item.content,
categories=item.tags if hasattr(item, 'tags') else None,
author_name=getattr(item, 'author', 'John Doe'),
pubdate=item.date)
def write_feed(self, elements, context, filename=None, feed_type='atom'): def write_feed(self, elements, context, filename=None, feed_type='atom'):
"""Generate a feed with the list of articles provided """Generate a feed with the list of articles provided
@ -27,23 +46,13 @@ class Writer(object):
:param filename: the filename to output. :param filename: the filename to output.
:param feed_type: the feed type to use (atom or rss) :param feed_type: the feed type to use (atom or rss)
""" """
site_url = context.get('SITEURL', get_relative_path(filename)) self.site_url = context.get('SITEURL', get_relative_path(filename))
self.feed_url= '%s/%s' % (self.site_url, filename)
feed_class = Rss201rev2Feed if feed_type == 'rss' else Atom1Feed feed = self._create_new_feed(feed_type, context)
feed = feed_class( for item in elements:
title=context['SITENAME'], self._add_item_to_the_feed(feed, item)
link=site_url,
feed_url= "%s/%s" % (site_url, filename),
description=context.get('SITESUBTITLE', ''))
for element in elements:
feed.add_item(
title=element.title,
link= "%s/%s" % (site_url, element.url),
description=element.content,
categories=element.tags if hasattr(element, "tags") else None,
author_name=getattr(element, 'author', 'John Doe'),
pubdate=element.date)
if filename: if filename:
complete_path = os.path.join(self.output_path, filename) complete_path = os.path.join(self.output_path, filename)