Skip to content
Permalink
Browse files
Merge pull request #3067 from getnikola/atom-one-file
Use one file for Atom feeds
  • Loading branch information
Kwpolska committed May 2, 2018
2 parents 81a3aef + d2ee193 commit 8a71bee3e215ae201eff3830476e382731b8f95f
@@ -15,10 +15,15 @@ Important compatibility changes
* RSS feeds might have changed their places due to ``RSS_PATH``
behavior changes (you may need to change ``RSS_PATH``,
``RSS_FILENAME_BASE``)
* Atom feeds for archives and Atom pagination are no longer supported
(Issue #3016)

Features
--------

* Add ``DISABLE_MAIN_ATOM_FEED`` setting (Issue #3016, Issue #3039)
* Add ``ATOM_FILENAME_BASE`` setting (defaults to ``index`` for
existing sites, but ``feed`` for new sites) (Issue #3016)
* Tags ``draft``, ``private`` and ``mathjax`` are no longer treated
special if ``USE_TAG_METADATA`` is set to ``False`` (default for
new sites) (Issue #2761)
@@ -79,6 +84,8 @@ Features
Bugfixes
--------

* Always follow ``FEED_LENGTH`` for Atom feeds
* Apply filters to all Atom feeds
* Read file metadata if compiler metadata exists and prefer it over
compiler metadata (Issue #3008)
* Rename ``DISABLE_INDEXES_PLUGIN_INDEX_AND_ATOM_FEED`` to ``DISABLE_INDEXES``
@@ -143,6 +150,7 @@ Removed features
* Removed taxonomy option ``also_create_classifications_from_other_languages``
(Issue #2785)
* Removed old 7-line metadata format (Issue #2839)
* Atom feeds are now limited to one page (Issue #3016)

New in v7.8.8
=============
@@ -528,10 +528,17 @@ USE_BASE_TAG = False
# RSS_PATH = ""

# Final location for the blog main Atom feed is:
# output / TRANSLATION[lang] / ATOM_PATH / index.atom
# output / TRANSLATION[lang] / ATOM_PATH / ATOM_FILENAME_BASE ATOM_EXTENSION
# (translatable)
# ATOM_PATH = ""

# Atom filename base (without extension); used for indexes.
# (translatable)
ATOM_FILENAME_BASE = "feed"

# Extension for Atom feed files
# ATOM_EXTENSION = ".atom"

# Slug the Tag URL. Easier for users to type, special characters are
# often removed or replaced as well.
# SLUG_TAG_PATH = True
@@ -1071,9 +1078,6 @@ MARKDOWN_EXTENSIONS = ['markdown.extensions.fenced_code', 'markdown.extensions.c
# between each other. Old Atom feeds with no changes are marked as archived.
# GENERATE_ATOM = False

# Extension for Atom feed files
# ATOM_EXTENSION = ".atom"

# Only include teasers in Atom and RSS feeds. Disabling include the full
# content. Defaults to True.
# FEED_TEASERS = True
@@ -1242,10 +1246,10 @@ MARKDOWN_EXTENSIONS = ['markdown.extensions.fenced_code', 'markdown.extensions.c
# Plugins you don't want to use. Be careful :-)
# DISABLED_PLUGINS = ["render_galleries"]

# Special settings to disable only parts of the indexes plugin (to allow RSS
# but no blog indexes, or to allow blog indexes and Atom but no site-wide RSS).
# Special settings to disable only parts of the indexes plugin.
# Use with care.
# DISABLE_INDEXES = False
# DISABLE_MAIN_ATOM_FEED = False
# DISABLE_MAIN_RSS_FEED = False

# Add the absolute paths to directories containing plugins to use them.
@@ -457,6 +457,7 @@ def __init__(self, **config):
'CREATE_DAILY_ARCHIVE': False,
'DATE_FORMAT': '%Y-%m-%d %H:%M',
'DISABLE_INDEXES': False,
'DISABLE_MAIN_ATOM_FEED': False,
'DISABLE_MAIN_RSS_FEED': False,
'JS_DATE_FORMAT': 'YYYY-MM-DD HH:mm',
'DATE_FANCINESS': 0,
@@ -540,6 +541,7 @@ def __init__(self, **config):
'GENERATE_ATOM': False,
'ATOM_EXTENSION': '.atom',
'ATOM_PATH': '',
'ATOM_FILENAME_BASE': 'index',
'FEED_TEASERS': True,
'FEED_PLAIN': False,
'FEED_PREVIEWIMAGE': True,
@@ -667,6 +669,7 @@ def __init__(self, **config):
'ATOM_PATH',
'RSS_PATH',
'RSS_FILENAME_BASE',
'ATOM_FILENAME_BASE',
'AUTHOR_PATH',
'DATE_FORMAT',
'JS_DATE_FORMAT',
@@ -697,6 +700,7 @@ def __init__(self, **config):
self._ALL_PAGE_DEPS_TRANSLATABLE = ('atom_path',
'rss_path',
'rss_filename_base',
'atom_filename_base',
)
# WARNING: navigation_links SHOULD NOT be added to the list above.
# Themes ask for [lang] there and we should provide it.
@@ -729,8 +733,9 @@ def __init__(self, **config):
self.config['FILE_METADATA_UNSLUGIFY_TITLES'] = self.config['UNSLUGIFY_TITLES']

if 'DISABLE_INDEXES_PLUGIN_INDEX_AND_ATOM_FEED' in self.config:
utils.LOGGER.warn('The DISABLE_INDEXES_PLUGIN_INDEX_AND_ATOM_FEED setting was renamed to DISABLE_INDEXES.')
utils.LOGGER.warn('The DISABLE_INDEXES_PLUGIN_INDEX_AND_ATOM_FEED setting was renamed and split to DISABLE_INDEXES and DISABLE_MAIN_ATOM_FEED.')
self.config['DISABLE_INDEXES'] = self.config['DISABLE_INDEXES_PLUGIN_INDEX_AND_ATOM_FEED']
self.config['DISABLE_MAIN_ATOM_FEED'] = self.config['DISABLE_INDEXES_PLUGIN_INDEX_AND_ATOM_FEED']

if 'DISABLE_INDEXES_PLUGIN_RSS_FEED' in self.config:
utils.LOGGER.warn('The DISABLE_INDEXES_PLUGIN_RSS_FEED setting was renamed to DISABLE_MAIN_RSS_FEED.')
@@ -1198,6 +1203,7 @@ def _set_all_page_deps_from_config(self):
self.ALL_PAGE_DEPS['rss_extension'] = self.config.get('RSS_EXTENSION')
self.ALL_PAGE_DEPS['rss_path'] = self.config.get('RSS_PATH')
self.ALL_PAGE_DEPS['rss_filename_base'] = self.config.get('RSS_FILENAME_BASE')
self.ALL_PAGE_DEPS['atom_filename_base'] = self.config.get('ATOM_FILENAME_BASE')
self.ALL_PAGE_DEPS['slug_author_path'] = self.config.get('SLUG_AUTHOR_PATH')
self.ALL_PAGE_DEPS['slug_tag_path'] = self.config.get('SLUG_TAG_PATH')

@@ -2304,15 +2310,17 @@ def atom_link(link_rel, link_type, link_href):
for post in posts:
deps += post.deps(lang)
uptodate_deps += post.deps_uptodate(lang)

context = {}
blog_title = self.config['BLOG_TITLE'](lang)
context["posts"] = posts
context["title"] = self.config['BLOG_TITLE'](lang)
context["title"] = blog_title
context["description"] = self.config['BLOG_DESCRIPTION'](lang)
context["lang"] = lang
context["prevlink"] = None
context["nextlink"] = None
context["is_feed_stale"] = None
context.update(extra_context)

context["title"] = "{0} ({1})".format(blog_title, context["title"]) if blog_title != context["title"] else blog_title

deps_context = copy(context)
deps_context["posts"] = [(p.meta[lang]['title'], p.permalink(lang)) for p in
posts]
@@ -2324,13 +2332,8 @@ def atom_link(link_rel, link_type, link_href):
for k in self._ALL_PAGE_DEPS_TRANSLATABLE:
deps_context[k] = deps_context['all_page_deps'][k](lang)

deps_context['navigation_links'] = deps_context['global']['navigation_links'](lang)

nslist = {}
if context["is_feed_stale"] or "feedpagenum" in context and (not context["feedpagenum"] == context["feedpagecount"] - 1 and not context["feedpagenum"] == 0):
nslist["fh"] = "http://purl.org/syndication/history/1.0"
feed_xsl_link = self.abs_link("/assets/xml/atom.xsl")
feed_root = lxml.etree.Element("feed", nsmap=nslist)
feed_root = lxml.etree.Element("feed")
feed_root.addprevious(lxml.etree.ProcessingInstruction(
"xml-stylesheet",
'href="' + utils.encodelink(feed_xsl_link) + '" type="text/xsl media="all"'))
@@ -2347,25 +2350,6 @@ def atom_link(link_rel, link_type, link_href):
feed_author_name.text = self.config["BLOG_AUTHOR"](lang)
feed_root.append(atom_link("self", "application/atom+xml",
self.abs_link(context["feedlink"])))
# Older is "next" and newer is "previous" in paginated feeds (opposite of archived)
if "nextfeedlink" in context:
feed_root.append(atom_link("next", "application/atom+xml",
self.abs_link(context["nextfeedlink"])))
if "prevfeedlink" in context:
feed_root.append(atom_link("previous", "application/atom+xml",
self.abs_link(context["prevfeedlink"])))
if context["is_feed_stale"] or "feedpagenum" in context and not context["feedpagenum"] == 0:
feed_root.append(atom_link("current", "application/atom+xml",
self.abs_link(context["currentfeedlink"])))
# Older is "prev-archive" and newer is "next-archive" in archived feeds (opposite of paginated)
if "prevfeedlink" in context and (context["is_feed_stale"] or "feedpagenum" in context and not context["feedpagenum"] == context["feedpagecount"] - 1):
feed_root.append(atom_link("next-archive", "application/atom+xml",
self.abs_link(context["prevfeedlink"])))
if "nextfeedlink" in context:
feed_root.append(atom_link("prev-archive", "application/atom+xml",
self.abs_link(context["nextfeedlink"])))
if context["is_feed_stale"] or "feedpagenum" and not context["feedpagenum"] == context["feedpagecount"] - 1:
lxml.etree.SubElement(feed_root, "{http://purl.org/syndication/history/1.0}archive")
feed_root.append(atom_link("alternate", "text/html",
self.abs_link(context["permalink"])))
feed_generator = lxml.etree.SubElement(feed_root, "generator")
@@ -2454,7 +2438,7 @@ def atom_post_text(post, text):
data = data.decode('utf-8')
atom_file.write(data)

def generic_index_renderer(self, lang, posts, indexes_title, template_name, context_source, kw, basename, page_link, page_path, additional_dependencies=[]):
def generic_index_renderer(self, lang, posts, indexes_title, template_name, context_source, kw, basename, page_link, page_path, additional_dependencies=None):
"""Create an index page.
lang: The language
@@ -2489,12 +2473,11 @@ def generic_index_renderer(self, lang, posts, indexes_title, template_name, cont
kw["indexes_pages_main"] = self.config['INDEXES_PAGES_MAIN']
kw["indexes_static"] = self.config['INDEXES_STATIC']
kw['indexes_pretty_page_url'] = self.config["INDEXES_PRETTY_PAGE_URL"]
kw['demote_headers'] = self.config['DEMOTE_HEADERS']
kw['generate_atom'] = self.config["GENERATE_ATOM"]
kw['feed_links_append_query'] = self.config["FEED_LINKS_APPEND_QUERY"]
kw['currentfeed'] = None
kw['show_index_page_navigation'] = self.config['SHOW_INDEX_PAGE_NAVIGATION']

if additional_dependencies is None:
additional_dependencies = []

# Split in smaller lists
lists = []
if kw["indexes_static"]:
@@ -2594,34 +2577,6 @@ def generic_index_renderer(self, lang, posts, indexes_title, template_name, cont
task['basename'] = basename
yield task

if kw['generate_atom']:
atom_output_name = os.path.join(kw['output_folder'], page_path(i, ipages_i, num_pages, False, extension=".atom"))
context["feedlink"] = page_link(i, ipages_i, num_pages, False, extension=".atom")
if not kw["currentfeed"]:
kw["currentfeed"] = context["feedlink"]
context["currentfeedlink"] = kw["currentfeed"]
context["feedpagenum"] = i
context["feedpagecount"] = num_pages
kw['feed_teasers'] = self.config['FEED_TEASERS']
kw['feed_plain'] = self.config['FEED_PLAIN']
kw['feed_previewimage'] = self.config['FEED_PREVIEWIMAGE']
atom_task = {
"basename": basename,
"name": atom_output_name,
"file_dep": sorted([_.base_path for _ in post_list]),
"task_dep": ['render_posts'],
"targets": [atom_output_name],
"actions": [(self.atom_feed_renderer,
(lang,
post_list,
atom_output_name,
kw['filters'],
context,))],
"clean": True,
"uptodate": [utils.config_changed(kw, 'nikola.nikola.Nikola.atom_feed_renderer')] + additional_dependencies
}
yield utils.apply_filters(atom_task, kw['filters'])

if kw["indexes_pages_main"] and kw['indexes_pretty_page_url'](lang):
# create redirection
output_name = os.path.join(kw['output_folder'], page_path(0, displayed_page_numbers[0], num_pages, True))
@@ -2635,6 +2590,59 @@ def generic_index_renderer(self, lang, posts, indexes_title, template_name, cont
'uptodate': [utils.config_changed(kw, 'nikola.nikola.Nikola.generic_index_renderer')],
}, kw["filters"])

def generic_atom_renderer(self, lang, posts, context_source, kw, basename, classification, kind, additional_dependencies=None):
"""Create an Atom feed.
lang: The language
posts: A list of posts
context_source: This will be copied and extended and used as every
page's context
kw: An extended version will be used for uptodate dependencies
basename: Basename for task
classification: name of current classification (used to generate links)
kind: classification kind (used to generate links)
additional_dependencies: a list of dependencies which will be added
to task['uptodate']
"""
# Update kw
kw = kw.copy()
kw["feed_length"] = self.config['FEED_LENGTH']
kw['generate_atom'] = self.config["GENERATE_ATOM"]
kw['feed_links_append_query'] = self.config["FEED_LINKS_APPEND_QUERY"]
kw['feed_teasers'] = self.config['FEED_TEASERS']
kw['feed_plain'] = self.config['FEED_PLAIN']
kw['feed_previewimage'] = self.config['FEED_PREVIEWIMAGE']

if additional_dependencies is None:
additional_dependencies = []

post_list = posts[:kw["feed_length"]]
feedlink = self.link(kind + "_atom", classification, lang)
feedpath = self.path(kind + "_atom", classification, lang)

context = context_source.copy()
if 'has_other_languages' not in context:
context['has_other_languages'] = False

output_name = os.path.join(kw['output_folder'], feedpath)
context["feedlink"] = feedlink
task = {
"basename": basename,
"name": output_name,
"file_dep": sorted([_.base_path for _ in post_list]),
"task_dep": ['render_posts'],
"targets": [output_name],
"actions": [(self.atom_feed_renderer,
(lang,
post_list,
output_name,
kw['filters'],
context,))],
"clean": True,
"uptodate": [utils.config_changed(kw, 'nikola.nikola.Nikola.atom_feed_renderer')] + additional_dependencies
}
yield utils.apply_filters(task, kw['filters'])

def __repr__(self):
"""Representation of a Nikola site."""
return '<Nikola Site: {0!r}>'.format(self.config['BLOG_TITLE'](self.config['DEFAULT_LANG']))
@@ -643,18 +643,18 @@ class Taxonomy(BasePlugin):
The template to use for the subcategories list when
show_list_as_subcategories_list is True.
generate_atom_feeds_for_post_lists = False:
Whether to generate Atom feeds for post lists in case GENERATE_ATOM is set.
template_for_single_list = "tagindex.tmpl":
The template to use for the post list for one classification.
template_for_classification_overview = "list.tmpl":
The template to use for the classification overview page.
Set to None to avoid generating overviews.
always_disable_atom = False:
Whether to always disable Atom feed generation.
always_disable_rss = False:
Whether to always disable RSS feed generation
Whether to always disable RSS feed generation.
apply_to_posts = True:
Whether this classification applies to posts.
@@ -698,9 +698,9 @@ class Taxonomy(BasePlugin):
show_list_as_subcategories_list = False
show_list_as_index = False
subcategories_list_template = "taxonomy_list.tmpl"
generate_atom_feeds_for_post_lists = False
template_for_single_list = "tagindex.tmpl"
template_for_classification_overview = "list.tmpl"
always_disable_atom = False
always_disable_rss = False
apply_to_posts = True
apply_to_pages = False
@@ -860,6 +860,10 @@ def should_generate_classification_page(self, classification: str, post_list: 't
"""Only generates list of posts for classification if this function returns True."""
return True

def should_generate_atom_for_classification_page(self, classification: str, post_list: 'typing.List[nikola.post.Post]', lang: str) -> bool:
"""Only generates Atom feed for list of posts for classification if this function returns True."""
return self.should_generate_classification_page(classification, post_list, lang)

def should_generate_rss_for_classification_page(self, classification: str, post_list: 'typing.List[nikola.post.Post]', lang: str) -> bool:
"""Only generates RSS feed for list of posts for classification if this function returns True."""
return self.should_generate_classification_page(classification, post_list, lang)
@@ -241,6 +241,8 @@ def _postprocess_path(self, path, lang, append_index='auto', dest_type='page', p
if force_extension is not None:
if len(path) == 0 and dest_type == 'rss':
path = [self.site.config['RSS_FILENAME_BASE'](lang)]
elif len(path) == 0 and dest_type == 'feed':
path = [self.site.config['ATOM_FILENAME_BASE'](lang)]
elif len(path) == 0 or append_index == 'always':
path = path + [os.path.splitext(self.site.config['INDEX_FILE'])[0]]
elif len(path) > 0 and append_index == 'never':

0 comments on commit 8a71bee

Please sign in to comment.