#!/usr/bin/env python ### # Copyright (c) 2002, Jeremiah Fincher # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions, and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions, and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the author of this software nor the name of # contributors to this software may be used to endorse or promote products # derived from this software without specific prior written consent. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. ### import os import cgi import imp import sys import os.path import textwrap import traceback import supybot import supybot.world as world world.documenting = True if not os.path.exists('test-conf'): os.mkdir('test-conf') registryFilename = os.path.join('test-conf', 'test.conf') fd = file(registryFilename, 'w') fd.write(""" supybot.directories.data: test-data supybot.directories.conf: test-conf supybot.directories.log: test-logs """) fd.close() import supybot.registry as registry registry.open(registryFilename) import supybot.conf as conf import supybot.utils as utils import supybot.callbacks as callbacks commandDict = {} firstChars = {} def genHeader(title, meta=''): return ''' %s %s
''' % (title, meta) def genNavbar(path, cActive=True): download = 'http://sourceforge.net/project/showfiles.php?group_id=58965' bug = 'http://sourceforge.net/tracker/?func=add&group_id=58965&'\ 'atid=489447' if cActive: command = '
  • \nCommands Index\n
  • '\ % path[3:] else: command = '
  • \nCommands Index\n
  • ' return ''' ''' % (path, download, bug, command) def genFooter(): return '''

    Valid HTML 4.01! Valid CSS! SourceForge.net Logo
    ''' def prepIndex(): directory = os.path.join('docs', 'plugins') if not os.path.exists(directory): os.mkdir(directory) fd = file(os.path.join('docs', 'plugins.html'), 'w') fd.write(textwrap.dedent(''' %s
    Supybot Plugin Documentation Index
    %s
    ''' % (genHeader('Supybot Plugin Documentation'), genNavbar('../')))) fd.close() def makePluginDocumentation(pluginWindow): global commandDict global firstChars trClasses = { 'even':'odd', 'odd':'even' } trClass = 'even' (pluginName, module, plugin) = pluginWindow[1] if getattr(module, "deprecated", False): deprecated = textwrap.dedent("""
    This plugin is deprecated. That means that it is probably broken and no one cares about it enought to fix it or the 3rd party module it may be using. If you want this plugin to work, adopt it or provide a patch in our patch tracker on Sourceforge.
    """) else: deprecated = '' print 'Generating documentation for %s.py' % pluginName prev = pluginWindow[0][0] or '../plugins' next = pluginWindow[2][0] or '../plugins' # can't use string.capitalize() because it lowercases every character # except the first. must create our own capitalized names cpluginName = '%s%s' % (pluginName[0].upper(), pluginName[1:]) temp = prev.strip('./') cprev = '%s%s' % (temp[0].upper(), temp[1:]) temp = next.strip('./') cnext = '%s%s' % (temp[0].upper(), temp[1:]) directory = os.path.join('docs', 'plugins') if not os.path.exists(directory): os.mkdir(directory) id = file(os.path.join('docs', 'plugins.html'), 'a') id.write('%s\n' % (pluginName, cpluginName)) fd = file(os.path.join(directory,'%s.html' % pluginName), 'w') title = 'Documentation for the %s plugin for Supybot' % pluginName meta = ''' ''' % (next, prev) pluginhelp = getattr(module.Class, '__doc__', False) if pluginhelp: pluginhelp = '
    %s
    ' %\ cgi.escape(pluginhelp) else: pluginhelp = '' fd.write(textwrap.dedent(''' %s
    %s
    %s %s
    %s ''' % (genHeader(title, meta), cgi.escape(module.__doc__ or ""), pluginhelp, deprecated, genNavbar('../../'), pluginName))) attrs = [x for x in dir(plugin) if plugin.isCommand(x) and not x.startswith('_')] id.write('(%s)
    \n' % ', '.join(attrs)) for attr in attrs: if attr in commandDict: commandDict[attr].append(pluginName) else: commandDict[attr] = [pluginName] if attr[0] not in firstChars: firstChars[attr[0]] = '' method = getattr(plugin, attr) if hasattr(method, '__doc__'): doclines = method.__doc__.splitlines() help = doclines.pop(0) morehelp = 'This command has no detailed help.' if doclines: doclines = filter(None, doclines) doclines = map(str.strip, doclines) morehelp = ' '.join(doclines) help = cgi.escape(help) morehelp = cgi.escape(morehelp) trClass = trClasses[trClass] fd.write(textwrap.dedent(''' ''' % (trClass, attr, attr, help, morehelp))) try: pluginconf = conf.supybot.plugins.get(pluginName) fd.write(textwrap.dedent( '''
    Commands for %s
    CommandArgs Detailed Help
    %s%s %s

    ''' % pluginName)) trClass = trClasses[trClass] for config in [(c[0], c[1]) for c in\ pluginconf.getValues(getChildren=True,fullNames=False)]: name = config[0] default = str(config[1]) if isinstance(config[1]._default, basestring): default = utils.dqrepr(default) help = config[1]._help help = cgi.escape(help) trClass = trClasses[trClass] fd.write(textwrap.dedent(''' ''' % (trClass, name, default, config[1].channelValue, help))) except registry.NonExistentRegistryEntry: pass fd.write('
    Configuration Variables for %s
    Config Var Default Value Channel Specific Help
    %s%s%s %s
    \n') fd.write(textwrap.dedent('''

    <- %s | Plugins Index | Commands Index | %s -> %s ''' % (prev, cprev, next, cnext, genFooter()))) fd.close() id.close() def finishIndex(): directory = 'docs' if not os.path.exists(directory): os.mkdir(directory) fd = file(os.path.join(directory, 'plugins.html'), 'a') fd.write(textwrap.dedent('
    \n%s' % genFooter())) fd.close() def makeCommandsIndex(): from string import ascii_lowercase global commandDict global firstChars directory = 'docs' if not os.path.exists(directory): os.mkdir(directory) fd = file(os.path.join(directory, 'commands.html'), 'w') title = 'Supybot Commands Index' fd.write(textwrap.dedent(''' %s
    %s
    %s
    ''' % (genHeader(title), title, genNavbar('../', cActive=False)))) commands = [c for c in commandDict.iterkeys()] commands.sort() for i in ascii_lowercase: if i in firstChars: fd.write('%s \n' % (i, i.capitalize())) else: fd.write('%s ' % i.capitalize()) firstChars.clear() fd.write('
    \n
    ') pluginLink = '%s' for command in commands: c = command[0] if c not in firstChars: if firstChars: fd.write('
    \n') fd.write('\n
    ') firstChars[c] = '' fd.write('
    %s
    \n' % (c, c.capitalize())) plugins = commandDict[command] plugins.sort() fd.write('%s (%s)
    \n' % (command, ', \n\t'.join([pluginLink % (p,command,p) for p in plugins]))) fd.write('\n
    ') fd.write(textwrap.dedent(genFooter())) fd.close() def genPlugins(): for directory in conf.supybot.directories.plugins(): for filename in os.listdir(directory): if filename.endswith('.py') and filename[0].isupper(): pluginName = filename.split('.')[0] moduleInfo = imp.find_module(pluginName, conf.supybot.directories.plugins() ) try: module = imp.load_module(pluginName, *moduleInfo) except Exception, e: print 'Couldn\'t load %s: %s' % \ (pluginName, utils.exnToString(e)) continue if not hasattr(module, 'Class'): print '%s is not a plugin.' % filename continue try: plugin = module.Class() except Exception, e: print '%s could not be loaded: %s' % (filename, utils.exnToString(e)) continue if isinstance(plugin, callbacks.Privmsg) and not \ isinstance(plugin, callbacks.PrivmsgRegexp): yield (pluginName, module, plugin) if __name__ == '__main__': if not os.path.exists(conf.supybot.directories.data()): os.mkdir(conf.supybot.directories.data()) if not os.path.exists(conf.supybot.directories.conf()): os.mkdir(conf.supybot.directories.conf()) if not os.path.exists(conf.supybot.directories.log()): os.mkdir(conf.supybot.directories.log()) prepIndex() plugins = [p for p in genPlugins()] plugins.sort() plugins.insert(0, [None]) plugins.append([None]) for pluginWindow in window(plugins, 3): makePluginDocumentation(pluginWindow) finishIndex() makeCommandsIndex() # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: