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)