mirror of
https://github.com/getpelican/pelican.git
synced 2025-10-15 20:28:56 +02:00
Merge branch 'master' of github.com:ametaireau/pelican into tests
This commit is contained in:
commit
e53eea6ecc
7 changed files with 150 additions and 98 deletions
|
|
@ -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 ---------------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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__':
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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': [],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue