From 2f6acdf42f0d4b34f49a6259e4e34bd1f6cbc3e1 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Thu, 1 Sep 2011 17:48:09 +0000 Subject: [PATCH] Misc: Add --unloaded option. --- plugins/Misc/config.py | 5 +++ plugins/Misc/plugin.py | 72 +++++++++++++++++++++++++++++++++--------- plugins/Misc/test.py | 6 ++++ src/version.py | 2 +- 4 files changed, 69 insertions(+), 16 deletions(-) diff --git a/plugins/Misc/config.py b/plugins/Misc/config.py index f1c4dc19e..873661212 100644 --- a/plugins/Misc/config.py +++ b/plugins/Misc/config.py @@ -46,6 +46,11 @@ conf.registerGlobalValue(Misc, 'listPrivatePlugins', plugins with the list command if given the --private switch. If this is disabled, non-owner users should be unable to see what private plugins are loaded."""))) +conf.registerGlobalValue(Misc, 'listUnloadedPlugins', + registry.Boolean(True, _("""Determines whether the bot will list unloaded + plugins with the list command if given the --unloaded switch. If this is + disabled, non-owner users should be unable to see what unloaded plugins + are available."""))) conf.registerGlobalValue(Misc, 'timestampFormat', registry.String('[%H:%M:%S]', _("""Determines the format string for timestamps in the Misc.last command. Refer to the Python documentation diff --git a/plugins/Misc/plugin.py b/plugins/Misc/plugin.py index 2f20de0a0..7b7a03487 100644 --- a/plugins/Misc/plugin.py +++ b/plugins/Misc/plugin.py @@ -30,6 +30,7 @@ import re import os +import imp import sys import time @@ -49,6 +50,23 @@ from supybot.utils.iter import ifilter from supybot.i18n import PluginInternationalization, internationalizeDocstring _ = PluginInternationalization('Misc') +def get_suffix(file): + for suffix in imp.get_suffixes(): + if file[-len(suffix[0]):] == suffix[0]: + return suffix + return None + +def getPluginsInDirectory(directory): + # get modules in a given directory + plugins = [] + for filename in os.listdir(directory): + pluginPath = os.path.join(directory, filename) + if os.path.isdir(pluginPath): + if all(os.path.isfile(os.path.join(pluginPath, x)) + for x in ['__init__.py', 'config.py', 'plugin.py']): + plugins.append(filename) + return plugins + class RegexpTimeout(Exception): pass @@ -121,34 +139,57 @@ class Misc(callbacks.Plugin): @internationalizeDocstring def list(self, irc, msg, args, optlist, cb): - """[--private] [] + """[--private] [--unloaded] [] Lists the commands available in the given plugin. If no plugin is given, lists the public plugins available. If --private is given, - lists the private plugins. + lists the private plugins. If --unloaded is given, it will list + available plugins that are not loaded. """ private = False + unloaded = False for (option, argument) in optlist: if option == 'private': private = True if not self.registryValue('listPrivatePlugins') and \ not ircdb.checkCapability(msg.prefix, 'owner'): irc.errorNoCapability('owner') + elif option == 'unloaded': + unloaded = True + if not self.registryValue('listUnloadedPlugins') and \ + not ircdb.checkCapability(msg.prefix, 'owner'): + irc.errorNoCapability('owner') + if unloaded and private: + irc.error(_('--private and --unloaded are uncompatible options.')) + return if not cb: - def isPublic(cb): - name = cb.name() - return conf.supybot.plugins.get(name).public() - names = [cb.name() for cb in irc.callbacks - if (private and not isPublic(cb)) or - (not private and isPublic(cb))] - names.sort() - if names: - irc.reply(format('%L', names)) + if unloaded: + installedPluginsDirectory = os.path.join( + os.path.dirname(__file__), '..') + plugins = getPluginsInDirectory(installedPluginsDirectory) + for directory in conf.supybot.directories.plugins()[:]: + plugins.extend(getPluginsInDirectory(directory)) + # Remove loaded plugins: + loadedPlugins = [x.name() for x in irc.callbacks] + plugins = [x for x in plugins if x not in loadedPlugins] + + plugins.sort() + irc.reply(format('%L', plugins)) else: - if private: - irc.reply(_('There are no private plugins.')) + def isPublic(cb): + name = cb.name() + return conf.supybot.plugins.get(name).public() + names = [cb.name() for cb in irc.callbacks + if (private and not isPublic(cb)) or + (not private and isPublic(cb))] + names.sort() + if names: + irc.reply(format('%L', names)) else: - irc.reply(_('There are no public plugins.')) + if private: + irc.reply(_('There are no private plugins.')) + else: + irc.reply(_('There are no public plugins.')) else: commands = cb.listCommands() if commands: @@ -162,7 +203,8 @@ class Misc(callbacks.Plugin): 'Try "config list supybot.plugins.%s" to see ' 'what configuration variables it has.'), cb.name())) - list = wrap(list, [getopts({'private':''}), additional('plugin')]) + list = wrap(list, [getopts({'private':'', 'unloaded':''}), + additional('plugin')]) @internationalizeDocstring def apropos(self, irc, msg, args, s): diff --git a/plugins/Misc/test.py b/plugins/Misc/test.py index bf7948dbd..7105d9414 100644 --- a/plugins/Misc/test.py +++ b/plugins/Misc/test.py @@ -114,6 +114,12 @@ class MiscTestCase(ChannelPluginTestCase): self.assertRegexp('list', name) self.assertNotRegexp('list --private', name) + def testListUnloaded(self): + unloadedPlugin = 'Alias' + loadedPlugin = 'Anonymous' + self.assertRegexp('list --unloaded', 'Alias') + self.assertNotRegexp('list --unloaded', 'Anonymous') + def testListDoesNotIncludeNonCanonicalName(self): self.assertNotRegexp('list Owner', '_exec') diff --git a/src/version.py b/src/version.py index 0c1c0fda6..65819247d 100644 --- a/src/version.py +++ b/src/version.py @@ -1,3 +1,3 @@ """stick the various versioning attributes in here, so we only have to change them once.""" -version = '0.83.4.1+limnoria (2011-08-30T17:21:39+0000)' +version = '0.83.4.1+limnoria (2011-09-01T17:48:08+0000)'