From 59a72da360e2eff53ef510261c3f6307148b52dc Mon Sep 17 00:00:00 2001 From: Michał Górny Date: Sat, 22 Feb 2020 18:15:51 +0100 Subject: Generate a Policy Index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michał Górny --- exts/policyident.py | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/exts/policyident.py b/exts/policyident.py index 6093c8c..7ecc9f2 100644 --- a/exts/policyident.py +++ b/exts/policyident.py @@ -2,13 +2,44 @@ # (c) 2020 Michał Górny # 2-clause BSD license +import collections + from docutils import nodes +from sphinx.domains import Index from sphinx.util import logging logger = logging.getLogger(__name__) +Policy = collections.namedtuple('Policy', ('id', 'title', 'docname', + 'chapter')) + + +class PolicyIndex(Index): + name = 'policy-index' + localname = 'Policy Index' + shortname = 'Policy Index' + + def generate(self, docnames=None): + env = self.domain.env + if not hasattr(env, 'policy_index'): + env.policy_index = [] + + entries = collections.defaultdict(list) + for p in env.policy_index: + if docnames is not None and p.docname not in docnames: + continue + entries[p.chapter].append(('PG' + p.id, # name + 0, # subtype + p.docname, # docname + 'pg' + p.id, # anchor + p.title, # extra + '', # qualifier + '')) # descr + + return ([(k, sorted(v)) for k, v in entries.items()], False) + def find_pg_id(section): # first child should be title @@ -17,7 +48,7 @@ def find_pg_id(section): # second child should be field list cl = section.children[1] if not isinstance(cl, nodes.field_list): - return None + return None, title.astext(), None for f in cl.traverse(nodes.field): fn = next(iter(f.traverse(nodes.field_name))) @@ -29,20 +60,61 @@ def find_pg_id(section): if fv.astext() != iv: raise RuntimeError('PG value must be 4 digits, zero-padded ({})' .format(iv)) - return iv + + el = section + titles = [] + while el.parent is not None: + title = el.children[0] + assert isinstance(title, nodes.title) + titles.append(title.astext()) + el = el.parent + # combine all section titles up to but excluding + # the chapter title + title = ': '.join(reversed(titles[:-1])) + + return iv, title, titles[-1] logger.warning('%s: no PG identifier found', title.astext()) + return None, title.astext(), None def on_doctree_read(app, doctree): + env = app.builder.env + if not hasattr(env, 'policy_index'): + env.policy_index = [] + for node in doctree.traverse(nodes.section): - pg_id = find_pg_id(node) + pg_id, title, chapter = find_pg_id(node) if pg_id is not None: node['ids'].insert(0, 'pg' + pg_id) + env.policy_index.append(Policy(pg_id, title, env.docname, + chapter)) + + +def on_env_purge_doc(app, env, docname): + if not hasattr(env, 'policy_index'): + return + + env.policy_index = [p for p in env.policy_index + if p.docname != docname] + + +def on_env_merge_info(app, env, docnames, other): + if not hasattr(other, 'policy_index'): + return + if not hasattr(env, 'policy_index'): + env.policy_index = [] + + env.policy_index.extend(other.policy_index) def setup(app): app.connect('doctree-read', on_doctree_read) + app.connect('env-purge-doc', on_env_purge_doc) + app.connect('env-merge-info', on_env_merge_info) + app.add_index_to_domain('std', PolicyIndex) return { 'version': '0', + 'parallel_read_safe': True, + 'parallel_write_safe': True, } -- cgit v1.2.3-65-gdbad