doc/ext/extras/txnbox.cmake.in.py (304 lines of code) (raw):

# -*- coding: utf-8 -*- # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Copyright 2019, Oath Inc. """ Transaction Box Sphinx Directives ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Sphinx Docs directives for Transaction Box plugin. """ from docutils import nodes from docutils.parsers import rst from docutils.parsers.rst import directives from sphinx.domains import Domain, ObjType, std from sphinx.roles import XRefRole from sphinx.locale import _ import sphinx import re def txb_value_type_options(argument): return directives.choice(argument, ('NULL', 'string', 'integer', 'boolean', 'ip-address', 'duration')) def txb_make_field(self, tag, value): field = nodes.field() field.append(nodes.field_name(text=tag)) body = nodes.field_body() if isinstance(value, str): body.append(sphinx.addnodes.compact_paragraph(text=value)) else: body.append(value) field.append(body) return field class TxbDirective(std.Target): """ Transaction Box Directive. """ make_field = txb_make_field required_arguments = 1 # name of directive optional_arguments = 0 final_argument_whitespace = False has_content = True option_spec = { 'class': rst.directives.class_option, 'arg': rst.directives.unchanged, 'value': rst.directives.unchanged, 'keys': rst.directives.unchanged, 'hooks': rst.directives.unchanged } # External entry point def run(self): env = self.state.document.settings.env txb_name = self.arguments[0] txb_id = nodes.make_id(txb_name) # First, make a generic desc() node to be the parent. node = sphinx.addnodes.desc() node.document = self.state.document node['objtype'] = 'directive' # Next, make a signature node. This creates a permalink and a highlighted background when the link is selected. title = sphinx.addnodes.desc_signature(txb_name, '') title['ids'].append(txb_name) title['ids'].append(txb_id) title['names'].append(txb_name) title['first'] = False title['objtype'] = 'directive' self.add_name(title) title['classes'].append('directive-title') # Finally, add a desc_name() node to display the name of the # configuration variable. title += sphinx.addnodes.desc_name(txb_name, txb_name) node.append(title) if ('class' in self.options): title['classes'].append(self.options.get('class')) # This has to be a distinct node before the title. if nested then the browser will scroll forward to just past the title. anchor = nodes.target('', '', names=[txb_name]) # Second (optional) arg is 'msgNode' - no idea what I should pass for that # or if it even matters, although I now think it should not be used. self.state.document.note_explicit_target(title) env.domaindata['txb']['directive'][txb_name] = env.docname fl = nodes.field_list() if ('keys' in self.options): key_field = nodes.field() key_field.append(nodes.field_name(text='Secondary Keys')) key_value = nodes.field_list() key_body = nodes.field_body() key_body.append(key_value) key_field.append(key_body) key_list = self.options['keys'].split('|') for key in key_list: tag = key descr = '' if ':' in key: (tag, descr) = key.split(':') tag = tag.strip() descr = descr.strip() key_value.append(self.make_field(tag, descr)) fl.append(key_field) if ('arg' in self.options): fl.append(self.make_field('Argument', self.options['arg'])) if ('value' in self.options): fl.append(self.make_field('Value', self.options['value'])) # Get any contained content nn = nodes.compound() self.state.nested_parse(self.content, self.content_offset, nn) # Create an index node so that Sphinx adds this directive to the index. indexnode = sphinx.addnodes.index(entries=[]) indexnode['entries'].append(('single', _('%s') % txb_name, txb_id, '', '')) return [indexnode, node, fl, nn] # Extractor support class TxbExtractor(std.Target): """ Extractor description. Descriptive text should follow, indented. Then the bulk description (if any) undented. This should be considered equivalent to the Doxygen short and long description. """ required_arguments = 1 optional_arguments = 0 final_argument_whitespace = True has_content = True make_field = txb_make_field option_spec = { 'class': rst.directives.class_option, 'arg': rst.directives.unchanged, # 'result': txb_value_type_options 'result': rst.directives.unchanged } # External entry point def run(self): env = self.state.document.settings.env txb_name = self.arguments[0] txb_id = nodes.make_id(txb_name) # First, make a generic desc() node to be the parent. node = sphinx.addnodes.desc() node.document = self.state.document node['objtype'] = 'extractor' # Next, make a signature node. This creates a permalink and a highlighted background when the link is selected. title = sphinx.addnodes.desc_signature(txb_name, '') title['ids'].append(txb_id) title['names'].append(txb_name) title['first'] = False title['objtype'] = 'extractor' self.add_name(title) title['classes'].append('directive-title') # Finally, add a desc_name() node to display the name of the # configuration variable. title += sphinx.addnodes.desc_name(txb_name, txb_name) node.append(title) if ('class' in self.options): title['classes'].append(self.options.get('class')) # This has to be a distinct node before the title. if nested then the browser will scroll forward to just past the title. anchor = nodes.target('', '', names=[txb_name]) # Second (optional) arg is 'msgNode' - no idea what I should pass for that # or if it even matters, although I now think it should not be used. self.state.document.note_explicit_target(title) env.domaindata['txb']['extractor'][txb_name] = env.docname fl = nodes.field_list() if ('result' in self.options): fl.append(self.make_field('Result', sphinx.addnodes.literal_emphasis(text=self.options['result']))) # fl.append(self.make_field('Result', self.options['result'])) if ('arg' in self.options): fl.append(self.make_field('Argument', self.options['arg'])) # Get any contained content nn = nodes.compound() self.state.nested_parse(self.content, self.content_offset, nn) # Create an index node so that Sphinx adds this directive to the index. indexnode = sphinx.addnodes.index(entries=[]) indexnode['entries'].append(('single', _('%s') % txb_name, txb_id, '', '')) return [indexnode, node, fl, nn] class TxbDirectiveRef(XRefRole): def process_link(self, env, ref_node, explicit_title_p, title, target): return title, target class TxbExtractorRef(XRefRole): def process_link(self, env, ref_node, explicit_title_p, title, target): return title, target class TxbComparison(std.Target): """ Comparison description. """ make_field = txb_make_field required_arguments = 1 optional_arguments = 0 final_argument_whitespace = False has_content = True option_spec = { 'class': rst.directives.class_option, 'arg': rst.directives.unchanged, 'type': rst.directives.unchanged, 'groups': rst.directives.unchanged, 'tuple': rst.directives.flag } # External entry point def run(self): env = self.state.document.settings.env txb_name = self.arguments[0] txb_id = nodes.make_id(txb_name) # First, make a generic desc() node to be the parent. node = sphinx.addnodes.desc() node.document = self.state.document node['objtype'] = 'comparison' # Next, make a signature node. This creates a permalink and a highlighted background when the link is selected. title = sphinx.addnodes.desc_signature(txb_name, '') title['ids'].append(txb_id) title['names'].append(txb_name) title['first'] = False title['objtype'] = 'comparison' self.add_name(title) title['classes'].append('comparison-title') # Finally, add a desc_name() node to display the name of the # configuration variable. title += sphinx.addnodes.desc_name(txb_name, txb_name) node.append(title) if ('class' in self.options): title['classes'].append(self.options.get('class')) fl = nodes.field_list() if ('arg' in self.options): fl.append(self.make_field('Argument', self.options['arg'])) if ('type' in self.options): fl.append(self.make_field('Value Types', self.options['type'])) if ('tuple' in self.options): fl.append(self.make_field('List matching', sphinx.addnodes.literal_emphasis(text='enabled'))) if ('groups' in self.options): fl.append(self.make_field('Groups', self.options['groups'])) # This has to be a distinct node before the title. if nested then the browser will scroll forward to just past the title. anchor = nodes.target('', '', names=[txb_name]) # Second (optional) arg is 'msgNode' - no idea what I should pass for that # or if it even matters, although I now think it should not be used. self.state.document.note_explicit_target(title) env.domaindata['txb']['comparison'][txb_name] = env.docname # Get any contained content nn = nodes.compound() self.state.nested_parse(self.content, self.content_offset, nn) # Create an index node so that Sphinx adds this directive to the index. indexnode = sphinx.addnodes.index(entries=[]) indexnode['entries'].append(('single', _('%s') % txb_name, txb_id, '', '')) return [indexnode, node, fl, nn] class TxbRef(XRefRole): def process_link(self, env, ref_node, explicit_title_p, title, target): return title, target class TxbModifier(std.Target): """ Transaction Box Modifier. """ make_field = txb_make_field required_arguments = 1 # name of modifier optional_arguments = 0 final_argument_whitespace = False has_content = True obj_type = 'modifier' option_spec = { 'class': rst.directives.class_option, 'arg': rst.directives.unchanged, 'expr': rst.directives.unchanged, 'value': rst.directives.unchanged, 'result': rst.directives.unchanged } # External entry point def run(self): env = self.state.document.settings.env txb_name = self.arguments[0] txb_id = nodes.make_id(txb_name) # First, make a generic desc() node to be the parent. node = sphinx.addnodes.desc() node.document = self.state.document node['objtype'] = self.obj_type # Next, make a signature node. This creates a permalink and a highlighted background when the link is selected. title = sphinx.addnodes.desc_signature(txb_name, '') title['ids'].append(txb_name) title['ids'].append(txb_id) title['names'].append(txb_name) title['first'] = False title['objtype'] = self.obj_type self.add_name(title) title['classes'].append('modifier-title') # Finally, add a desc_name() node to display the name of the # configuration variable. title += sphinx.addnodes.desc_name(txb_name, txb_name) node.append(title) if ('class' in self.options): title['classes'].append(self.options.get('class')) # This has to be a distinct node before the title. if nested then the browser will scroll forward to just past the title. anchor = nodes.target('', '', names=[txb_name]) # Second (optional) arg is 'msgNode' - no idea what I should pass for that # or if it even matters, although I now think it should not be used. self.state.document.note_explicit_target(title) env.domaindata['txb'][self.obj_type][txb_name] = env.docname fl = nodes.field_list() if ('keys' in self.options): fl.append(self.make_field('Secondary Keys', self.options['keys'])) if ('arg' in self.options): fl.append(self.make_field('Argument', self.options['arg'])) if ('value' in self.options): fl.append(self.make_field('Value', self.options['value'])) # Get any contained content nn = nodes.compound() self.state.nested_parse(self.content, self.content_offset, nn) # Create an index node so that Sphinx adds this directive to the index. indexnode = sphinx.addnodes.index(entries=[]) indexnode['entries'].append(('single', _('%s') % txb_name, txb_id, '', '')) return [indexnode, node, fl, nn] class TxnBoxDomain(Domain): """ Transaction Box Documentation. """ name = 'txb' label = 'Transaction Box' data_version = 2 object_types = { 'directive': ObjType(_('Directive'), 'directive'), 'extractor': ObjType(_('Extractor'), 'extractor'), 'comparison': ObjType(_('Comparison'), 'comparison'), 'modifier': ObjType(_('Modifier'), 'modifier') } directives = {'directive': TxbDirective, 'extractor': TxbExtractor, 'comparison': TxbComparison, 'modifier': TxbModifier} roles = {'drtv': TxbDirectiveRef(), 'ex': TxbExtractorRef(), 'cmp': TxbRef(), 'mod': TxbRef()} initial_data = { 'directive': {}, # full name -> docname 'extractor': {}, 'comparison': {}, 'modifier': {} } dangling_warnings = { 'directive': "No definition found for directive '%(target)s'", 'extractor': "No definition found for extractor '%(target)s'", 'comparison': "No definition found for comparison '%(target)s'", 'modifier': "No definition found for modifier '%(targets)s'" } def clear_doc(self, docname): tmp_list = self.data['directive'] for var, doc in list(tmp_list.items()): if doc == docname: del tmp_list[var] tmp_list = self.data['extractor'] for var, doc in list(tmp_list.items()): if doc == docname: del tmp_list[var] tmp_list = self.data['comparison'] for var, doc in list(tmp_list.items()): if doc == docname: del tmp_list[var] tmp_list = self.data['modifier'] for var, doc in list(tmp_list.items()): if doc == docname: del tmp_list[var] def find_doc(self, key, obj_type): zret = None if obj_type == 'drtv': obj_list = self.data['directive'] elif obj_type == 'extractor': obj_list = self.data['extractor'] elif obj_type == 'cmp': obj_list = self.data['comparison'] elif obj_type == 'ex': obj_list = self.data['extractor'] elif obj_type == 'mod': obj_list = self.data['modifier'] else: obj_list = None if obj_list and key in obj_list: zret = obj_list[key] return zret def resolve_xref(self, env, src_doc, builder, obj_type, target, node, cont_node): dst_doc = self.find_doc(target, obj_type) if (dst_doc): return sphinx.util.nodes.make_refnode(builder, src_doc, dst_doc, nodes.make_id(target), cont_node, target) def get_objects(self): for var, doc in self.data['directive'].items(): yield var, var, 'directive', doc, var, 1 for var, doc in self.data['extractor'].items(): yield var, var, 'extractor', doc, var, 1 for var, doc in self.data['comparison'].items(): yield var, var, 'comparison', doc, var, 1 for var, doc in self.data['modifier'].items(): yield var, var, 'modifier', doc, var, 1 def setup(app): rst.roles.register_generic_role('arg', nodes.emphasis) rst.roles.register_generic_role('const', nodes.literal) app.add_domain(TxnBoxDomain)