Rewrite the plugin doc generation script so it actually works.

Depends on Limnoria >= 2021.04.05, both for supybot-plugin-doc updates
and reorganized documentation in plugins
This commit is contained in:
Valentin Lorentz 2021-04-11 11:34:14 +02:00
parent f1e719a82d
commit 71536bc9f9
3 changed files with 48 additions and 73 deletions

3
.gitignore vendored
View File

@ -8,3 +8,6 @@ logs/
backup/
data/
tmp/
# auto-generated:
use/plugins/

111
generate_plugin_doc.py Normal file → Executable file
View File

@ -1,83 +1,50 @@
#!/usr/bin/env python2
from __future__ import with_statement
#!/usr/bin/env python3
import os
import re
import sys
import pkgutil
import subprocess
import textwrap
# Commands instances are converted into SynchronizedAndFirewalled
from supybot.callbacks import SynchronizedAndFirewalled as Commands
import supybot.plugins
validCommandName = re.compile('^[a-z]+$')
OUTPUT_DIR = os.path.join(os.path.dirname(__file__), "use", "plugins")
sys.path.append('/home/progval/workspace/Supybot/Supybot-plugins')
def iter_subpackages(package):
for importer, modname, ispkg in pkgutil.iter_modules(package.__path__):
if ispkg:
yield modname
def main():
pluginNames = sys.argv[1:]
for pluginName in pluginNames:
supybot = __import__('%s.plugin' % pluginName)
PluginClass = supybot.plugin.Class
filename = 'use/plugins/%s.rst' % pluginName.lower()
try:
os.unlink(filename)
except OSError:
pass
with open(filename, 'a') as fd:
fd.write('\n.. _plugin-%s:\n\nThe %s plugin\n' %
(pluginName.lower(), pluginName))
fd.write('='*len('The %s plugin' % pluginName))
fd.write('\n\n')
writeDoc(PluginClass, fd, pluginName.lower())
os.makedirs(OUTPUT_DIR, exist_ok=True)
def writeDoc(PluginClass, fd, prefix):
prefix += ' '
for attributeName, attribute in PluginClass.__dict__.items():
if not callable(attribute):
continue
if not validCommandName.match(attributeName):
continue
if attributeName == 'die':
continue
if isinstance(attribute, Commands):
writeDoc(attribute, fd, prefix + attributeName)
else:
if attribute.__doc__ is None:
attribute.__doc__ = ''
syntax = attribute.__doc__.split('\n\n')[0].strip()
if syntax == 'takes no arguments' or syntax == '' or syntax == '':
syntax = ''
else:
syntax = ' ' + syntax
args = {
'prefix_dash': prefix.replace(' ', '-'),
'command': attributeName, # Does not contain spaces
'prefix_with_trailing_space': prefix,
'syntax': syntax,
'help_string': parseHelpString(attribute.__doc__),
}
args['decoration'] = '^'*len('%(prefix_with_trailing_space)s%(command)s%(syntax)s' %
args)
fd.write('.. _command-%(prefix_dash)s%(command)s:\n\n'
'%(prefix_with_trailing_space)s%(command)s%(syntax)s\n'
'%(decoration)s\n\n'
'%(help_string)s\n\n' % args)
subprocess.run([
"supybot-plugin-doc",
"--plugins-dir", os.path.dirname(supybot.plugins.__file__),
"-o", OUTPUT_DIR,
"-f", "rst",
"--title-template", "$name",
], check=True)
def parseHelpString(string):
# Remove the syntax
string = '\n\n'.join(string.split('\n\n')[1:])
# Remove the starting and ending spaces
string = '\n'.join([x.strip(' ') for x in string.split('\n')])
if string.endswith('\n'):
string = string[0:-1]
# Put the argument names into italic
string = re.sub(r'(<[^>]+>)', r'*\1*', string, re.M)
string = re.sub(r'(--[^ ]+)', r'*\1*', string, re.M)
# Turn config variable names into refs
string = re.sub(r'(supybot.[a-zA-Z0-9.]+)', r':ref:`\1`', string, re.M)
return string
plugins = list(iter_subpackages(supybot.plugins))
with open(os.path.join(OUTPUT_DIR, "index.rst"), "w") as fd:
fd.write(
textwrap.dedent(
"""
Built-in plugins reference
==========================
if __name__ == '__main__':
main()
Here is a list of all built-in plugins and their commands
and configuration.
For an overview of all major plugins, see
`Limnoria.net's plugin page`_
.. _Limnoria.net's plugin page: https://limnoria.net/plugins.xhtml
.. toctree::
:maxdepth: 1
"""
)
)
for plugin in plugins:
fd.write(f" {plugin}\n")

View File

@ -14,6 +14,11 @@ User Guide
identifying_to_services.rst
capabilities.rst
security.rst
faq.rst
httpserver.rst
supybot-botchk.rst
faq.rst
.. toctree::
:maxdepth: 1
plugins/index.rst