mirror of
https://github.com/getpelican/pelican.git
synced 2025-10-15 20:28:56 +02:00
merge with master
This commit is contained in:
commit
93c04cd79f
166 changed files with 4437 additions and 2285 deletions
|
|
@ -6,6 +6,7 @@ import logging
|
|||
import datetime
|
||||
import subprocess
|
||||
|
||||
from codecs import open
|
||||
from collections import defaultdict
|
||||
from functools import partial
|
||||
from itertools import chain
|
||||
|
|
@ -16,7 +17,7 @@ from jinja2.exceptions import TemplateNotFound
|
|||
|
||||
from pelican.contents import Article, Page, Category, is_valid_content
|
||||
from pelican.readers import read_file
|
||||
from pelican.utils import copy, process_translations, open
|
||||
from pelican.utils import copy, process_translations
|
||||
from pelican import signals
|
||||
|
||||
|
||||
|
|
@ -36,8 +37,11 @@ class Generator(object):
|
|||
|
||||
# templates cache
|
||||
self._templates = {}
|
||||
self._templates_path = os.path.expanduser(
|
||||
os.path.join(self.theme, 'templates'))
|
||||
self._templates_path = []
|
||||
self._templates_path.append(os.path.expanduser(
|
||||
os.path.join(self.theme, 'templates')))
|
||||
self._templates_path += self.settings.get('EXTRA_TEMPLATES_PATHS', [])
|
||||
|
||||
|
||||
theme_path = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
|
@ -116,6 +120,7 @@ class ArticlesGenerator(Generator):
|
|||
self.dates = {}
|
||||
self.tags = defaultdict(list)
|
||||
self.categories = defaultdict(list)
|
||||
self.related_posts = []
|
||||
self.authors = defaultdict(list)
|
||||
super(ArticlesGenerator, self).__init__(*args, **kwargs)
|
||||
self.drafts = []
|
||||
|
|
@ -123,10 +128,17 @@ class ArticlesGenerator(Generator):
|
|||
|
||||
def generate_feeds(self, writer):
|
||||
"""Generate the feeds from the current context, and output files."""
|
||||
if self.settings.get('FEED_ATOM') is None \
|
||||
and self.settings.get('FEED_RSS') is None:
|
||||
return
|
||||
elif self.settings.get('SITEURL') is '':
|
||||
logger.warning(
|
||||
'Feeds generated without SITEURL set properly may not be valid'
|
||||
)
|
||||
|
||||
if self.settings.get('FEED'):
|
||||
if self.settings.get('FEED_ATOM'):
|
||||
writer.write_feed(self.articles, self.context,
|
||||
self.settings['FEED'])
|
||||
self.settings['FEED_ATOM'])
|
||||
|
||||
if self.settings.get('FEED_RSS'):
|
||||
writer.write_feed(self.articles, self.context,
|
||||
|
|
@ -134,44 +146,49 @@ class ArticlesGenerator(Generator):
|
|||
|
||||
for cat, arts in self.categories:
|
||||
arts.sort(key=attrgetter('date'), reverse=True)
|
||||
if self.settings.get('CATEGORY_FEED'):
|
||||
if self.settings.get('CATEGORY_FEED_ATOM'):
|
||||
writer.write_feed(arts, self.context,
|
||||
self.settings['CATEGORY_FEED'] % cat)
|
||||
self.settings['CATEGORY_FEED_ATOM'] % cat)
|
||||
|
||||
if self.settings.get('CATEGORY_FEED_RSS'):
|
||||
writer.write_feed(arts, self.context,
|
||||
self.settings['CATEGORY_FEED_RSS'] % cat,
|
||||
feed_type='rss')
|
||||
|
||||
if self.settings.get('TAG_FEED') or self.settings.get('TAG_FEED_RSS'):
|
||||
if self.settings.get('TAG_FEED_ATOM') \
|
||||
or self.settings.get('TAG_FEED_RSS'):
|
||||
for tag, arts in self.tags.items():
|
||||
arts.sort(key=attrgetter('date'), reverse=True)
|
||||
if self.settings.get('TAG_FEED'):
|
||||
if self.settings.get('TAG_FEED_ATOM'):
|
||||
writer.write_feed(arts, self.context,
|
||||
self.settings['TAG_FEED'] % tag)
|
||||
self.settings['TAG_FEED_ATOM'] % tag)
|
||||
|
||||
if self.settings.get('TAG_FEED_RSS'):
|
||||
writer.write_feed(arts, self.context,
|
||||
self.settings['TAG_FEED_RSS'] % tag,
|
||||
feed_type='rss')
|
||||
|
||||
if self.settings.get('TRANSLATION_FEED'):
|
||||
if self.settings.get('TRANSLATION_FEED_ATOM') or \
|
||||
self.settings.get('TRANSLATION_FEED_RSS'):
|
||||
translations_feeds = defaultdict(list)
|
||||
for article in chain(self.articles, self.translations):
|
||||
translations_feeds[article.lang].append(article)
|
||||
|
||||
for lang, items in translations_feeds.items():
|
||||
items.sort(key=attrgetter('date'), reverse=True)
|
||||
writer.write_feed(items, self.context,
|
||||
self.settings['TRANSLATION_FEED'] % lang)
|
||||
if self.settings.get('TRANSLATION_FEED_ATOM'):
|
||||
writer.write_feed(items, self.context,
|
||||
self.settings['TRANSLATION_FEED_ATOM'] % lang)
|
||||
if self.settings.get('TRANSLATION_FEED_RSS'):
|
||||
writer.write_feed(items, self.context,
|
||||
self.settings['TRANSLATION_FEED_RSS'] % lang,
|
||||
feed_type='rss')
|
||||
|
||||
def generate_articles(self, write):
|
||||
"""Generate the articles."""
|
||||
article_template = self.get_template('article')
|
||||
for article in chain(self.translations, self.articles):
|
||||
write(article.save_as,
|
||||
article_template, self.context, article=article,
|
||||
category=article.category)
|
||||
write(article.save_as, self.get_template(article.template),
|
||||
self.context, article=article, category=article.category)
|
||||
|
||||
def generate_direct_templates(self, write):
|
||||
"""Generate direct templates pages"""
|
||||
|
|
@ -183,7 +200,7 @@ class ArticlesGenerator(Generator):
|
|||
save_as = self.settings.get("%s_SAVE_AS" % template.upper(),
|
||||
'%s.html' % template)
|
||||
if not save_as:
|
||||
continue
|
||||
continue
|
||||
|
||||
write(save_as, self.get_template(template),
|
||||
self.context, blog=True, paginated=paginated,
|
||||
|
|
@ -222,10 +239,10 @@ class ArticlesGenerator(Generator):
|
|||
|
||||
def generate_drafts(self, write):
|
||||
"""Generate drafts pages."""
|
||||
article_template = self.get_template('article')
|
||||
for article in self.drafts:
|
||||
write('drafts/%s.html' % article.slug, article_template,
|
||||
self.context, article=article, category=article.category)
|
||||
write('drafts/%s.html' % article.slug,
|
||||
self.get_template(article.template), self.context,
|
||||
article=article, category=article.category)
|
||||
|
||||
def generate_pages(self, writer):
|
||||
"""Generate the pages on the disk"""
|
||||
|
|
@ -264,7 +281,7 @@ class ArticlesGenerator(Generator):
|
|||
if 'category' not in metadata:
|
||||
|
||||
if os.path.dirname(f) == article_path: # if the article is not in a subdirectory
|
||||
category = self.settings['DEFAULT_CATEGORY']
|
||||
category = self.settings['DEFAULT_CATEGORY']
|
||||
else:
|
||||
category = os.path.basename(os.path.dirname(f))\
|
||||
.decode('utf-8')
|
||||
|
|
@ -272,9 +289,13 @@ class ArticlesGenerator(Generator):
|
|||
if category != '':
|
||||
metadata['category'] = Category(category, self.settings)
|
||||
|
||||
if 'date' not in metadata and self.settings['FALLBACK_ON_FS_DATE']:
|
||||
if 'date' not in metadata and self.settings['DEFAULT_DATE']:
|
||||
if self.settings['DEFAULT_DATE'] == 'fs':
|
||||
metadata['date'] = datetime.datetime.fromtimestamp(
|
||||
os.stat(f).st_ctime)
|
||||
os.stat(f).st_ctime)
|
||||
else:
|
||||
metadata['date'] = datetime.datetime(
|
||||
*self.settings['DEFAULT_DATE'])
|
||||
|
||||
signals.article_generate_context.send(self, metadata=metadata)
|
||||
article = Article(content, metadata, settings=self.settings,
|
||||
|
|
@ -305,7 +326,7 @@ class ArticlesGenerator(Generator):
|
|||
self.articles.sort(key=attrgetter('date'), reverse=True)
|
||||
self.dates = list(self.articles)
|
||||
self.dates.sort(key=attrgetter('date'),
|
||||
reverse=self.context['REVERSE_ARCHIVE_ORDER'])
|
||||
reverse=self.context['NEWEST_FIRST_ARCHIVES'])
|
||||
|
||||
# create tag cloud
|
||||
tag_cloud = defaultdict(int)
|
||||
|
|
@ -345,7 +366,9 @@ class ArticlesGenerator(Generator):
|
|||
self.authors.sort(key=lambda item: item[0].name)
|
||||
|
||||
self._update_context(('articles', 'dates', 'tags', 'categories',
|
||||
'tag_cloud', 'authors'))
|
||||
'tag_cloud', 'authors', 'related_posts'))
|
||||
|
||||
signals.article_generator_finalized.send(self)
|
||||
|
||||
def generate_output(self, writer):
|
||||
self.generate_feeds(writer)
|
||||
|
|
@ -357,32 +380,46 @@ class PagesGenerator(Generator):
|
|||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.pages = []
|
||||
self.hidden_pages = []
|
||||
self.hidden_translations = []
|
||||
super(PagesGenerator, self).__init__(*args, **kwargs)
|
||||
signals.pages_generator_init.send(self)
|
||||
|
||||
def generate_context(self):
|
||||
all_pages = []
|
||||
hidden_pages = []
|
||||
for f in self.get_files(
|
||||
os.path.join(self.path, self.settings['PAGE_DIR']),
|
||||
exclude=self.settings['PAGE_EXCLUDES']):
|
||||
try:
|
||||
content, metadata = read_file(f)
|
||||
content, metadata = read_file(f, settings=self.settings)
|
||||
except Exception, e:
|
||||
logger.error(u'Could not process %s\n%s' % (f, str(e)))
|
||||
logger.warning(u'Could not process %s\n%s' % (f, str(e)))
|
||||
continue
|
||||
signals.pages_generate_context.send(self, metadata=metadata )
|
||||
page = Page(content, metadata, settings=self.settings,
|
||||
filename=f)
|
||||
if not is_valid_content(page, f):
|
||||
continue
|
||||
all_pages.append(page)
|
||||
if page.status == "published":
|
||||
all_pages.append(page)
|
||||
elif page.status == "hidden":
|
||||
hidden_pages.append(page)
|
||||
else:
|
||||
logger.warning(u"Unknown status %s for file %s, skipping it." %
|
||||
(repr(unicode.encode(page.status, 'utf-8')),
|
||||
repr(f)))
|
||||
|
||||
self.pages, self.translations = process_translations(all_pages)
|
||||
self.hidden_pages, self.hidden_translations = process_translations(hidden_pages)
|
||||
|
||||
self._update_context(('pages', ))
|
||||
self.context['PAGES'] = self.pages
|
||||
|
||||
def generate_output(self, writer):
|
||||
for page in chain(self.translations, self.pages):
|
||||
writer.write_file(page.save_as, self.get_template('page'),
|
||||
for page in chain(self.translations, self.pages,
|
||||
self.hidden_translations, self.hidden_pages):
|
||||
writer.write_file(page.save_as, self.get_template(page.template),
|
||||
self.context, page=page,
|
||||
relative_urls=self.settings.get('RELATIVE_URLS'))
|
||||
|
||||
|
|
@ -406,7 +443,23 @@ class StaticGenerator(Generator):
|
|||
# Define the assets environment that will be passed to the
|
||||
# generators. The StaticGenerator must then be run first to have
|
||||
# the assets in the output_path before generating the templates.
|
||||
assets_url = self.settings['SITEURL'] + '/theme/'
|
||||
|
||||
# Let ASSET_URL honor Pelican's RELATIVE_URLS setting.
|
||||
# Hint for templates:
|
||||
# Current version of webassets seem to remove any relative
|
||||
# paths at the beginning of the URL. So, if RELATIVE_URLS
|
||||
# is on, ASSET_URL will start with 'theme/', regardless if we
|
||||
# set assets_url here to './theme/' or to 'theme/'.
|
||||
# XXX However, this breaks the ASSET_URL if user navigates to
|
||||
# a sub-URL, e.g. if he clicks on a category. To workaround this
|
||||
# issue, I use
|
||||
# <link rel="stylesheet" href="{{ SITEURL }}/{{ ASSET_URL }}">
|
||||
# instead of
|
||||
# <link rel="stylesheet" href="{{ ASSET_URL }}">
|
||||
if self.settings.get('RELATIVE_URLS'):
|
||||
assets_url = './theme/'
|
||||
else:
|
||||
assets_url = self.settings['SITEURL'] + '/theme/'
|
||||
assets_src = os.path.join(self.output_path, 'theme')
|
||||
self.assets_env = AssetsEnvironment(assets_src, assets_url)
|
||||
|
||||
|
|
@ -430,13 +483,20 @@ class PdfGenerator(Generator):
|
|||
"""Generate PDFs on the output dir, for all articles and pages coming from
|
||||
rst"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(PdfGenerator, self).__init__(*args, **kwargs)
|
||||
try:
|
||||
from rst2pdf.createpdf import RstToPdf
|
||||
pdf_style_path = os.path.join(self.settings['PDF_STYLE_PATH']) \
|
||||
if 'PDF_STYLE_PATH' in self.settings.keys() \
|
||||
else ''
|
||||
pdf_style = self.settings['PDF_STYLE'] if 'PDF_STYLE' \
|
||||
in self.settings.keys() \
|
||||
else 'twelvepoint'
|
||||
self.pdfcreator = RstToPdf(breakside=0,
|
||||
stylesheets=['twelvepoint'])
|
||||
stylesheets=[pdf_style],
|
||||
style_path=[pdf_style_path])
|
||||
except ImportError:
|
||||
raise Exception("unable to find rst2pdf")
|
||||
super(PdfGenerator, self).__init__(*args, **kwargs)
|
||||
|
||||
def _create_pdf(self, obj, output_path):
|
||||
if obj.filename.endswith(".rst"):
|
||||
|
|
@ -444,7 +504,7 @@ class PdfGenerator(Generator):
|
|||
output_pdf = os.path.join(output_path, filename)
|
||||
# print "Generating pdf for", obj.filename, " in ", output_pdf
|
||||
with open(obj.filename) as f:
|
||||
self.pdfcreator.createPdf(text=f, output=output_pdf)
|
||||
self.pdfcreator.createPdf(text=f.read(), output=output_pdf)
|
||||
logger.info(u' [ok] writing %s' % output_pdf)
|
||||
|
||||
def generate_context(self):
|
||||
|
|
@ -468,6 +528,19 @@ class PdfGenerator(Generator):
|
|||
for page in self.context['pages']:
|
||||
self._create_pdf(page, pdf_path)
|
||||
|
||||
class SourceFileGenerator(Generator):
|
||||
def generate_context(self):
|
||||
self.output_extension = self.settings['OUTPUT_SOURCES_EXTENSION']
|
||||
|
||||
def _create_source(self, obj, output_path):
|
||||
filename = os.path.splitext(obj.save_as)[0]
|
||||
dest = os.path.join(output_path, filename + self.output_extension)
|
||||
copy('', obj.filename, dest)
|
||||
|
||||
def generate_output(self, writer=None):
|
||||
logger.info(u' Generating source files...')
|
||||
for object in chain(self.context['articles'], self.context['pages']):
|
||||
self._create_source(object, self.output_path)
|
||||
|
||||
class LessCSSGenerator(Generator):
|
||||
"""Compile less css files."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue