Merge branch 'master' into html_list_tags

This commit is contained in:
Justin Mayer 2018-11-01 15:43:14 +01:00 committed by GitHub
commit 11de7b2e47
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
209 changed files with 3907 additions and 1398 deletions

View file

@ -5,21 +5,25 @@ import argparse
import collections
import locale
import logging
import multiprocessing
import os
import pprint
import re
import sys
import time
import traceback
import six
# pelican.log has to be the first pelican module to be loaded
# because logging.setLoggerClass has to be called before logging.getLogger
from pelican.log import init
from pelican.log import init as init_logging
from pelican import signals # noqa
from pelican.generators import (ArticlesGenerator, PagesGenerator,
SourceFileGenerator, StaticGenerator,
TemplatePagesGenerator)
from pelican.readers import Readers
from pelican.server import ComplexHTTPRequestHandler, RootedHTTPServer
from pelican.settings import read_settings
from pelican.utils import (clean_output_dir, file_watcher,
folder_watcher, maybe_pluralize)
@ -170,6 +174,10 @@ class Pelican(object):
if hasattr(p, 'generate_context'):
p.generate_context()
for p in generators:
if hasattr(p, 'refresh_metadata_intersite_links'):
p.refresh_metadata_intersite_links()
signals.all_generators_finalized.send(generators)
writer = self.get_writer()
@ -205,13 +213,20 @@ class Pelican(object):
len(pages_generator.hidden_translations)),
'hidden page',
'hidden pages')
pluralized_draft_pages = maybe_pluralize(
(len(pages_generator.draft_pages) +
len(pages_generator.draft_translations)),
'draft page',
'draft pages')
print('Done: Processed {}, {}, {} and {} in {:.2f} seconds.'.format(
pluralized_articles,
pluralized_drafts,
pluralized_pages,
pluralized_hidden_pages,
time.time() - start_time))
print('Done: Processed {}, {}, {}, {} and {} in {:.2f} seconds.'
.format(
pluralized_articles,
pluralized_drafts,
pluralized_pages,
pluralized_hidden_pages,
pluralized_draft_pages,
time.time() - start_time))
def get_generator_classes(self):
generators = [ArticlesGenerator, PagesGenerator]
@ -255,6 +270,32 @@ class Pelican(object):
return writer(self.output_path, settings=self.settings)
class PrintSettings(argparse.Action):
def __call__(self, parser, namespace, values, option_string):
instance, settings = get_instance(namespace)
if values:
# One or more arguments provided, so only print those settings
for setting in values:
if setting in settings:
# Only add newline between setting name and value if dict
if isinstance(settings[setting], dict):
setting_format = '\n{}:\n{}'
else:
setting_format = '\n{}: {}'
print(setting_format.format(
setting,
pprint.pformat(settings[setting])))
else:
print('\n{} is not a recognized setting.'.format(setting))
break
else:
# No argument was given to --print-settings, so print all settings
pprint.pprint(settings)
parser.exit()
def parse_arguments():
parser = argparse.ArgumentParser(
description='A tool to generate a static blog, '
@ -305,6 +346,12 @@ def parse_arguments():
help='Relaunch pelican each time a modification occurs'
' on the content files.')
parser.add_argument('--print-settings', dest='print_settings', nargs='*',
action=PrintSettings, metavar='SETTING_NAME',
help='Print current configuration settings and exit. '
'Append one or more setting name arguments to see the '
'values for specific settings only.')
parser.add_argument('--relative-urls', dest='relative_paths',
action='store_true',
help='Use relative urls in output, '
@ -327,7 +374,29 @@ def parse_arguments():
help=('Exit the program with non-zero status if any '
'errors/warnings encountered.'))
return parser.parse_args()
parser.add_argument('--logs-dedup-min-level', default='WARNING',
choices=('DEBUG', 'INFO', 'WARNING', 'ERROR'),
help=('Only enable log de-duplication for levels equal'
' to or above the specified value'))
parser.add_argument('-l', '--listen', dest='listen', action='store_true',
help='Serve content files via HTTP and port 8000.')
parser.add_argument('-p', '--port', dest='port', type=int,
help='Port to serve HTTP files at. (default: 8000)')
parser.add_argument('-b', '--bind', dest='bind',
help='IP to bind to when serving files via HTTP '
'(default: 127.0.0.1)')
args = parser.parse_args()
if args.port is not None and not args.listen:
logger.warning('--port without --listen has no effect')
if args.bind is not None and not args.listen:
logger.warning('--bind without --listen has no effect')
return args
def get_config(args):
@ -350,6 +419,10 @@ def get_config(args):
config['WRITE_SELECTED'] = args.selected_paths.split(',')
if args.relative_paths:
config['RELATIVE_URLS'] = args.relative_paths
if args.port is not None:
config['PORT'] = args.port
if args.bind is not None:
config['BIND'] = args.bind
config['DEBUG'] = args.verbosity == logging.DEBUG
# argparse returns bytes in Py2. There is no definite answer as to which
@ -382,16 +455,118 @@ def get_instance(args):
return cls(settings), settings
def autoreload(watchers, args, old_static, reader_descs, excqueue=None):
while True:
try:
# Check source dir for changed files ending with the given
# extension in the settings. In the theme dir is no such
# restriction; all files are recursively checked if they
# have changed, no matter what extension the filenames
# have.
modified = {k: next(v) for k, v in watchers.items()}
if modified['settings']:
pelican, settings = get_instance(args)
# Adjust static watchers if there are any changes
new_static = settings.get("STATIC_PATHS", [])
# Added static paths
# Add new watchers and set them as modified
new_watchers = set(new_static).difference(old_static)
for static_path in new_watchers:
static_key = '[static]%s' % static_path
watchers[static_key] = folder_watcher(
os.path.join(pelican.path, static_path),
[''],
pelican.ignore_files)
modified[static_key] = next(watchers[static_key])
# Removed static paths
# Remove watchers and modified values
old_watchers = set(old_static).difference(new_static)
for static_path in old_watchers:
static_key = '[static]%s' % static_path
watchers.pop(static_key)
modified.pop(static_key)
# Replace old_static with the new one
old_static = new_static
if any(modified.values()):
print('\n-> Modified: {}. re-generating...'.format(
', '.join(k for k, v in modified.items() if v)))
if modified['content'] is None:
logger.warning(
'No valid files found in content for '
+ 'the active readers:\n'
+ '\n'.join(reader_descs))
if modified['theme'] is None:
logger.warning('Empty theme folder. Using `basic` '
'theme.')
pelican.run()
except KeyboardInterrupt as e:
logger.warning("Keyboard interrupt, quitting.")
if excqueue is not None:
excqueue.put(traceback.format_exception_only(type(e), e)[-1])
return
except Exception as e:
if (args.verbosity == logging.DEBUG):
if excqueue is not None:
excqueue.put(
traceback.format_exception_only(type(e), e)[-1])
else:
raise
logger.warning(
'Caught exception "%s". Reloading.', e)
finally:
time.sleep(.5) # sleep to avoid cpu load
def listen(server, port, output, excqueue=None):
RootedHTTPServer.allow_reuse_address = True
try:
httpd = RootedHTTPServer(
output, (server, port), ComplexHTTPRequestHandler)
except OSError as e:
logging.error("Could not listen on port %s, server %s.", port, server)
if excqueue is not None:
excqueue.put(traceback.format_exception_only(type(e), e)[-1])
return
logging.info("Serving at port %s, server %s.", port, server)
try:
httpd.serve_forever()
except Exception as e:
if excqueue is not None:
excqueue.put(traceback.format_exception_only(type(e), e)[-1])
return
def main():
args = parse_arguments()
init(args.verbosity, args.fatal)
logs_dedup_min_level = getattr(logging, args.logs_dedup_min_level)
init_logging(args.verbosity, args.fatal,
logs_dedup_min_level=logs_dedup_min_level)
logger.debug('Pelican version: %s', __version__)
logger.debug('Python version: %s', sys.version.split()[0])
try:
pelican, settings = get_instance(args)
readers = Readers(settings)
reader_descs = sorted(set(['%s (%s)' %
(type(r).__name__,
', '.join(r.file_extensions))
for r in readers.readers.values()
if r.enabled]))
watchers = {'content': folder_watcher(pelican.path,
readers.extensions,
@ -410,76 +585,34 @@ def main():
[''],
pelican.ignore_files)
if args.autoreload:
if args.autoreload and args.listen:
excqueue = multiprocessing.Queue()
p1 = multiprocessing.Process(
target=autoreload,
args=(watchers, args, old_static, reader_descs, excqueue))
p2 = multiprocessing.Process(
target=listen,
args=(settings.get('BIND'), settings.get('PORT'),
settings.get("OUTPUT_PATH"), excqueue))
p1.start()
p2.start()
exc = excqueue.get()
p1.terminate()
p2.terminate()
logger.critical(exc)
elif args.autoreload:
print(' --- AutoReload Mode: Monitoring `content`, `theme` and'
' `settings` for changes. ---')
while True:
try:
# Check source dir for changed files ending with the given
# extension in the settings. In the theme dir is no such
# restriction; all files are recursively checked if they
# have changed, no matter what extension the filenames
# have.
modified = {k: next(v) for k, v in watchers.items()}
if modified['settings']:
pelican, settings = get_instance(args)
# Adjust static watchers if there are any changes
new_static = settings.get("STATIC_PATHS", [])
# Added static paths
# Add new watchers and set them as modified
new_watchers = set(new_static).difference(old_static)
for static_path in new_watchers:
static_key = '[static]%s' % static_path
watchers[static_key] = folder_watcher(
os.path.join(pelican.path, static_path),
[''],
pelican.ignore_files)
modified[static_key] = next(watchers[static_key])
# Removed static paths
# Remove watchers and modified values
old_watchers = set(old_static).difference(new_static)
for static_path in old_watchers:
static_key = '[static]%s' % static_path
watchers.pop(static_key)
modified.pop(static_key)
# Replace old_static with the new one
old_static = new_static
if any(modified.values()):
print('\n-> Modified: {}. re-generating...'.format(
', '.join(k for k, v in modified.items() if v)))
if modified['content'] is None:
logger.warning('No valid files found in content.')
if modified['theme'] is None:
logger.warning('Empty theme folder. Using `basic` '
'theme.')
pelican.run()
except KeyboardInterrupt:
logger.warning("Keyboard interrupt, quitting.")
break
except Exception as e:
if (args.verbosity == logging.DEBUG):
raise
logger.warning(
'Caught exception "%s". Reloading.', e)
finally:
time.sleep(.5) # sleep to avoid cpu load
autoreload(watchers, args, old_static, reader_descs)
elif args.listen:
listen(settings.get('BIND'), settings.get('PORT'),
settings.get("OUTPUT_PATH"))
else:
if next(watchers['content']) is None:
logger.warning('No valid files found in content.')
logger.warning(
'No valid files found in content for '
+ 'the active readers:\n'
+ '\n'.join(reader_descs))
if next(watchers['theme']) is None:
logger.warning('Empty theme folder. Using `basic` theme.')

View file

@ -11,7 +11,7 @@ import sys
import pytz
import six
from six.moves.urllib.parse import urlparse, urlunparse
from six.moves.urllib.parse import urljoin, urlparse, urlunparse
from pelican import signals
from pelican.settings import DEFAULT_CONFIG
@ -98,14 +98,16 @@ class Content(object):
if not hasattr(self, 'slug'):
if (settings['SLUGIFY_SOURCE'] == 'title' and
hasattr(self, 'title')):
self.slug = slugify(self.title,
settings.get('SLUG_SUBSTITUTIONS', ()))
self.slug = slugify(
self.title,
regex_subs=settings.get('SLUG_REGEX_SUBSTITUTIONS', []))
elif (settings['SLUGIFY_SOURCE'] == 'basename' and
source_path is not None):
basename = os.path.basename(
os.path.splitext(source_path)[0])
self.slug = slugify(
basename, settings.get('SLUG_SUBSTITUTIONS', ()))
basename,
regex_subs=settings.get('SLUG_REGEX_SUBSTITUTIONS', []))
self.source_path = source_path
@ -140,9 +142,8 @@ class Content(object):
if not hasattr(self, 'status'):
self.status = getattr(self, 'default_status', None)
# store the summary metadata if it is set
if 'summary' in metadata:
self._summary = metadata['summary']
if len(self._context.get('filenames', [])) > 0:
self.refresh_metadata_intersite_links()
signals.content_object_init.send(self)
@ -228,6 +229,87 @@ class Content(object):
key = key if self.in_default_lang else 'lang_%s' % key
return self._expand_settings(key)
def _link_replacer(self, siteurl, m):
what = m.group('what')
value = urlparse(m.group('value'))
path = value.path
origin = m.group('path')
# urllib.parse.urljoin() produces `a.html` for urljoin("..", "a.html")
# so if RELATIVE_URLS are enabled, we fall back to os.path.join() to
# properly get `../a.html`. However, os.path.join() produces
# `baz/http://foo/bar.html` for join("baz", "http://foo/bar.html")
# instead of correct "http://foo/bar.html", so one has to pick a side
# as there is no silver bullet.
if self.settings['RELATIVE_URLS']:
joiner = os.path.join
else:
joiner = urljoin
# However, it's not *that* simple: urljoin("blog", "index.html")
# produces just `index.html` instead of `blog/index.html` (unlike
# os.path.join()), so in order to get a correct answer one needs to
# append a trailing slash to siteurl in that case. This also makes
# the new behavior fully compatible with Pelican 3.7.1.
if not siteurl.endswith('/'):
siteurl += '/'
# XXX Put this in a different location.
if what in {'filename', 'attach'}:
if path.startswith('/'):
path = path[1:]
else:
# relative to the source path of this content
path = self.get_relative_source_path(
os.path.join(self.relative_dir, path)
)
if path not in self._context['filenames']:
unquoted_path = path.replace('%20', ' ')
if unquoted_path in self._context['filenames']:
path = unquoted_path
linked_content = self._context['filenames'].get(path)
if linked_content:
if what == 'attach':
if isinstance(linked_content, Static):
linked_content.attach_to(self)
else:
logger.warning(
"%s used {attach} link syntax on a "
"non-static file. Use {filename} instead.",
self.get_relative_source_path())
origin = joiner(siteurl, linked_content.url)
origin = origin.replace('\\', '/') # for Windows paths.
else:
logger.warning(
"Unable to find '%s', skipping url replacement.",
value.geturl(), extra={
'limit_msg': ("Other resources were not found "
"and their urls not replaced")})
elif what == 'category':
origin = joiner(siteurl, Category(path, self.settings).url)
elif what == 'tag':
origin = joiner(siteurl, Tag(path, self.settings).url)
elif what == 'index':
origin = joiner(siteurl, self.settings['INDEX_SAVE_AS'])
elif what == 'author':
origin = joiner(siteurl, Author(path, self.settings).url)
else:
logger.warning(
"Replacement Indicator '%s' not recognized, "
"skipping replacement",
what)
# keep all other parts, such as query, fragment, etc.
parts = list(value)
parts[2] = origin
origin = urlunparse(parts)
return ''.join((m.group('markup'), m.group('quote'), origin,
m.group('quote')))
def _update_content(self, content, siteurl):
"""Update the content attribute.
@ -251,69 +333,7 @@ class Content(object):
\2""".format(instrasite_link_regex)
hrefs = re.compile(regex, re.X)
def replacer(m):
what = m.group('what')
value = urlparse(m.group('value'))
path = value.path
origin = m.group('path')
# XXX Put this in a different location.
if what in {'filename', 'attach'}:
if path.startswith('/'):
path = path[1:]
else:
# relative to the source path of this content
path = self.get_relative_source_path(
os.path.join(self.relative_dir, path)
)
if path not in self._context['filenames']:
unquoted_path = path.replace('%20', ' ')
if unquoted_path in self._context['filenames']:
path = unquoted_path
linked_content = self._context['filenames'].get(path)
if linked_content:
if what == 'attach':
if isinstance(linked_content, Static):
linked_content.attach_to(self)
else:
logger.warning(
"%s used {attach} link syntax on a "
"non-static file. Use {filename} instead.",
self.get_relative_source_path())
origin = '/'.join((siteurl, linked_content.url))
origin = origin.replace('\\', '/') # for Windows paths.
else:
logger.warning(
"Unable to find '%s', skipping url replacement.",
value.geturl(), extra={
'limit_msg': ("Other resources were not found "
"and their urls not replaced")})
elif what == 'category':
origin = '/'.join((siteurl, Category(path, self.settings).url))
elif what == 'tag':
origin = '/'.join((siteurl, Tag(path, self.settings).url))
elif what == 'index':
origin = '/'.join((siteurl, self.settings['INDEX_SAVE_AS']))
elif what == 'author':
origin = '/'.join((siteurl, Author(path, self.settings).url))
else:
logger.warning(
"Replacement Indicator '%s' not recognized, "
"skipping replacement",
what)
# keep all other parts, such as query, fragment, etc.
parts = list(value)
parts[2] = origin
origin = urlunparse(parts)
return ''.join((m.group('markup'), m.group('quote'), origin,
m.group('quote')))
return hrefs.sub(replacer, content)
return hrefs.sub(lambda m: self._link_replacer(siteurl, m), content)
def get_siteurl(self):
return self._context.get('localsiteurl', '')
@ -337,8 +357,8 @@ class Content(object):
This is based on the summary metadata if set, otherwise truncate the
content.
"""
if hasattr(self, '_summary'):
return self._update_content(self._summary, siteurl)
if 'summary' in self.metadata:
return self.metadata['summary']
if self.settings['SUMMARY_MAX_LENGTH'] is None:
return self.content
@ -413,13 +433,27 @@ class Content(object):
os.path.abspath(self.source_path),
os.path.abspath(self.settings['PATH']))))
def refresh_metadata_intersite_links(self):
for key in self.settings['FORMATTED_FIELDS']:
if key in self.metadata:
value = self._update_content(
self.metadata[key],
self.get_siteurl()
)
self.metadata[key] = value
setattr(self, key.lower(), value)
class Page(Content):
mandatory_properties = ('title',)
allowed_statuses = ('published', 'hidden')
allowed_statuses = ('published', 'hidden', 'draft')
default_status = 'published'
default_template = 'page'
def _expand_settings(self, key):
klass = 'draft_page' if self.status == 'draft' else None
return super(Page, self)._expand_settings(key, klass)
class Article(Content):
mandatory_properties = ('title', 'date', 'category')
@ -444,7 +478,7 @@ class Article(Content):
self.date = SafeDatetime.max
def _expand_settings(self, key):
klass = 'article' if self.status == 'published' else 'draft'
klass = 'draft' if self.status == 'draft' else 'article'
return super(Article, self)._expand_settings(key, klass)

View file

@ -21,8 +21,9 @@ from pelican import signals
from pelican.cache import FileStampDataCacher
from pelican.contents import Article, Page, Static
from pelican.readers import Readers
from pelican.utils import (DateFormatter, copy, mkdir_p, posixize_path,
process_translations, python_2_unicode_compatible)
from pelican.utils import (DateFormatter, copy, mkdir_p, order_content,
posixize_path, process_translations,
python_2_unicode_compatible)
logger = logging.getLogger(__name__)
@ -51,20 +52,25 @@ class Generator(object):
# templates cache
self._templates = {}
self._templates_path = []
self._templates_path.append(os.path.expanduser(
os.path.join(self.theme, 'templates')))
self._templates_path += self.settings['EXTRA_TEMPLATES_PATHS']
self._templates_path = list(self.settings['THEME_TEMPLATES_OVERRIDES'])
theme_path = os.path.dirname(os.path.abspath(__file__))
theme_templates_path = os.path.expanduser(
os.path.join(self.theme, 'templates'))
self._templates_path.append(theme_templates_path)
theme_loader = FileSystemLoader(theme_templates_path)
simple_theme_path = os.path.dirname(os.path.abspath(__file__))
simple_loader = FileSystemLoader(
os.path.join(simple_theme_path, "themes", "simple", "templates"))
simple_loader = FileSystemLoader(os.path.join(theme_path,
"themes", "simple", "templates"))
self.env = Environment(
loader=ChoiceLoader([
FileSystemLoader(self._templates_path),
simple_loader, # implicit inheritance
PrefixLoader({'!simple': simple_loader}) # explicit one
PrefixLoader({
'!simple': simple_loader,
'!theme': theme_loader
}) # explicit ones
]),
**self.settings['JINJA_ENVIRONMENT']
)
@ -86,12 +92,19 @@ class Generator(object):
templates ready to use with Jinja2.
"""
if name not in self._templates:
try:
self._templates[name] = self.env.get_template(name + '.html')
except TemplateNotFound:
for ext in self.settings['TEMPLATE_EXTENSIONS']:
try:
self._templates[name] = self.env.get_template(name + ext)
break
except TemplateNotFound:
continue
if name not in self._templates:
raise PelicanTemplateNotFound(
'[templates] unable to load {}.html from {}'.format(
name, self._templates_path))
'[templates] unable to load {}[{}] from {}'.format(
name, ', '.join(self.settings['TEMPLATE_EXTENSIONS']),
self._templates_path))
return self._templates[name]
def _include_path(self, path, extensions=None):
@ -255,7 +268,7 @@ class TemplatePagesGenerator(Generator):
template = self.env.get_template(source)
rurls = self.settings['RELATIVE_URLS']
writer.write_file(dest, template, self.context, rurls,
override_output=True)
override_output=True, url='')
finally:
del self.env.loader.loaders[0]
@ -282,67 +295,100 @@ class ArticlesGenerator(CachingGenerator):
if self.settings.get('FEED_ATOM'):
writer.write_feed(self.articles, self.context,
self.settings['FEED_ATOM'])
self.settings['FEED_ATOM'],
self.settings.get('FEED_ATOM_URL',
self.settings['FEED_ATOM']))
if self.settings.get('FEED_RSS'):
writer.write_feed(self.articles, self.context,
self.settings['FEED_RSS'], feed_type='rss')
self.settings['FEED_RSS'],
self.settings.get('FEED_RSS_URL',
self.settings['FEED_RSS']),
feed_type='rss')
if (self.settings.get('FEED_ALL_ATOM') or
self.settings.get('FEED_ALL_RSS')):
all_articles = list(self.articles)
for article in self.articles:
all_articles.extend(article.translations)
all_articles.sort(key=attrgetter('date'), reverse=True)
order_content(all_articles,
order_by=self.settings['ARTICLE_ORDER_BY'])
if self.settings.get('FEED_ALL_ATOM'):
writer.write_feed(all_articles, self.context,
self.settings['FEED_ALL_ATOM'])
self.settings['FEED_ALL_ATOM'],
self.settings.get(
'FEED_ALL_ATOM_URL',
self.settings['FEED_ALL_ATOM']))
if self.settings.get('FEED_ALL_RSS'):
writer.write_feed(all_articles, self.context,
self.settings['FEED_ALL_RSS'],
self.settings.get(
'FEED_ALL_RSS_URL',
self.settings['FEED_ALL_RSS']),
feed_type='rss')
for cat, arts in self.categories:
arts.sort(key=attrgetter('date'), reverse=True)
if self.settings.get('CATEGORY_FEED_ATOM'):
writer.write_feed(arts, self.context,
self.settings['CATEGORY_FEED_ATOM']
% cat.slug,
self.settings.get(
'CATEGORY_FEED_ATOM_URL',
self.settings['CATEGORY_FEED_ATOM'])
% cat.slug, feed_title=cat.name)
if self.settings.get('CATEGORY_FEED_RSS'):
writer.write_feed(arts, self.context,
self.settings['CATEGORY_FEED_RSS']
% cat.slug,
self.settings.get(
'CATEGORY_FEED_RSS_URL',
self.settings['CATEGORY_FEED_RSS'])
% cat.slug, feed_title=cat.name,
feed_type='rss')
for auth, arts in self.authors:
arts.sort(key=attrgetter('date'), reverse=True)
if self.settings.get('AUTHOR_FEED_ATOM'):
writer.write_feed(arts, self.context,
self.settings['AUTHOR_FEED_ATOM']
% auth.slug,
self.settings.get(
'AUTHOR_FEED_ATOM_URL',
self.settings['AUTHOR_FEED_ATOM'])
% auth.slug, feed_title=auth.name)
if self.settings.get('AUTHOR_FEED_RSS'):
writer.write_feed(arts, self.context,
self.settings['AUTHOR_FEED_RSS']
% auth.slug,
self.settings.get(
'AUTHOR_FEED_RSS_URL',
self.settings['AUTHOR_FEED_RSS'])
% auth.slug, feed_title=auth.name,
feed_type='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_ATOM'):
writer.write_feed(arts, self.context,
self.settings['TAG_FEED_ATOM']
% tag.slug,
self.settings.get(
'TAG_FEED_ATOM_URL',
self.settings['TAG_FEED_ATOM'])
% tag.slug, feed_title=tag.name)
if self.settings.get('TAG_FEED_RSS'):
writer.write_feed(arts, self.context,
self.settings['TAG_FEED_RSS'] % tag.slug,
feed_title=tag.name, feed_type='rss')
self.settings.get(
'TAG_FEED_RSS_URL',
self.settings['TAG_FEED_RSS'])
% tag.slug, feed_title=tag.name,
feed_type='rss')
if (self.settings.get('TRANSLATION_FEED_ATOM') or
self.settings.get('TRANSLATION_FEED_RSS')):
@ -351,15 +397,22 @@ class ArticlesGenerator(CachingGenerator):
translations_feeds[article.lang].append(article)
for lang, items in translations_feeds.items():
items.sort(key=attrgetter('date'), reverse=True)
items = order_content(
items, order_by=self.settings['ARTICLE_ORDER_BY'])
if self.settings.get('TRANSLATION_FEED_ATOM'):
writer.write_feed(
items, self.context,
self.settings['TRANSLATION_FEED_ATOM'] % lang)
self.settings['TRANSLATION_FEED_ATOM'] % lang,
self.settings.get(
'TRANSLATION_FEED_ATOM_URL',
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,
self.settings.get(
'TRANSLATION_FEED_RSS_URL',
self.settings['TRANSLATION_FEED_RSS']) % lang,
feed_type='rss')
def generate_articles(self, write):
@ -369,7 +422,7 @@ class ArticlesGenerator(CachingGenerator):
write(article.save_as, self.get_template(article.template),
self.context, article=article, category=article.category,
override_output=hasattr(article, 'override_save_as'),
blog=True)
url=article.url, blog=True)
def generate_period_archives(self, write):
"""Generate per-year, per-month, and per-day archives."""
@ -384,24 +437,32 @@ class ArticlesGenerator(CachingGenerator):
'day': self.settings['DAY_ARCHIVE_SAVE_AS'],
}
period_url = {
'year': self.settings['YEAR_ARCHIVE_URL'],
'month': self.settings['MONTH_ARCHIVE_URL'],
'day': self.settings['DAY_ARCHIVE_URL'],
}
period_date_key = {
'year': attrgetter('date.year'),
'month': attrgetter('date.year', 'date.month'),
'day': attrgetter('date.year', 'date.month', 'date.day')
}
def _generate_period_archives(dates, key, save_as_fmt):
def _generate_period_archives(dates, key, save_as_fmt, url_fmt):
"""Generate period archives from `dates`, grouped by
`key` and written to `save_as`.
"""
# `dates` is already sorted by date
for _period, group in groupby(dates, key=key):
archive = list(group)
articles = [a for a in self.articles if a in archive]
# arbitrarily grab the first date so that the usual
# format string syntax can be used for specifying the
# period archive dates
date = archive[0].date
save_as = save_as_fmt.format(date=date)
url = url_fmt.format(date=date)
context = self.context.copy()
if key == period_date_key['year']:
@ -418,62 +479,60 @@ class ArticlesGenerator(CachingGenerator):
month_name,
_period[2])
write(save_as, template, context,
dates=archive, blog=True)
write(save_as, template, context, articles=articles,
dates=archive, template_name='period_archives',
blog=True, url=url)
for period in 'year', 'month', 'day':
save_as = period_save_as[period]
url = period_url[period]
if save_as:
key = period_date_key[period]
_generate_period_archives(self.dates, key, save_as)
_generate_period_archives(self.dates, key, save_as, url)
def generate_direct_templates(self, write):
"""Generate direct templates pages"""
PAGINATED_TEMPLATES = self.settings['PAGINATED_DIRECT_TEMPLATES']
for template in self.settings['DIRECT_TEMPLATES']:
paginated = {}
if template in PAGINATED_TEMPLATES:
paginated = {'articles': self.articles, 'dates': self.dates}
save_as = self.settings.get("%s_SAVE_AS" % template.upper(),
'%s.html' % template)
url = self.settings.get("%s_URL" % template.upper(),
'%s.html' % template)
if not save_as:
continue
write(save_as, self.get_template(template),
self.context, blog=True, paginated=paginated,
page_name=os.path.splitext(save_as)[0])
write(save_as, self.get_template(template), self.context,
articles=self.articles, dates=self.dates, blog=True,
template_name=template,
page_name=os.path.splitext(save_as)[0], url=url)
def generate_tags(self, write):
"""Generate Tags pages."""
tag_template = self.get_template('tag')
for tag, articles in self.tags.items():
articles.sort(key=attrgetter('date'), reverse=True)
dates = [article for article in self.dates if article in articles]
write(tag.save_as, tag_template, self.context, tag=tag,
articles=articles, dates=dates,
paginated={'articles': articles, 'dates': dates}, blog=True,
page_name=tag.page_name, all_articles=self.articles)
url=tag.url, articles=articles, dates=dates,
template_name='tag', blog=True, page_name=tag.page_name,
all_articles=self.articles)
def generate_categories(self, write):
"""Generate category pages."""
category_template = self.get_template('category')
for cat, articles in self.categories:
articles.sort(key=attrgetter('date'), reverse=True)
dates = [article for article in self.dates if article in articles]
write(cat.save_as, category_template, self.context,
write(cat.save_as, category_template, self.context, url=cat.url,
category=cat, articles=articles, dates=dates,
paginated={'articles': articles, 'dates': dates}, blog=True,
page_name=cat.page_name, all_articles=self.articles)
template_name='category', blog=True, page_name=cat.page_name,
all_articles=self.articles)
def generate_authors(self, write):
"""Generate Author pages."""
author_template = self.get_template('author')
for aut, articles in self.authors:
articles.sort(key=attrgetter('date'), reverse=True)
dates = [article for article in self.dates if article in articles]
write(aut.save_as, author_template, self.context,
author=aut, articles=articles, dates=dates,
paginated={'articles': articles, 'dates': dates}, blog=True,
url=aut.url, author=aut, articles=articles, dates=dates,
template_name='author', blog=True,
page_name=aut.page_name, all_articles=self.articles)
def generate_drafts(self, write):
@ -482,7 +541,7 @@ class ArticlesGenerator(CachingGenerator):
write(draft.save_as, self.get_template(draft.template),
self.context, article=draft, category=draft.category,
override_output=hasattr(draft, 'override_save_as'),
blog=True, all_articles=self.articles)
blog=True, all_articles=self.articles, url=draft.url)
def generate_pages(self, writer):
"""Generate the pages on the disk"""
@ -538,11 +597,14 @@ class ArticlesGenerator(CachingGenerator):
all_drafts.append(article)
self.add_source_path(article)
self.articles, self.translations = process_translations(
all_articles,
order_by=self.settings['ARTICLE_ORDER_BY'])
self.drafts, self.drafts_translations = \
process_translations(all_drafts)
def _process(arts):
origs, translations = process_translations(
arts, translation_id=self.settings['ARTICLE_TRANSLATION_ID'])
origs = order_content(origs, self.settings['ARTICLE_ORDER_BY'])
return origs, translations
self.articles, self.translations = _process(all_articles)
self.drafts, self.drafts_translations = _process(all_drafts)
signals.article_generator_pretaxonomy.send(self)
@ -581,20 +643,32 @@ class ArticlesGenerator(CachingGenerator):
self.generate_pages(writer)
signals.article_writer_finalized.send(self, writer=writer)
def refresh_metadata_intersite_links(self):
for e in chain(self.articles,
self.translations,
self.drafts,
self.drafts_translations):
if hasattr(e, 'refresh_metadata_intersite_links'):
e.refresh_metadata_intersite_links()
class PagesGenerator(CachingGenerator):
"""Generate pages"""
def __init__(self, *args, **kwargs):
self.pages = []
self.translations = []
self.hidden_pages = []
self.hidden_translations = []
self.draft_pages = []
self.draft_translations = []
super(PagesGenerator, self).__init__(*args, **kwargs)
signals.page_generator_init.send(self)
def generate_context(self):
all_pages = []
hidden_pages = []
draft_pages = []
for f in self.get_files(
self.settings['PAGE_PATHS'],
exclude=self.settings['PAGE_EXCLUDES']):
@ -625,15 +699,21 @@ class PagesGenerator(CachingGenerator):
all_pages.append(page)
elif page.status == "hidden":
hidden_pages.append(page)
elif page.status == "draft":
draft_pages.append(page)
self.add_source_path(page)
self.pages, self.translations = process_translations(
all_pages,
order_by=self.settings['PAGE_ORDER_BY'])
self.hidden_pages, self.hidden_translations = \
process_translations(hidden_pages)
def _process(pages):
origs, translations = process_translations(
pages, translation_id=self.settings['PAGE_TRANSLATION_ID'])
origs = order_content(origs, self.settings['PAGE_ORDER_BY'])
return origs, translations
self._update_context(('pages', 'hidden_pages'))
self.pages, self.translations = _process(all_pages)
self.hidden_pages, self.hidden_translations = _process(hidden_pages)
self.draft_pages, self.draft_translations = _process(draft_pages)
self._update_context(('pages', 'hidden_pages', 'draft_pages'))
self.save_cache()
self.readers.save_cache()
@ -641,14 +721,26 @@ class PagesGenerator(CachingGenerator):
def generate_output(self, writer):
for page in chain(self.translations, self.pages,
self.hidden_translations, self.hidden_pages):
self.hidden_translations, self.hidden_pages,
self.draft_translations, self.draft_pages):
signals.page_generator_write_page.send(self, content=page)
writer.write_file(
page.save_as, self.get_template(page.template),
self.context, page=page,
relative_urls=self.settings['RELATIVE_URLS'],
override_output=hasattr(page, 'override_save_as'))
override_output=hasattr(page, 'override_save_as'),
url=page.url)
signals.page_writer_finalized.send(self, writer=writer)
def refresh_metadata_intersite_links(self):
for e in chain(self.pages,
self.hidden_pages,
self.hidden_translations,
self.draft_pages,
self.draft_translations):
if hasattr(e, 'refresh_metadata_intersite_links'):
e.refresh_metadata_intersite_links()
class StaticGenerator(Generator):
"""copy static paths (what you want to copy, like images, medias etc.
@ -696,14 +788,21 @@ class StaticGenerator(Generator):
final_path=None):
"""Copy all the paths from source to destination"""
for path in paths:
source_path = os.path.join(source, path)
if final_path:
copy(os.path.join(source, path),
os.path.join(output_path, destination, final_path),
self.settings['IGNORE_FILES'])
if os.path.isfile(source_path):
destination_path = os.path.join(output_path, destination,
final_path,
os.path.basename(path))
else:
destination_path = os.path.join(output_path, destination,
final_path)
else:
copy(os.path.join(source, path),
os.path.join(output_path, destination, path),
self.settings['IGNORE_FILES'])
destination_path = os.path.join(output_path, destination, path)
copy(source_path, destination_path,
self.settings['IGNORE_FILES'])
def _file_update_required(self, staticfile):
source_path = os.path.join(self.path, staticfile.source_path)
@ -726,7 +825,7 @@ class StaticGenerator(Generator):
save_as = os.path.join(self.output_path, staticfile.save_as)
s_mtime = os.path.getmtime(source_path)
d_mtime = os.path.getmtime(save_as)
return s_mtime > d_mtime
return s_mtime - d_mtime > 0.000001
def _link_or_copy_staticfile(self, sc):
if self.settings['STATIC_CREATE_LINKS']:

View file

@ -91,6 +91,8 @@ class LimitFilter(logging.Filter):
E.g.: log.warning(('43 is not the answer', 'More erroneous answers'))
"""
LOGS_DEDUP_MIN_LEVEL = logging.WARNING
_ignore = set()
_raised_messages = set()
_threshold = 5
@ -98,7 +100,7 @@ class LimitFilter(logging.Filter):
def filter(self, record):
# don't limit log messages for anything above "warning"
if record.levelno > logging.WARN:
if record.levelno > self.LOGS_DEDUP_MIN_LEVEL:
return True
# extract group
@ -226,7 +228,8 @@ def get_formatter():
return TextFormatter()
def init(level=None, fatal='', handler=logging.StreamHandler(), name=None):
def init(level=None, fatal='', handler=logging.StreamHandler(), name=None,
logs_dedup_min_level=None):
FatalLogger.warnings_fatal = fatal.startswith('warning')
FatalLogger.errors_fatal = bool(fatal)
@ -237,6 +240,8 @@ def init(level=None, fatal='', handler=logging.StreamHandler(), name=None):
if level:
logger.setLevel(level)
if logs_dedup_min_level:
LimitFilter.LOGS_DEDUP_MIN_LEVEL = logs_dedup_min_level
def log_warnings():

