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'
exclude_patterns = ['_build']
pygments_style = 'sphinx'
version = "2"
release = version
# -- Options for HTML output ---------------------------------------------------

View file

@ -91,7 +91,39 @@ the menu.
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
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.
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"
def init_params(settings=None, path=None, theme=None, output_path=None,
markup=None, keep=False):
"""Read the settings, and performs some checks on the environment
before doing anything else.
"""
if settings is None:
settings = {}
settings = read_settings(settings)
path = path or settings['PATH']
if path.endswith('/'):
path = path[:-1]
class Pelican(object):
def __init__(self, settings=None, path=None, theme=None, output_path=None,
markup=None, keep=False):
"""Read the settings, and performs some checks on the environment
before doing anything else.
"""
self.path = path or settings['PATH']
if self.path.endswith('/'):
self.path = path[:-1]
# define the default settings
theme = theme or settings['THEME']
output_path = output_path or settings['OUTPUT_PATH']
output_path = os.path.realpath(output_path)
markup = markup or settings['MARKUP']
keep = keep or settings['KEEP_OUTPUT_DIRECTORY']
# define the default settings
self.settings = settings
self.theme = theme or settings['THEME']
self.path = path
output_path = output_path or settings['OUTPUT_PATH']
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
if not os.path.exists(theme):
theme_path = os.sep.join([os.path.dirname(
os.path.abspath(__file__)), "themes/%s" % theme])
if os.path.exists(theme_path):
theme = theme_path
else:
raise Exception("Impossible to find the theme %s" % theme)
# find the theme in pelican.theme if the given one does not exists
if not os.path.exists(self.theme):
theme_path = os.sep.join([os.path.dirname(
os.path.abspath(__file__)), "themes/%s" % self.theme])
if os.path.exists(theme_path):
self.theme = theme_path
else:
raise Exception("Impossible to find the theme %s" % theme)
# get the list of files to parse
if not path:
raise Exception('you need to specify a path to search the docs on !')
return settings, path, theme, output_path, markup, keep
# get the list of files to parse
if not self.path:
raise Exception('you need to specify a path to search the docs on !')
def run_generators(generators, settings, path, theme, output_path, markup, keep):
"""Run the generators and return"""
def run(self):
"""Run the generators and return"""
context = settings.copy()
generators = [p(context, settings, path, theme, output_path, markup, keep)
for p in generators]
context = self.settings.copy()
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:
if hasattr(p, 'generate_context'):
p.generate_context()
for p in generators:
if hasattr(p, 'generate_context'):
p.generate_context()
# erase the directory if it is not the source
if output_path not in os.path.realpath(path) and not keep:
clean_output_dir(output_path)
# erase the directory if it is not the source
if os.path.realpath(self.path).startswith(self.output_path) and not keep:
clean_output_dir(self.output_path)
writer = Writer(output_path)
writer = self.get_writer()
for p in generators:
if hasattr(p, 'generate_output'):
p.generate_output(writer)
for p in generators:
if hasattr(p, 'generate_output'):
p.generate_output(writer)
def run_pelican(settings, path, theme, output_path, markup, delete):
"""Run pelican with the given parameters"""
def get_generator_classes(self):
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():
@ -106,7 +114,18 @@ def main():
# the variable with 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__':

View file

@ -8,7 +8,7 @@ import os
from jinja2 import Environment, FileSystemLoader
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.readers import read_file
@ -81,8 +81,8 @@ class ArticlesGenerator(Generator):
self.articles = [] # only articles in default language
self.translations = []
self.dates = {}
self.tags = {}
self.categories = {}
self.tags = defaultdict(list)
self.categories = defaultdict(list)
super(ArticlesGenerator, self).__init__(*args, **kwargs)
def generate_feeds(self, writer):
@ -184,14 +184,14 @@ class ArticlesGenerator(Generator):
if hasattr(article, 'tags'):
for tag in article.tags:
update_dict(self.tags, tag, article)
self.tags[tag].append(article)
all_articles.append(article)
self.articles, self.translations = process_translations(all_articles)
for article in self.articles:
# 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

View file

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

View file

@ -7,17 +7,6 @@ from codecs import open as _open
from itertools import groupby
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):
"""Return a datetime object from a string.

View file

@ -15,6 +15,25 @@ class Writer(object):
self.output_path = output_path
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'):
"""Generate a feed with the list of articles provided
@ -27,23 +46,13 @@ class Writer(object):
:param filename: the filename to output.
: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(
title=context['SITENAME'],
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)
for item in elements:
self._add_item_to_the_feed(feed, item)
if filename:
complete_path = os.path.join(self.output_path, filename)