diff --git a/.gitignore b/.gitignore index 61a0f68..20ceceb 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ logs/ backup/ data/ tmp/ + +# auto-generated: +use/plugins/ diff --git a/generate_plugin_doc.py b/generate_plugin_doc.py old mode 100644 new mode 100755 index 7810bcb..a3a37b6 --- a/generate_plugin_doc.py +++ b/generate_plugin_doc.py @@ -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") diff --git a/use/index.rst b/use/index.rst index ce4c7f7..8d1a24d 100644 --- a/use/index.rst +++ b/use/index.rst @@ -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