View file

@ -17,14 +17,14 @@ PaginationRule = namedtuple(
class Paginator(object):
def __init__(self, name, object_list, settings):
def __init__(self, name, url, object_list, settings, per_page=None):
self.name = name
self.url = url
self.object_list = object_list
self.settings = settings
if settings.get('DEFAULT_PAGINATION'):
self.per_page = settings.get('DEFAULT_PAGINATION')
self.orphans = settings.get('DEFAULT_ORPHANS')
if per_page:
self.per_page = per_page
self.orphans = settings['DEFAULT_ORPHANS']
else:
self.per_page = len(object_list)
self.orphans = 0
@ -37,8 +37,8 @@ class Paginator(object):
top = bottom + self.per_page
if top + self.orphans >= self.count:
top = self.count
return Page(self.name, self.object_list[bottom:top], number, self,
self.settings)
return Page(self.name, self.url, self.object_list[bottom:top], number,
self, self.settings)
def _get_count(self):
"Returns the total number of objects, across all pages."
@ -65,8 +65,12 @@ class Paginator(object):
class Page(object):
def __init__(self, name, object_list, number, paginator, settings):
def __init__(self, name, url, object_list, number, paginator, settings):
self.full_name = name
self.name, self.extension = os.path.splitext(name)
dn, fn = os.path.split(name)
self.base_name = dn if fn in ('index.htm', 'index.html') else self.name
self.base_url = url
self.object_list = object_list
self.number = number
self.paginator = paginator
@ -133,24 +137,16 @@ class Page(object):
# URL or SAVE_AS is a string, format it with a controlled context
context = {
'name': self.name.replace(os.sep, '/'),
'object_list': self.object_list,
'number': self.number,
'paginator': self.paginator,
'settings': self.settings,
'base_name': os.path.dirname(self.name),
'number_sep': '/',
'save_as': self.full_name,
'url': self.base_url,
'name': self.name,
'base_name': self.base_name,
'extension': self.extension,
'number': self.number,
}
if self.number == 1:
# no page numbers on the first page
context['number'] = ''
context['number_sep'] = ''
ret = prop_value.format(**context)
if ret[0] == '/':
ret = ret[1:]
ret = ret.lstrip('/')
return ret
url = property(functools.partial(_from_settings, key='URL'))

View file

@ -31,6 +31,20 @@ except ImportError:
# This means that _filter_discardable_metadata() must be called on processed
# metadata dicts before use, to remove the items with the special value.
_DISCARD = object()
DUPLICATES_DEFINITIONS_ALLOWED = {
'tags': False,
'date': False,
'modified': False,
'status': False,
'category': False,
'author': False,
'save_as': False,
'url': False,
'authors': False,
'slug': False
}
METADATA_PROCESSORS = {
'tags': lambda x, y: ([
Tag(tag, y)
@ -203,11 +217,18 @@ class RstReader(BaseReader):
def __init__(self, *args, **kwargs):
super(RstReader, self).__init__(*args, **kwargs)
def _parse_metadata(self, document):
def _parse_metadata(self, document, source_path):
"""Return the dict containing document metadata"""
formatted_fields = self.settings['FORMATTED_FIELDS']
output = {}
if document.first_child_matching_class(docutils.nodes.title) is None:
logger.warning(
'Document title missing in file %s: '
'Ensure exactly one top level section',
source_path)
for docinfo in document.traverse(docutils.nodes.docinfo):
for element in docinfo.children:
if element.tagname == 'field': # custom fields (e.g. summary)
@ -234,6 +255,7 @@ class RstReader(BaseReader):
extra_params = {'initial_header_level': '2',
'syntax_highlight': 'short',
'input_encoding': 'utf-8',
'language_code': self.settings.get('DEFAULT_LANG'),
'exit_status_level': 2,
'embed_stylesheet': False}
user_params = self.settings.get('DOCUTILS_SETTINGS')
@ -256,7 +278,7 @@ class RstReader(BaseReader):
parts = pub.writer.parts
content = parts.get('body')
metadata = self._parse_metadata(pub.document)
metadata = self._parse_metadata(pub.document, source_path)
metadata.setdefault('title', parts.get('title'))
return content, metadata
@ -294,7 +316,7 @@ class MarkdownReader(BaseReader):
self._md.reset()
formatted = self._md.convert(formatted_values)
output[name] = self.process_metadata(name, formatted)
elif name in METADATA_PROCESSORS:
elif not DUPLICATES_DEFINITIONS_ALLOWED.get(name, True):
if len(value) > 1:
logger.warning(
'Duplicate definition of `%s` '

View file

@ -1,8 +1,11 @@
# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import argparse
import logging
import os
import posixpath
import ssl
import sys
try:
@ -10,37 +13,81 @@ try:
except ImportError:
magic_from_file = None
from six.moves import BaseHTTPServer
from six.moves import SimpleHTTPServer as srvmod
from six.moves import socketserver
from six.moves import urllib
def parse_arguments():
parser = argparse.ArgumentParser(
description='Pelican Development Server',
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument("port", default=8000, type=int, nargs="?",
help="Port to Listen On")
parser.add_argument("server", default="", nargs="?",
help="Interface to Listen On")
parser.add_argument('--ssl', action="store_true",
help='Activate SSL listener')
parser.add_argument('--cert', default="./cert.pem", nargs="?",
help='Path to certificate file. ' +
'Relative to current directory')
parser.add_argument('--key', default="./key.pem", nargs="?",
help='Path to certificate key file. ' +
'Relative to current directory')
parser.add_argument('--path', default=".",
help='Path to pelican source directory to serve. ' +
'Relative to current directory')
return parser.parse_args()
class ComplexHTTPRequestHandler(srvmod.SimpleHTTPRequestHandler):
SUFFIXES = ['', '.html', '/index.html']
SUFFIXES = ['.html', '/index.html', '/', '']
def translate_path(self, path):
# abandon query parameters
path = path.split('?', 1)[0]
path = path.split('#', 1)[0]
# Don't forget explicit trailing slash when normalizing. Issue17324
trailing_slash = path.rstrip().endswith('/')
path = urllib.parse.unquote(path)
path = posixpath.normpath(path)
words = path.split('/')
words = filter(None, words)
path = self.base_path
for word in words:
if os.path.dirname(word) or word in (os.curdir, os.pardir):
# Ignore components that are not a simple file/directory name
continue
path = os.path.join(path, word)
if trailing_slash:
path += '/'
return path
def do_GET(self):
# cut off a query string
if '?' in self.path:
self.path, _ = self.path.split('?', 1)
original_path = self.path.split('?', 1)[0]
# try to find file
self.path = self.get_path_that_exists(original_path)
if not self.path:
logging.warning("Unable to find `%s` or variations.",
original_path)
return
logging.info("Found `%s`.", self.path)
srvmod.SimpleHTTPRequestHandler.do_GET(self)
def get_path_that_exists(self, original_path):
# Try to strip trailing slash
original_path = original_path.rstrip('/')
# Try to detect file by applying various suffixes
for suffix in self.SUFFIXES:
if not hasattr(self, 'original_path'):
self.original_path = self.path
self.path = self.original_path + suffix
path = self.translate_path(self.path)
if os.path.exists(path):
srvmod.SimpleHTTPRequestHandler.do_GET(self)
logging.info("Found `%s`." % self.path)
break
logging.info("Tried to find `%s`, but it doesn't exist.",
self.path)
else:
# Fallback if there were no matches
logging.warning("Unable to find `%s` or variations.",
self.original_path)
path = original_path + suffix
if os.path.exists(self.translate_path(path)):
return path
logging.info("Tried to find `%s`, but it doesn't exist.", path)
return None
def guess_type(self, path):
"""Guess at the mime type for the specified file.
@ -54,19 +101,36 @@ class ComplexHTTPRequestHandler(srvmod.SimpleHTTPRequestHandler):
return mimetype
if __name__ == '__main__':
PORT = len(sys.argv) in (2, 3) and int(sys.argv[1]) or 8000
SERVER = len(sys.argv) == 3 and sys.argv[2] or ""
class RootedHTTPServer(BaseHTTPServer.HTTPServer):
def __init__(self, base_path, *args, **kwargs):
BaseHTTPServer.HTTPServer.__init__(self, *args, **kwargs)
self.RequestHandlerClass.base_path = base_path
socketserver.TCPServer.allow_reuse_address = True
if __name__ == '__main__':
logging.warning("'python -m pelican.server' is deprecated. The "
"Pelican development server should be run via "
"'pelican --listen' or 'pelican -l' (this can be combined "
"with regeneration as 'pelican -lr'). Rerun 'pelican-"
"quickstart' to get new Makefile and tasks.py files.")
args = parse_arguments()
RootedHTTPServer.allow_reuse_address = True
try:
httpd = socketserver.TCPServer(
(SERVER, PORT), ComplexHTTPRequestHandler)
except OSError as e:
logging.error("Could not listen on port %s, server %s.", PORT, SERVER)
httpd = RootedHTTPServer(
args.path, (args.server, args.port), ComplexHTTPRequestHandler)
if args.ssl:
httpd.socket = ssl.wrap_socket(
httpd.socket, keyfile=args.key,
certfile=args.cert, server_side=True)
except ssl.SSLError as e:
logging.error("Couldn't open certificate file %s or key file %s",
args.cert, args.key)
logging.error("Could not listen on port %s, server %s.",
args.port, args.server)
sys.exit(getattr(e, 'exitcode', 1))
logging.info("Serving at port %s, server %s.", PORT, SERVER)
logging.info("Serving at port %s, server %s.",
args.port, args.server)
try:
httpd.serve_forever()
except KeyboardInterrupt as e:

View file

@ -6,6 +6,7 @@ import inspect
import locale
import logging
import os
import re
from os.path import isabs
from posixpath import join as posix_join
@ -80,6 +81,11 @@ DEFAULT_CONFIG = {
'PAGE_ORDER_BY': 'basename',
'PAGE_LANG_URL': 'pages/{slug}-{lang}.html',
'PAGE_LANG_SAVE_AS': posix_join('pages', '{slug}-{lang}.html'),
'DRAFT_PAGE_URL': 'drafts/pages/{slug}.html',
'DRAFT_PAGE_SAVE_AS': posix_join('drafts', 'pages', '{slug}.html'),
'DRAFT_PAGE_LANG_URL': 'drafts/pages/{slug}-{lang}.html',
'DRAFT_PAGE_LANG_SAVE_AS': posix_join('drafts', 'pages',
'{slug}-{lang}.html'),
'STATIC_URL': '{path}',
'STATIC_SAVE_AS': '{path}',
'STATIC_CREATE_LINKS': False,
@ -91,16 +97,23 @@ DEFAULT_CONFIG = {
'AUTHOR_URL': 'author/{slug}.html',
'AUTHOR_SAVE_AS': posix_join('author', '{slug}.html'),
'PAGINATION_PATTERNS': [
(0, '{name}{number}{extension}', '{name}{number}{extension}'),
(1, '{name}{extension}', '{name}{extension}'),
(2, '{name}{number}{extension}', '{name}{number}{extension}'),
],
'YEAR_ARCHIVE_URL': '',
'YEAR_ARCHIVE_SAVE_AS': '',
'MONTH_ARCHIVE_URL': '',
'MONTH_ARCHIVE_SAVE_AS': '',
'DAY_ARCHIVE_URL': '',
'DAY_ARCHIVE_SAVE_AS': '',
'RELATIVE_URLS': False,
'DEFAULT_LANG': 'en',
'ARTICLE_TRANSLATION_ID': 'slug',
'PAGE_TRANSLATION_ID': 'slug',
'DIRECT_TEMPLATES': ['index', 'tags', 'categories', 'authors', 'archives'],
'EXTRA_TEMPLATES_PATHS': [],
'PAGINATED_DIRECT_TEMPLATES': ['index'],
'THEME_TEMPLATES_OVERRIDES': [],
'PAGINATED_TEMPLATES': {'index': None, 'tag': None, 'category': None,
'author': None},
'PELICAN_CLASS': 'pelican.Pelican',
'DEFAULT_DATE_FORMAT': '%a %d %B %Y',
'DATE_FORMATS': {},
@ -134,8 +147,14 @@ DEFAULT_CONFIG = {
'PLUGINS': [],
'PYGMENTS_RST_OPTIONS': {},
'TEMPLATE_PAGES': {},
'TEMPLATE_EXTENSIONS': ['.html'],
'IGNORE_FILES': ['.#*'],
'SLUG_SUBSTITUTIONS': (),
'SLUG_REGEX_SUBSTITUTIONS': [
(r'[^\w\s-]', ''), # remove non-alphabetical/whitespace/'-' chars
(r'(?u)\A\s*', ''), # strip leading whitespace
(r'(?u)\s*\Z', ''), # strip trailing whitespace
(r'[-\s]+', '-'), # reduce multiple whitespace or '-' to single '-'
],
'INTRASITE_LINK_REGEX': '[{|](?P<what>.*?)[|}]',
'SLUGIFY_SOURCE': 'title',
'CACHE_CONTENT': False,
@ -146,85 +165,70 @@ DEFAULT_CONFIG = {
'LOAD_CONTENT_CACHE': False,
'WRITE_SELECTED': [],
'FORMATTED_FIELDS': ['summary'],
'PORT': 8000,
'BIND': '',
}
PYGMENTS_RST_OPTIONS = None
def read_settings(path=None, override=None):
settings = override or {}
if path:
local_settings = get_settings_from_file(path)
# Make the paths relative to the settings file
settings = dict(get_settings_from_file(path), **settings)
if settings:
settings = handle_deprecated_settings(settings)
if path:
# Make relative paths absolute
def getabs(maybe_relative, base_path=path):
if isabs(maybe_relative):
return maybe_relative
return os.path.abspath(os.path.normpath(os.path.join(
os.path.dirname(base_path), maybe_relative)))
for p in ['PATH', 'OUTPUT_PATH', 'THEME', 'CACHE_PATH']:
if p in local_settings and local_settings[p] is not None \
and not isabs(local_settings[p]):
absp = os.path.abspath(os.path.normpath(os.path.join(
os.path.dirname(path), local_settings[p])))
if settings.get(p) is not None:
absp = getabs(settings[p])
# THEME may be a name rather than a path
if p != 'THEME' or os.path.exists(absp):
local_settings[p] = absp
settings[p] = absp
if 'PLUGIN_PATH' in local_settings:
logger.warning('PLUGIN_PATH setting has been replaced by '
'PLUGIN_PATHS, moving it to the new setting name.')
local_settings['PLUGIN_PATHS'] = local_settings['PLUGIN_PATH']
del local_settings['PLUGIN_PATH']
if 'JINJA_EXTENSIONS' in local_settings:
logger.warning('JINJA_EXTENSIONS setting has been deprecated, '
'moving it to JINJA_ENVIRONMENT setting.')
local_settings['JINJA_ENVIRONMENT']['extensions'] = \
local_settings['JINJA_EXTENSIONS']
del local_settings['JINJA_EXTENSIONS']
if isinstance(local_settings['PLUGIN_PATHS'], six.string_types):
logger.warning("Defining PLUGIN_PATHS setting as string "
"has been deprecated (should be a list)")
local_settings['PLUGIN_PATHS'] = [local_settings['PLUGIN_PATHS']]
elif local_settings['PLUGIN_PATHS'] is not None:
def getabs(path, pluginpath):
if isabs(pluginpath):
return pluginpath
else:
path_dirname = os.path.dirname(path)
path_joined = os.path.join(path_dirname, pluginpath)
path_normed = os.path.normpath(path_joined)
path_absolute = os.path.abspath(path_normed)
return path_absolute
if settings.get('PLUGIN_PATHS') is not None:
settings['PLUGIN_PATHS'] = [getabs(pluginpath)
for pluginpath
in settings['PLUGIN_PATHS']]
pluginpath_list = [getabs(path, pluginpath)
for pluginpath
in local_settings['PLUGIN_PATHS']]
local_settings['PLUGIN_PATHS'] = pluginpath_list
else:
local_settings = copy.deepcopy(DEFAULT_CONFIG)
settings = dict(copy.deepcopy(DEFAULT_CONFIG), **settings)
settings = configure_settings(settings)
if override:
local_settings.update(override)
parsed_settings = configure_settings(local_settings)
# This is because there doesn't seem to be a way to pass extra
# parameters to docutils directive handlers, so we have to have a
# variable here that we'll import from within Pygments.run (see
# rstdirectives.py) to see what the user defaults were.
global PYGMENTS_RST_OPTIONS
PYGMENTS_RST_OPTIONS = parsed_settings.get('PYGMENTS_RST_OPTIONS', None)
return parsed_settings
PYGMENTS_RST_OPTIONS = settings.get('PYGMENTS_RST_OPTIONS', None)
return settings
def get_settings_from_module(module=None, default_settings=DEFAULT_CONFIG):
def get_settings_from_module(module=None):
"""Loads settings from a module, returns a dictionary."""
context = copy.deepcopy(default_settings)
context = {}
if module is not None:
context.update(
(k, v) for k, v in inspect.getmembers(module) if k.isupper())
return context
def get_settings_from_file(path, default_settings=DEFAULT_CONFIG):
def get_settings_from_file(path):
"""Loads settings from a file path, returning a dict."""
name, ext = os.path.splitext(os.path.basename(path))
module = load_source(name, path)
return get_settings_from_module(module, default_settings=default_settings)
return get_settings_from_module(module)
def get_jinja_environment(settings):
@ -241,6 +245,149 @@ def get_jinja_environment(settings):
return settings
def handle_deprecated_settings(settings):
"""Converts deprecated settings and issues warnings. Issues an exception
if both old and new setting is specified.
"""
# PLUGIN_PATH -> PLUGIN_PATHS
if 'PLUGIN_PATH' in settings:
logger.warning('PLUGIN_PATH setting has been replaced by '
'PLUGIN_PATHS, moving it to the new setting name.')
settings['PLUGIN_PATHS'] = settings['PLUGIN_PATH']
del settings['PLUGIN_PATH']
# PLUGIN_PATHS: str -> [str]
if isinstance(settings.get('PLUGIN_PATHS'), six.string_types):
logger.warning("Defining PLUGIN_PATHS setting as string "
"has been deprecated (should be a list)")
settings['PLUGIN_PATHS'] = [settings['PLUGIN_PATHS']]
# JINJA_EXTENSIONS -> JINJA_ENVIRONMENT > extensions
if 'JINJA_EXTENSIONS' in settings:
logger.warning('JINJA_EXTENSIONS setting has been deprecated, '
'moving it to JINJA_ENVIRONMENT setting.')
settings['JINJA_ENVIRONMENT']['extensions'] = \
settings['JINJA_EXTENSIONS']
del settings['JINJA_EXTENSIONS']
# {ARTICLE,PAGE}_DIR -> {ARTICLE,PAGE}_PATHS
for key in ['ARTICLE', 'PAGE']:
old_key = key + '_DIR'
new_key = key + '_PATHS'
if old_key in settings:
logger.warning(
'Deprecated setting %s, moving it to %s list',
old_key, new_key)
settings[new_key] = [settings[old_key]] # also make a list
del settings[old_key]
# EXTRA_TEMPLATES_PATHS -> THEME_TEMPLATES_OVERRIDES
if 'EXTRA_TEMPLATES_PATHS' in settings:
logger.warning('EXTRA_TEMPLATES_PATHS is deprecated use '
'THEME_TEMPLATES_OVERRIDES instead.')
if ('THEME_TEMPLATES_OVERRIDES' in settings and
settings['THEME_TEMPLATES_OVERRIDES']):
raise Exception(
'Setting both EXTRA_TEMPLATES_PATHS and '
'THEME_TEMPLATES_OVERRIDES is not permitted. Please move to '
'only setting THEME_TEMPLATES_OVERRIDES.')
settings['THEME_TEMPLATES_OVERRIDES'] = \
settings['EXTRA_TEMPLATES_PATHS']
del settings['EXTRA_TEMPLATES_PATHS']
# MD_EXTENSIONS -> MARKDOWN
if 'MD_EXTENSIONS' in settings:
logger.warning('MD_EXTENSIONS is deprecated use MARKDOWN '
'instead. Falling back to the default.')
settings['MARKDOWN'] = DEFAULT_CONFIG['MARKDOWN']
# LESS_GENERATOR -> Webassets plugin
# FILES_TO_COPY -> STATIC_PATHS, EXTRA_PATH_METADATA
for old, new, doc in [
('LESS_GENERATOR', 'the Webassets plugin', None),
('FILES_TO_COPY', 'STATIC_PATHS and EXTRA_PATH_METADATA',
'https://github.com/getpelican/pelican/'
'blob/master/docs/settings.rst#path-metadata'),
]:
if old in settings:
message = 'The {} setting has been removed in favor of {}'.format(
old, new)
if doc:
message += ', see {} for details'.format(doc)
logger.warning(message)
# PAGINATED_DIRECT_TEMPLATES -> PAGINATED_TEMPLATES
if 'PAGINATED_DIRECT_TEMPLATES' in settings:
message = 'The {} setting has been removed in favor of {}'.format(
'PAGINATED_DIRECT_TEMPLATES', 'PAGINATED_TEMPLATES')
logger.warning(message)
for t in settings['PAGINATED_DIRECT_TEMPLATES']:
if t not in settings['PAGINATED_TEMPLATES']:
settings['PAGINATED_TEMPLATES'][t] = None
del settings['PAGINATED_DIRECT_TEMPLATES']
# {SLUG,CATEGORY,TAG,AUTHOR}_SUBSTITUTIONS ->
# {SLUG,CATEGORY,TAG,AUTHOR}_REGEX_SUBSTITUTIONS
url_settings_url = \
'http://docs.getpelican.com/en/latest/settings.html#url-settings'
flavours = {'SLUG', 'CATEGORY', 'TAG', 'AUTHOR'}
old_values = {f: settings[f + '_SUBSTITUTIONS']
for f in flavours if f + '_SUBSTITUTIONS' in settings}
new_values = {f: settings[f + '_REGEX_SUBSTITUTIONS']
for f in flavours if f + '_REGEX_SUBSTITUTIONS' in settings}
if old_values and new_values:
raise Exception(
'Setting both {new_key} and {old_key} (or variants thereof) is '
'not permitted. Please move to only setting {new_key}.'
.format(old_key='SLUG_SUBSTITUTIONS',
new_key='SLUG_REGEX_SUBSTITUTIONS'))
if old_values:
message = ('{} and variants thereof are deprecated and will be '
'removed in the future. Please use {} and variants thereof '
'instead. Check {}.'
.format('SLUG_SUBSTITUTIONS', 'SLUG_REGEX_SUBSTITUTIONS',
url_settings_url))
logger.warning(message)
if old_values.get('SLUG'):
for f in {'CATEGORY', 'TAG'}:
if old_values.get(f):
old_values[f] = old_values['SLUG'] + old_values[f]
old_values['AUTHOR'] = old_values.get('AUTHOR', [])
for f in flavours:
if old_values.get(f) is not None:
regex_subs = []
# by default will replace non-alphanum characters
replace = True
for tpl in old_values[f]:
try:
src, dst, skip = tpl
if skip:
replace = False
except ValueError:
src, dst = tpl
regex_subs.append(
(re.escape(src), dst.replace('\\', r'\\')))
if replace:
regex_subs += [
(r'[^\w\s-]', ''),
(r'(?u)\A\s*', ''),
(r'(?u)\s*\Z', ''),
(r'[-\s]+', '-'),
]
else:
regex_subs += [
(r'(?u)\A\s*', ''),
(r'(?u)\s*\Z', ''),
]
settings[f + '_REGEX_SUBSTITUTIONS'] = regex_subs
settings.pop(f + '_SUBSTITUTIONS', None)
return settings
def configure_settings(settings):
"""Provide optimizations, error checking, and warnings for the given
settings.
@ -365,23 +512,12 @@ def configure_settings(settings):
key=lambda r: r[0],
)
# move {ARTICLE,PAGE}_DIR -> {ARTICLE,PAGE}_PATHS
for key in ['ARTICLE', 'PAGE']:
old_key = key + '_DIR'
new_key = key + '_PATHS'
if old_key in settings:
logger.warning(
'Deprecated setting %s, moving it to %s list',
old_key, new_key)
settings[new_key] = [settings[old_key]] # also make a list
del settings[old_key]
# Save people from accidentally setting a string rather than a list
path_keys = (
'ARTICLE_EXCLUDES',
'DEFAULT_METADATA',
'DIRECT_TEMPLATES',
'EXTRA_TEMPLATES_PATHS',
'THEME_TEMPLATES_OVERRIDES',
'FILES_TO_COPY',
'IGNORE_FILES',
'PAGINATED_DIRECT_TEMPLATES',
@ -399,12 +535,6 @@ def configure_settings(settings):
PATH_KEY)
settings[PATH_KEY] = DEFAULT_CONFIG[PATH_KEY]
# Deprecated warning of MD_EXTENSIONS
if 'MD_EXTENSIONS' in settings:
logger.warning('MD_EXTENSIONS is deprecated use MARKDOWN '
'instead. Falling back to the default.')
settings['MARKDOWN'] = DEFAULT_CONFIG['MARKDOWN']
# Add {PAGE,ARTICLE}_PATHS to {ARTICLE,PAGE}_EXCLUDES
mutually_exclusive = ('ARTICLE', 'PAGE')
for type_1, type_2 in [mutually_exclusive, mutually_exclusive[::-1]]:
@ -417,17 +547,4 @@ def configure_settings(settings):
except KeyError:
continue # setting not specified, nothing to do
for old, new, doc in [
('LESS_GENERATOR', 'the Webassets plugin', None),
('FILES_TO_COPY', 'STATIC_PATHS and EXTRA_PATH_METADATA',
'https://github.com/getpelican/pelican/'
'blob/master/docs/settings.rst#path-metadata'),
]:
if old in settings:
message = 'The {} setting has been removed in favor of {}'.format(
old, new)
if doc:
message += ', see {} for details'.format(doc)
logger.warning(message)
return settings

View file

@ -27,6 +27,7 @@ article_writer_finalized = signal('article_writer_finalized')
page_generator_init = signal('page_generator_init')
page_generator_finalized = signal('page_generator_finalized')
page_generator_write_page = signal('page_generator_write_page')
page_writer_finalized = signal('page_writer_finalized')
static_generator_init = signal('static_generator_init')

View file

@ -0,0 +1,8 @@
This is a test draft page
##########################
:status: draft
The quick brown fox .
This page is a draft.

View file

@ -0,0 +1,12 @@
title: This is a markdown test draft page
status: draft
Test Markdown File Header
=========================
Used for pelican test
---------------------
The quick brown fox .
This page is a draft

View file

@ -0,0 +1,11 @@
This is a test draft page with a custom template
#################################################
:status: draft
:template: custom
The quick brown fox .
This page is a draft
This page has a custom template to be called when rendered

1067
pelican/tests/content/bloggerexport.xml vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -554,7 +554,11 @@ Pelicans are supposed to eat fish, damn it!
<iframe width="420" height="315" src="http://www.youtube.com/embed/QNNl_uWmQXE" frameborder="0" allowfullscreen></iframe>
Bottom line: don't mess up with birds]]></content:encoded>
Bottom line: don't mess up with birds
"That's a 'wonderful' shoe."
“Thats a magic sock.”]]></content:encoded>
<excerpt:encoded><![CDATA[]]></excerpt:encoded>
<wp:post_id>173</wp:post_id>
<wp:post_date>2012-02-16 15:52:55</wp:post_date>

View file

@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<title>A Pelican Blog</title>
<title>A Pelican Blog - Categories</title>
<link rel="stylesheet" href="/theme/css/main.css" />
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
</head>
@ -20,12 +20,13 @@
<li><a href="/category/yeah.html">yeah</a></li>
</ul></nav>
</header><!-- /#banner -->
<ul>
<li><a href="/category/bar.html">bar</a></li>
<li><a href="/category/cat1.html">cat1</a></li>
<li><a href="/category/misc.html">misc</a></li>
<li><a href="/category/yeah.html">yeah</a></li>
</ul>
<h1>Categories on A Pelican Blog</h1>
<ul>
<li><a href="/category/bar.html">bar</a> (1)</li>
<li><a href="/category/cat1.html">cat1</a> (4)</li>
<li><a href="/category/misc.html">misc</a> (4)</li>
<li><a href="/category/yeah.html">yeah</a> (1)</li>
</ul>
<section id="extras" class="body">
<div class="social">
<h2>social</h2>

View file

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en">
<html lang="fr">
<head>
<meta charset="utf-8" />
<title>Deuxième article</title>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 751 B

After

Width:  |  Height:  |  Size: 411 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 958 B

After

Width:  |  Height:  |  Size: 827 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 B

After

Width:  |  Height:  |  Size: 150 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 606 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 B

After

Width:  |  Height:  |  Size: 223 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 B

After

Width:  |  Height:  |  Size: 402 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 803 B

After

Width:  |  Height:  |  Size: 420 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 527 B

After

Width:  |  Height:  |  Size: 511 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 975 B

After

Width:  |  Height:  |  Size: 840 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 896 B

After

Width:  |  Height:  |  Size: 625 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 693 B

After

Width:  |  Height:  |  Size: 458 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 879 B

After

Width:  |  Height:  |  Size: 751 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 535 B

After

Width:  |  Height:  |  Size: 435 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 580 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 916 B

After

Width:  |  Height:  |  Size: 414 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 416 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 B

After

Width:  |  Height:  |  Size: 349 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 458 B

After

Width:  |  Height:  |  Size: 316 B

Before After
Before After

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="./">Alexis' log </a></h1>
<h1><a href="./">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
<li><a href="./override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="./">Alexis' log </a></h1>
<h1><a href="./">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
<li><a href="./override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="./">Alexis' log </a></h1>
<h1><a href="./">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
<li><a href="./override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="./">Alexis' log </a></h1>
<h1><a href="./">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
<li><a href="./override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="./">Alexis' log </a></h1>
<h1><a href="./">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
<li><a href="./override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="../">Alexis' log </a></h1>
<h1><a href="../">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="../tag/oh.html">Oh Oh Oh</a></li>
<li><a href="../override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="../">Alexis' log </a></h1>
<h1><a href="../">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="../tag/oh.html">Oh Oh Oh</a></li>
<li><a href="../override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="../">Alexis' log </a></h1>
<h1><a href="../">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="../tag/oh.html">Oh Oh Oh</a></li>
<li><a href="../override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="./">Alexis' log </a></h1>
<h1><a href="./">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
<li><a href="./override/">Override url/save_as</a></li>

View file

@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Alexis' log</title>
<title>Alexis' log - Categories</title>
<link rel="stylesheet" href="./theme/css/main.css" />
<link href="http://blog.notmyidea.org/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="Alexis' log Atom Feed" />
<link href="http://blog.notmyidea.org/feeds/all.rss.xml" type="application/rss+xml" rel="alternate" title="Alexis' log RSS Feed" />
@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="./">Alexis' log </a></h1>
<h1><a href="./">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
<li><a href="./override/">Override url/save_as</a></li>
@ -24,12 +24,13 @@
<li><a href="./category/bar.html">bar</a></li>
</ul></nav>
</header><!-- /#banner -->
<ul>
<li><a href="./category/yeah.html">yeah</a></li>
<li><a href="./category/misc.html">misc</a></li>
<li><a href="./category/cat1.html">cat1</a></li>
<li><a href="./category/bar.html">bar</a></li>
</ul>
<h1>Categories on Alexis' log</h1>
<ul>
<li><a href="./category/bar.html">bar</a> (1)</li>
<li><a href="./category/cat1.html">cat1</a> (4)</li>
<li><a href="./category/misc.html">misc</a> (4)</li>
<li><a href="./category/yeah.html">yeah</a> (1)</li>
</ul>
<section id="extras" class="body">
<div class="blogroll">
<h2>links</h2>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="../">Alexis' log </a></h1>
<h1><a href="../">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="../tag/oh.html">Oh Oh Oh</a></li>
<li><a href="../override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="../">Alexis' log </a></h1>
<h1><a href="../">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="../tag/oh.html">Oh Oh Oh</a></li>
<li><a href="../override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="../">Alexis' log </a></h1>
<h1><a href="../">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="../tag/oh.html">Oh Oh Oh</a></li>
<li><a href="../override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="../">Alexis' log </a></h1>
<h1><a href="../">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="../tag/oh.html">Oh Oh Oh</a></li>
<li><a href="../override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="../">Alexis' log </a></h1>
<h1><a href="../">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="../tag/oh.html">Oh Oh Oh</a></li>
<li><a href="../override/">Override url/save_as</a></li>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Alexis' log - Alexis Métaireau</title><link href="http://blog.notmyidea.org/" rel="alternate"></link><link href="http://blog.notmyidea.org/feeds/alexis-metaireau.atom.xml" rel="self"></link><id>http://blog.notmyidea.org/</id><updated>2013-11-17T23:29:00+01:00</updated><entry><title>FILENAME_METADATA example</title><link href="http://blog.notmyidea.org/filename_metadata-example.html" rel="alternate"></link><published>2012-11-30T00:00:00+01:00</published><updated>2012-11-30T00:00:00+01:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html</id><summary type="html">&lt;p&gt;Some cool stuff!&lt;/p&gt;
<feed xmlns="http://www.w3.org/2005/Atom"><title>Alexis' log - Alexis Métaireau</title><link href="http://blog.notmyidea.org/" rel="alternate"></link><link href="http://blog.notmyidea.org/feeds/alexis-metaireau.atom.xml" rel="self"></link><id>http://blog.notmyidea.org/</id><updated>2013-11-17T23:29:00+01:00</updated><subtitle>A personal blog.</subtitle><entry><title>FILENAME_METADATA example</title><link href="http://blog.notmyidea.org/filename_metadata-example.html" rel="alternate"></link><published>2012-11-30T00:00:00+01:00</published><updated>2012-11-30T00:00:00+01:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html</id><summary type="html">&lt;p&gt;Some cool stuff!&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Some cool stuff!&lt;/p&gt;
</content></entry><entry><title>Second article</title><link href="http://blog.notmyidea.org/second-article.html" rel="alternate"></link><published>2012-02-29T00:00:00+01:00</published><updated>2012-02-29T00:00:00+01:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2012-02-29:/second-article.html</id><summary type="html">&lt;p&gt;This is some article, in english&lt;/p&gt;
</summary><content type="html">&lt;p&gt;This is some article, in english&lt;/p&gt;

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>Alexis' log - Alexis Métaireau</title><link>http://blog.notmyidea.org/</link><description></description><lastBuildDate>Sun, 17 Nov 2013 23:29:00 +0100</lastBuildDate><item><title>FILENAME_METADATA example</title><link>http://blog.notmyidea.org/filename_metadata-example.html</link><description>&lt;p&gt;Some cool stuff!&lt;/p&gt;
<rss version="2.0"><channel><title>Alexis' log - Alexis Métaireau</title><link>http://blog.notmyidea.org/</link><description>A personal blog.</description><lastBuildDate>Sun, 17 Nov 2013 23:29:00 +0100</lastBuildDate><item><title>FILENAME_METADATA example</title><link>http://blog.notmyidea.org/filename_metadata-example.html</link><description>&lt;p&gt;Some cool stuff!&lt;/p&gt;
</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Alexis Métaireau</dc:creator><pubDate>Fri, 30 Nov 2012 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html</guid></item><item><title>Second article</title><link>http://blog.notmyidea.org/second-article.html</link><description>&lt;p&gt;This is some article, in english&lt;/p&gt;
</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Alexis Métaireau</dc:creator><pubDate>Wed, 29 Feb 2012 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:blog.notmyidea.org,2012-02-29:/second-article.html</guid><category>foo</category><category>bar</category><category>baz</category></item><item><title>A markdown powered article</title><link>http://blog.notmyidea.org/a-markdown-powered-article.html</link><description>&lt;p&gt;You're mutually oblivious.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blog.notmyidea.org/unbelievable.html"&gt;a root-relative link to unbelievable&lt;/a&gt;

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Alexis' log</title><link href="http://blog.notmyidea.org/" rel="alternate"></link><link href="http://blog.notmyidea.org/feeds/all-en.atom.xml" rel="self"></link><id>http://blog.notmyidea.org/</id><updated>2013-11-17T23:29:00+01:00</updated><entry><title>FILENAME_METADATA example</title><link href="http://blog.notmyidea.org/filename_metadata-example.html" rel="alternate"></link><published>2012-11-30T00:00:00+01:00</published><updated>2012-11-30T00:00:00+01:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html</id><summary type="html">&lt;p&gt;Some cool stuff!&lt;/p&gt;
<feed xmlns="http://www.w3.org/2005/Atom"><title>Alexis' log</title><link href="http://blog.notmyidea.org/" rel="alternate"></link><link href="http://blog.notmyidea.org/feeds/all-en.atom.xml" rel="self"></link><id>http://blog.notmyidea.org/</id><updated>2013-11-17T23:29:00+01:00</updated><subtitle>A personal blog.</subtitle><entry><title>FILENAME_METADATA example</title><link href="http://blog.notmyidea.org/filename_metadata-example.html" rel="alternate"></link><published>2012-11-30T00:00:00+01:00</published><updated>2012-11-30T00:00:00+01:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html</id><summary type="html">&lt;p&gt;Some cool stuff!&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Some cool stuff!&lt;/p&gt;
</content></entry><entry><title>Second article</title><link href="http://blog.notmyidea.org/second-article.html" rel="alternate"></link><published>2012-02-29T00:00:00+01:00</published><updated>2012-02-29T00:00:00+01:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2012-02-29:/second-article.html</id><summary type="html">&lt;p&gt;This is some article, in english&lt;/p&gt;
</summary><content type="html">&lt;p&gt;This is some article, in english&lt;/p&gt;

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Alexis' log</title><link href="http://blog.notmyidea.org/" rel="alternate"></link><link href="http://blog.notmyidea.org/feeds/all-fr.atom.xml" rel="self"></link><id>http://blog.notmyidea.org/</id><updated>2012-03-02T14:01:01+01:00</updated><entry><title>Trop bien !</title><link href="http://blog.notmyidea.org/oh-yeah-fr.html" rel="alternate"></link><published>2012-03-02T14:01:01+01:00</published><updated>2012-03-02T14:01:01+01:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2012-03-02:/oh-yeah-fr.html</id><summary type="html">&lt;p&gt;Et voila du contenu en français&lt;/p&gt;
<feed xmlns="http://www.w3.org/2005/Atom"><title>Alexis' log</title><link href="http://blog.notmyidea.org/" rel="alternate"></link><link href="http://blog.notmyidea.org/feeds/all-fr.atom.xml" rel="self"></link><id>http://blog.notmyidea.org/</id><updated>2012-03-02T14:01:01+01:00</updated><subtitle>A personal blog.</subtitle><entry><title>Trop bien !</title><link href="http://blog.notmyidea.org/oh-yeah-fr.html" rel="alternate"></link><published>2012-03-02T14:01:01+01:00</published><updated>2012-03-02T14:01:01+01:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2012-03-02:/oh-yeah-fr.html</id><summary type="html">&lt;p&gt;Et voila du contenu en français&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Et voila du contenu en français&lt;/p&gt;
</content></entry><entry><title>Deuxième article</title><link href="http://blog.notmyidea.org/second-article-fr.html" rel="alternate"></link><published>2012-02-29T00:00:00+01:00</published><updated>2012-02-29T00:00:00+01:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2012-02-29:/second-article-fr.html</id><summary type="html">&lt;p&gt;Ceci est un article, en français.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Ceci est un article, en français.&lt;/p&gt;

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Alexis' log</title><link href="http://blog.notmyidea.org/" rel="alternate"></link><link href="http://blog.notmyidea.org/feeds/all.atom.xml" rel="self"></link><id>http://blog.notmyidea.org/</id><updated>2013-11-17T23:29:00+01:00</updated><entry><title>FILENAME_METADATA example</title><link href="http://blog.notmyidea.org/filename_metadata-example.html" rel="alternate"></link><published>2012-11-30T00:00:00+01:00</published><updated>2012-11-30T00:00:00+01:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html</id><summary type="html">&lt;p&gt;Some cool stuff!&lt;/p&gt;
<feed xmlns="http://www.w3.org/2005/Atom"><title>Alexis' log</title><link href="http://blog.notmyidea.org/" rel="alternate"></link><link href="http://blog.notmyidea.org/feeds/all.atom.xml" rel="self"></link><id>http://blog.notmyidea.org/</id><updated>2013-11-17T23:29:00+01:00</updated><subtitle>A personal blog.</subtitle><entry><title>FILENAME_METADATA example</title><link href="http://blog.notmyidea.org/filename_metadata-example.html" rel="alternate"></link><published>2012-11-30T00:00:00+01:00</published><updated>2012-11-30T00:00:00+01:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html</id><summary type="html">&lt;p&gt;Some cool stuff!&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Some cool stuff!&lt;/p&gt;
</content></entry><entry><title>Trop bien !</title><link href="http://blog.notmyidea.org/oh-yeah-fr.html" rel="alternate"></link><published>2012-03-02T14:01:01+01:00</published><updated>2012-03-02T14:01:01+01:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2012-03-02:/oh-yeah-fr.html</id><summary type="html">&lt;p&gt;Et voila du contenu en français&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Et voila du contenu en français&lt;/p&gt;

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>Alexis' log</title><link>http://blog.notmyidea.org/</link><description></description><lastBuildDate>Sun, 17 Nov 2013 23:29:00 +0100</lastBuildDate><item><title>FILENAME_METADATA example</title><link>http://blog.notmyidea.org/filename_metadata-example.html</link><description>&lt;p&gt;Some cool stuff!&lt;/p&gt;
<rss version="2.0"><channel><title>Alexis' log</title><link>http://blog.notmyidea.org/</link><description>A personal blog.</description><lastBuildDate>Sun, 17 Nov 2013 23:29:00 +0100</lastBuildDate><item><title>FILENAME_METADATA example</title><link>http://blog.notmyidea.org/filename_metadata-example.html</link><description>&lt;p&gt;Some cool stuff!&lt;/p&gt;
</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Alexis Métaireau</dc:creator><pubDate>Fri, 30 Nov 2012 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html</guid></item><item><title>Trop bien !</title><link>http://blog.notmyidea.org/oh-yeah-fr.html</link><description>&lt;p&gt;Et voila du contenu en français&lt;/p&gt;
</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Alexis Métaireau</dc:creator><pubDate>Fri, 02 Mar 2012 14:01:01 +0100</pubDate><guid isPermaLink="false">tag:blog.notmyidea.org,2012-03-02:/oh-yeah-fr.html</guid></item><item><title>Second article</title><link>http://blog.notmyidea.org/second-article.html</link><description>&lt;p&gt;This is some article, in english&lt;/p&gt;
</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Alexis Métaireau</dc:creator><pubDate>Wed, 29 Feb 2012 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:blog.notmyidea.org,2012-02-29:/second-article.html</guid><category>foo</category><category>bar</category><category>baz</category></item><item><title>Deuxième article</title><link>http://blog.notmyidea.org/second-article-fr.html</link><description>&lt;p&gt;Ceci est un article, en français.&lt;/p&gt;

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Alexis' log - bar</title><link href="http://blog.notmyidea.org/" rel="alternate"></link><link href="http://blog.notmyidea.org/feeds/bar.atom.xml" rel="self"></link><id>http://blog.notmyidea.org/</id><updated>2010-10-20T10:14:00+02:00</updated><entry><title>Oh yeah !</title><link href="http://blog.notmyidea.org/oh-yeah.html" rel="alternate"></link><published>2010-10-20T10:14:00+02:00</published><updated>2010-10-20T10:14:00+02:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2010-10-20:/oh-yeah.html</id><summary type="html">&lt;div class="section" id="why-not"&gt;
<feed xmlns="http://www.w3.org/2005/Atom"><title>Alexis' log - bar</title><link href="http://blog.notmyidea.org/" rel="alternate"></link><link href="http://blog.notmyidea.org/feeds/bar.atom.xml" rel="self"></link><id>http://blog.notmyidea.org/</id><updated>2010-10-20T10:14:00+02:00</updated><subtitle>A personal blog.</subtitle><entry><title>Oh yeah !</title><link href="http://blog.notmyidea.org/oh-yeah.html" rel="alternate"></link><published>2010-10-20T10:14:00+02:00</published><updated>2010-10-20T10:14:00+02:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2010-10-20:/oh-yeah.html</id><summary type="html">&lt;div class="section" id="why-not"&gt;
&lt;h2&gt;Why not ?&lt;/h2&gt;
&lt;p&gt;After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !&lt;/p&gt;

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>Alexis' log - bar</title><link>http://blog.notmyidea.org/</link><description></description><lastBuildDate>Wed, 20 Oct 2010 10:14:00 +0200</lastBuildDate><item><title>Oh yeah !</title><link>http://blog.notmyidea.org/oh-yeah.html</link><description>&lt;div class="section" id="why-not"&gt;
<rss version="2.0"><channel><title>Alexis' log - bar</title><link>http://blog.notmyidea.org/</link><description>A personal blog.</description><lastBuildDate>Wed, 20 Oct 2010 10:14:00 +0200</lastBuildDate><item><title>Oh yeah !</title><link>http://blog.notmyidea.org/oh-yeah.html</link><description>&lt;div class="section" id="why-not"&gt;
&lt;h2&gt;Why not ?&lt;/h2&gt;
&lt;p&gt;After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !&lt;/p&gt;

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Alexis' log - cat1</title><link href="http://blog.notmyidea.org/" rel="alternate"></link><link href="http://blog.notmyidea.org/feeds/cat1.atom.xml" rel="self"></link><id>http://blog.notmyidea.org/</id><updated>2011-04-20T00:00:00+02:00</updated><entry><title>A markdown powered article</title><link href="http://blog.notmyidea.org/a-markdown-powered-article.html" rel="alternate"></link><published>2011-04-20T00:00:00+02:00</published><updated>2011-04-20T00:00:00+02:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2011-04-20:/a-markdown-powered-article.html</id><summary type="html">&lt;p&gt;You're mutually oblivious.&lt;/p&gt;
<feed xmlns="http://www.w3.org/2005/Atom"><title>Alexis' log - cat1</title><link href="http://blog.notmyidea.org/" rel="alternate"></link><link href="http://blog.notmyidea.org/feeds/cat1.atom.xml" rel="self"></link><id>http://blog.notmyidea.org/</id><updated>2011-04-20T00:00:00+02:00</updated><subtitle>A personal blog.</subtitle><entry><title>A markdown powered article</title><link href="http://blog.notmyidea.org/a-markdown-powered-article.html" rel="alternate"></link><published>2011-04-20T00:00:00+02:00</published><updated>2011-04-20T00:00:00+02:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2011-04-20:/a-markdown-powered-article.html</id><summary type="html">&lt;p&gt;You're mutually oblivious.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blog.notmyidea.org/unbelievable.html"&gt;a root-relative link to unbelievable&lt;/a&gt;
&lt;a href="http://blog.notmyidea.org/unbelievable.html"&gt;a file-relative link to unbelievable&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;You're mutually oblivious.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blog.notmyidea.org/unbelievable.html"&gt;a root-relative link to unbelievable&lt;/a&gt;

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>Alexis' log - cat1</title><link>http://blog.notmyidea.org/</link><description></description><lastBuildDate>Wed, 20 Apr 2011 00:00:00 +0200</lastBuildDate><item><title>A markdown powered article</title><link>http://blog.notmyidea.org/a-markdown-powered-article.html</link><description>&lt;p&gt;You're mutually oblivious.&lt;/p&gt;
<rss version="2.0"><channel><title>Alexis' log - cat1</title><link>http://blog.notmyidea.org/</link><description>A personal blog.</description><lastBuildDate>Wed, 20 Apr 2011 00:00:00 +0200</lastBuildDate><item><title>A markdown powered article</title><link>http://blog.notmyidea.org/a-markdown-powered-article.html</link><description>&lt;p&gt;You're mutually oblivious.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blog.notmyidea.org/unbelievable.html"&gt;a root-relative link to unbelievable&lt;/a&gt;
&lt;a href="http://blog.notmyidea.org/unbelievable.html"&gt;a file-relative link to unbelievable&lt;/a&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Alexis Métaireau</dc:creator><pubDate>Wed, 20 Apr 2011 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:blog.notmyidea.org,2011-04-20:/a-markdown-powered-article.html</guid></item><item><title>Article 1</title><link>http://blog.notmyidea.org/article-1.html</link><description>&lt;p&gt;Article 1&lt;/p&gt;
</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Alexis Métaireau</dc:creator><pubDate>Thu, 17 Feb 2011 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:blog.notmyidea.org,2011-02-17:/article-1.html</guid></item><item><title>Article 2</title><link>http://blog.notmyidea.org/article-2.html</link><description>&lt;p&gt;Article 2&lt;/p&gt;

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Alexis' log - misc</title><link href="http://blog.notmyidea.org/" rel="alternate"></link><link href="http://blog.notmyidea.org/feeds/misc.atom.xml" rel="self"></link><id>http://blog.notmyidea.org/</id><updated>2012-11-30T00:00:00+01:00</updated><entry><title>FILENAME_METADATA example</title><link href="http://blog.notmyidea.org/filename_metadata-example.html" rel="alternate"></link><published>2012-11-30T00:00:00+01:00</published><updated>2012-11-30T00:00:00+01:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html</id><summary type="html">&lt;p&gt;Some cool stuff!&lt;/p&gt;
<feed xmlns="http://www.w3.org/2005/Atom"><title>Alexis' log - misc</title><link href="http://blog.notmyidea.org/" rel="alternate"></link><link href="http://blog.notmyidea.org/feeds/misc.atom.xml" rel="self"></link><id>http://blog.notmyidea.org/</id><updated>2012-11-30T00:00:00+01:00</updated><subtitle>A personal blog.</subtitle><entry><title>FILENAME_METADATA example</title><link href="http://blog.notmyidea.org/filename_metadata-example.html" rel="alternate"></link><published>2012-11-30T00:00:00+01:00</published><updated>2012-11-30T00:00:00+01:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html</id><summary type="html">&lt;p&gt;Some cool stuff!&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Some cool stuff!&lt;/p&gt;
</content></entry><entry><title>Second article</title><link href="http://blog.notmyidea.org/second-article.html" rel="alternate"></link><published>2012-02-29T00:00:00+01:00</published><updated>2012-02-29T00:00:00+01:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2012-02-29:/second-article.html</id><summary type="html">&lt;p&gt;This is some article, in english&lt;/p&gt;
</summary><content type="html">&lt;p&gt;This is some article, in english&lt;/p&gt;

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>Alexis' log - misc</title><link>http://blog.notmyidea.org/</link><description></description><lastBuildDate>Fri, 30 Nov 2012 00:00:00 +0100</lastBuildDate><item><title>FILENAME_METADATA example</title><link>http://blog.notmyidea.org/filename_metadata-example.html</link><description>&lt;p&gt;Some cool stuff!&lt;/p&gt;
<rss version="2.0"><channel><title>Alexis' log - misc</title><link>http://blog.notmyidea.org/</link><description>A personal blog.</description><lastBuildDate>Fri, 30 Nov 2012 00:00:00 +0100</lastBuildDate><item><title>FILENAME_METADATA example</title><link>http://blog.notmyidea.org/filename_metadata-example.html</link><description>&lt;p&gt;Some cool stuff!&lt;/p&gt;
</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Alexis Métaireau</dc:creator><pubDate>Fri, 30 Nov 2012 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:blog.notmyidea.org,2012-11-30:/filename_metadata-example.html</guid></item><item><title>Second article</title><link>http://blog.notmyidea.org/second-article.html</link><description>&lt;p&gt;This is some article, in english&lt;/p&gt;
</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Alexis Métaireau</dc:creator><pubDate>Wed, 29 Feb 2012 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:blog.notmyidea.org,2012-02-29:/second-article.html</guid><category>foo</category><category>bar</category><category>baz</category></item><item><title>Unbelievable !</title><link>http://blog.notmyidea.org/unbelievable.html</link><description>&lt;p&gt;Or completely awesome. Depends the needs.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html"&gt;a root-relative link to markdown-article&lt;/a&gt;

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Alexis' log - yeah</title><link href="http://blog.notmyidea.org/" rel="alternate"></link><link href="http://blog.notmyidea.org/feeds/yeah.atom.xml" rel="self"></link><id>http://blog.notmyidea.org/</id><updated>2013-11-17T23:29:00+01:00</updated><entry><title>This is a super article !</title><link href="http://blog.notmyidea.org/this-is-a-super-article.html" rel="alternate"></link><published>2010-12-02T10:14:00+01:00</published><updated>2013-11-17T23:29:00+01:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2010-12-02:/this-is-a-super-article.html</id><summary type="html">&lt;p class="first last"&gt;Multi-line metadata should be supported
<feed xmlns="http://www.w3.org/2005/Atom"><title>Alexis' log - yeah</title><link href="http://blog.notmyidea.org/" rel="alternate"></link><link href="http://blog.notmyidea.org/feeds/yeah.atom.xml" rel="self"></link><id>http://blog.notmyidea.org/</id><updated>2013-11-17T23:29:00+01:00</updated><subtitle>A personal blog.</subtitle><entry><title>This is a super article !</title><link href="http://blog.notmyidea.org/this-is-a-super-article.html" rel="alternate"></link><published>2010-12-02T10:14:00+01:00</published><updated>2013-11-17T23:29:00+01:00</updated><author><name>Alexis Métaireau</name></author><id>tag:blog.notmyidea.org,2010-12-02:/this-is-a-super-article.html</id><summary type="html">&lt;p class="first last"&gt;Multi-line metadata should be supported
as well as &lt;strong&gt;inline markup&lt;/strong&gt;.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Some content here !&lt;/p&gt;
&lt;div class="section" id="this-is-a-simple-title"&gt;

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>Alexis' log - yeah</title><link>http://blog.notmyidea.org/</link><description></description><lastBuildDate>Sun, 17 Nov 2013 23:29:00 +0100</lastBuildDate><item><title>This is a super article !</title><link>http://blog.notmyidea.org/this-is-a-super-article.html</link><description>&lt;p class="first last"&gt;Multi-line metadata should be supported
<rss version="2.0"><channel><title>Alexis' log - yeah</title><link>http://blog.notmyidea.org/</link><description>A personal blog.</description><lastBuildDate>Sun, 17 Nov 2013 23:29:00 +0100</lastBuildDate><item><title>This is a super article !</title><link>http://blog.notmyidea.org/this-is-a-super-article.html</link><description>&lt;p class="first last"&gt;Multi-line metadata should be supported
as well as &lt;strong&gt;inline markup&lt;/strong&gt;.&lt;/p&gt;
</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Alexis Métaireau</dc:creator><pubDate>Thu, 02 Dec 2010 10:14:00 +0100</pubDate><guid isPermaLink="false">tag:blog.notmyidea.org,2010-12-02:/this-is-a-super-article.html</guid><category>foo</category><category>bar</category><category>foobar</category></item></channel></rss>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="./">Alexis' log </a></h1>
<h1><a href="./">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
<li><a href="./override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="./">Alexis' log </a></h1>
<h1><a href="./">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
<li><a href="./override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="./">Alexis' log </a></h1>
<h1><a href="./">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
<li><a href="./override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="./">Alexis' log </a></h1>
<h1><a href="./">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
<li><a href="./override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="./">Alexis' log </a></h1>
<h1><a href="./">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
<li><a href="./override/">Override url/save_as</a></li>

View file

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en">
<html lang="fr">
<head>
<meta charset="utf-8" />
<title>Trop bien !</title>
@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="./">Alexis' log </a></h1>
<h1><a href="./">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
<li><a href="./override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="./">Alexis' log </a></h1>
<h1><a href="./">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
<li><a href="./override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="../">Alexis' log </a></h1>
<h1><a href="../">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="../tag/oh.html">Oh Oh Oh</a></li>
<li class="active"><a href="../override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="../">Alexis' log </a></h1>
<h1><a href="../">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="../tag/oh.html">Oh Oh Oh</a></li>
<li><a href="../override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="../">Alexis' log </a></h1>
<h1><a href="../">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="../tag/oh.html">Oh Oh Oh</a></li>
<li><a href="../override/">Override url/save_as</a></li>

View file

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en">
<html lang="fr">
<head>
<meta charset="utf-8" />
<title>Deuxième article</title>
@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="./">Alexis' log </a></h1>
<h1><a href="./">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
<li><a href="./override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="./">Alexis' log </a></h1>
<h1><a href="./">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
<li><a href="./override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="../">Alexis' log </a></h1>
<h1><a href="../">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="../tag/oh.html">Oh Oh Oh</a></li>
<li><a href="../override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="../">Alexis' log </a></h1>
<h1><a href="../">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="../tag/oh.html">Oh Oh Oh</a></li>
<li><a href="../override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="../">Alexis' log </a></h1>
<h1><a href="../">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="../tag/oh.html">Oh Oh Oh</a></li>
<li><a href="../override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="../">Alexis' log </a></h1>
<h1><a href="../">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="../tag/oh.html">Oh Oh Oh</a></li>
<li><a href="../override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="../">Alexis' log </a></h1>
<h1><a href="../">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li class="active"><a href="../tag/oh.html">Oh Oh Oh</a></li>
<li><a href="../override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="../">Alexis' log </a></h1>
<h1><a href="../">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="../tag/oh.html">Oh Oh Oh</a></li>
<li><a href="../override/">Override url/save_as</a></li>

View file

@ -13,7 +13,7 @@
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
</a>
<header id="banner" class="body">
<h1><a href="./">Alexis' log </a></h1>
<h1><a href="./">Alexis' log <strong>A personal blog.</strong></a></h1>
<nav><ul>
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
<li><a href="./override/">Override url/save_as</a></li>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 751 B

After

Width:  |  Height:  |  Size: 411 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 958 B

After

Width:  |  Height:  |  Size: 827 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 B

After

Width:  |  Height:  |  Size: 150 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 606 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 B

After

Width:  |  Height:  |  Size: 223 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 B

After

Width:  |  Height:  |  Size: 402 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 803 B

After

Width:  |  Height:  |  Size: 420 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 527 B

After

Width:  |  Height:  |  Size: 511 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 975 B

After

Width:  |  Height:  |  Size: 840 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 896 B

After

Width:  |  Height:  |  Size: 625 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 693 B

After

Width:  |  Height:  |  Size: 458 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 879 B

After

Width:  |  Height:  |  Size: 751 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 535 B

After

Width:  |  Height:  |  Size: 435 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 580 B

Before After
Before After

Some files were not shown because too many files have changed in this diff Show more