From b94b094b200713214deae49c899d6249fc8a02c2 Mon Sep 17 00:00:00 2001 From: Chris Holdgraf Date: Sun, 13 Sep 2020 14:34:16 -0700 Subject: [PATCH] frontmatter and blog post matching --- ablog/__init__.py | 5 ++ ablog/blog.py | 1 + ablog/post.py | 86 ++++++++++++++++++++++++---- docs/conf.py | 1 + docs/release/ablog-v0.1-released.rst | 12 ++-- 5 files changed, 87 insertions(+), 18 deletions(-) diff --git a/ablog/__init__.py b/ablog/__init__.py index b448f3f4..cf9946b2 100755 --- a/ablog/__init__.py +++ b/ablog/__init__.py @@ -3,6 +3,7 @@ """ import os +from glob import glob from .blog import CONFIG, Blog from .post import ( @@ -16,6 +17,7 @@ process_postlist, process_posts, purge_posts, + CheckFrontMatter, ) from .version import version as __version__ @@ -81,6 +83,7 @@ def setup(app): app.connect("html-collect-pages", generate_atom_feeds) app.connect("html-page-context", html_page_context) + app.add_transform(CheckFrontMatter) app.add_directive("update", UpdateDirective) app.add_node( UpdateNode, @@ -97,6 +100,8 @@ def setup(app): def config_inited(app, config): app.config.templates_path.append(get_html_templates_path()) + app.config.matched_blog_posts = [os.path.splitext(ii)[0] + for ii in glob(config.blog_post_pattern)] def get_html_templates_path(): diff --git a/ablog/blog.py b/ablog/blog.py index aa8e5b96..1f926d04 100644 --- a/ablog/blog.py +++ b/ablog/blog.py @@ -121,6 +121,7 @@ def verify_fn(key, value, config): ("disqus_shortname", None, True), ("disqus_drafts", False, True), ("disqus_pages", False, True), + ("blog_post_pattern", "", True, require_config_type(str)), ] diff --git a/ablog/post.py b/ablog/post.py index 85fc734e..d5aaa76b 100644 --- a/ablog/post.py +++ b/ablog/post.py @@ -13,6 +13,7 @@ from feedgen.feed import FeedGenerator from sphinx.locale import _ from sphinx.util.nodes import set_source_info +from sphinx.transforms import SphinxTransform import ablog @@ -27,6 +28,7 @@ "PostDirective", "UpdateDirective", "PostListDirective", + "CheckFrontMatter", "purge_posts", "process_posts", "process_postlist", @@ -87,18 +89,7 @@ def run(self): set_source_info(self, node) self.state.nested_parse(self.content, self.content_offset, node, match_titles=1) - node["date"] = self.arguments[0] if self.arguments else None - node["tags"] = self.options.get("tags", []) - node["author"] = self.options.get("author", []) - node["category"] = self.options.get("category", []) - node["location"] = self.options.get("location", []) - node["language"] = self.options.get("language", []) - node["redirect"] = self.options.get("redirect", []) - node["title"] = self.options.get("title", None) - node["image"] = self.options.get("image", None) - node["excerpt"] = self.options.get("excerpt", None) - node["exclude"] = "exclude" in self.options - node["nocomments"] = "nocomments" in self.options + node = _update_post_node(node, self.options, self.arguments) return [node] @@ -159,6 +150,58 @@ def run(self): return [node] +class CheckFrontMatter(SphinxTransform): + """Check the doctree for frontmatter meant for a blog post. + + This is mutually-exclusive with the PostDirective. Only one much be used.""" + + # Priority before 880 so that it runs before the `doctree-read` event + default_priority = 800 + + def apply(self): + # Check if page-level metadata has been given + docinfo = list(self.document.traverse(nodes.docinfo)) + if not docinfo: + return None + docinfo = docinfo[0] + + # Pull the metadata for the page to check if it is a blog post + metadata = {fn.children[0].astext(): fn.children[1].astext() for fn in docinfo.traverse(nodes.field)} + if docinfo.traverse(nodes.author): + metadata["author"] = list(docinfo.traverse(nodes.author))[0].astext() + # These two fields are special-cased in docutils + if docinfo.traverse(nodes.date): + metadata["date"] = list(docinfo.traverse(nodes.date))[0].astext() + if "blogpost" not in metadata and self.env.docname not in self.config.matched_blog_posts: + return None + if self.document.traverse(PostNode): + logging.warning(f"Found blog post front-matter as well as post directive, using post directive.") + + # Iterate through metadata and create a PostNode with relevant fields + option_spec = PostDirective.option_spec + for key, val in metadata.items(): + if key in option_spec: + if callable(option_spec[key]): + new_val = option_spec[key](val) + elif isinstance(option_spec[key], directives.flag): + new_val = True + metadata[key] = new_val + + node = PostNode() + node.document = self.document + node = _update_post_node(node, metadata, []) + node["date"] = metadata.get("date") + + if not metadata.get("excerpt"): + blog = Blog(self.app) + node["excerpt"] = blog.post_auto_excerpt + + sections = list(self.document.traverse(nodes.section)) + if sections: + sections[0].children.append(node) + node.parent = sections[0] + + def purge_posts(app, env, docname): """ Remove post and reference to it from the standard domain when its document @@ -172,6 +215,25 @@ def purge_posts(app, env, docname): env.domains["std"].data["labels"].pop(filename, None) +def _update_post_node(node, options, arguments): + """ + Extract metadata from options and populate a post node. + """ + node["date"] = arguments[0] if arguments else None + node["tags"] = options.get("tags", []) + node["author"] = options.get("author", []) + node["category"] = options.get("category", []) + node["location"] = options.get("location", []) + node["language"] = options.get("language", []) + node["redirect"] = options.get("redirect", []) + node["title"] = options.get("title", None) + node["image"] = options.get("image", None) + node["excerpt"] = options.get("excerpt", None) + node["exclude"] = "exclude" in options + node["nocomments"] = "nocomments" in options + return node + + def _get_section_title(section): """ Return section title as text. diff --git a/docs/conf.py b/docs/conf.py index f1ffde5e..1c59e036 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -74,6 +74,7 @@ disqus_shortname = "ablogforsphinx" disqus_pages = True fontawesome_css_file = "css/font-awesome.css" +blog_post_pattern = "release/ablog-v0.1-released*" # blog_feed_titles = False # blog_archive_titles = False diff --git a/docs/release/ablog-v0.1-released.rst b/docs/release/ablog-v0.1-released.rst index 8b8d3429..3f6bca65 100644 --- a/docs/release/ablog-v0.1-released.rst +++ b/docs/release/ablog-v0.1-released.rst @@ -1,12 +1,12 @@ +:tags: tips +:author: Ahmet +:category: Release +:location: SF +:date: May 14, 2014 + ABlog v0.1 released =================== -.. post:: May 14, 2014 - :tags: tips - :author: Ahmet - :category: Release - :location: SF - ABlog v0.1 is released.