Skip to content

Commit 2f6acdf

Browse files
committed
Misc: Add --unloaded option.
1 parent 6be6c91 commit 2f6acdf

File tree

4 files changed

+69
-16
lines changed

4 files changed

+69
-16
lines changed

plugins/Misc/config.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ def configure(advanced):
4646
plugins with the list command if given the --private switch. If this is
4747
disabled, non-owner users should be unable to see what private plugins
4848
are loaded.""")))
49+
conf.registerGlobalValue(Misc, 'listUnloadedPlugins',
50+
registry.Boolean(True, _("""Determines whether the bot will list unloaded
51+
plugins with the list command if given the --unloaded switch. If this is
52+
disabled, non-owner users should be unable to see what unloaded plugins
53+
are available.""")))
4954
conf.registerGlobalValue(Misc, 'timestampFormat',
5055
registry.String('[%H:%M:%S]', _("""Determines the format string for
5156
timestamps in the Misc.last command. Refer to the Python documentation

plugins/Misc/plugin.py

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
import re
3232
import os
33+
import imp
3334
import sys
3435
import time
3536

@@ -49,6 +50,23 @@
4950
from supybot.i18n import PluginInternationalization, internationalizeDocstring
5051
_ = PluginInternationalization('Misc')
5152

53+
def get_suffix(file):
54+
for suffix in imp.get_suffixes():
55+
if file[-len(suffix[0]):] == suffix[0]:
56+
return suffix
57+
return None
58+
59+
def getPluginsInDirectory(directory):
60+
# get modules in a given directory
61+
plugins = []
62+
for filename in os.listdir(directory):
63+
pluginPath = os.path.join(directory, filename)
64+
if os.path.isdir(pluginPath):
65+
if all(os.path.isfile(os.path.join(pluginPath, x))
66+
for x in ['__init__.py', 'config.py', 'plugin.py']):
67+
plugins.append(filename)
68+
return plugins
69+
5270
class RegexpTimeout(Exception):
5371
pass
5472

@@ -121,34 +139,57 @@ def invalidCommand(self, irc, msg, tokens):
121139

122140
@internationalizeDocstring
123141
def list(self, irc, msg, args, optlist, cb):
124-
"""[--private] [<plugin>]
142+
"""[--private] [--unloaded] [<plugin>]
125143
126144
Lists the commands available in the given plugin. If no plugin is
127145
given, lists the public plugins available. If --private is given,
128-
lists the private plugins.
146+
lists the private plugins. If --unloaded is given, it will list
147+
available plugins that are not loaded.
129148
"""
130149
private = False
150+
unloaded = False
131151
for (option, argument) in optlist:
132152
if option == 'private':
133153
private = True
134154
if not self.registryValue('listPrivatePlugins') and \
135155
not ircdb.checkCapability(msg.prefix, 'owner'):
136156
irc.errorNoCapability('owner')
157+
elif option == 'unloaded':
158+
unloaded = True
159+
if not self.registryValue('listUnloadedPlugins') and \
160+
not ircdb.checkCapability(msg.prefix, 'owner'):
161+
irc.errorNoCapability('owner')
162+
if unloaded and private:
163+
irc.error(_('--private and --unloaded are uncompatible options.'))
164+
return
137165
if not cb:
138-
def isPublic(cb):
139-
name = cb.name()
140-
return conf.supybot.plugins.get(name).public()
141-
names = [cb.name() for cb in irc.callbacks
142-
if (private and not isPublic(cb)) or
143-
(not private and isPublic(cb))]
144-
names.sort()
145-
if names:
146-
irc.reply(format('%L', names))
166+
if unloaded:
167+
installedPluginsDirectory = os.path.join(
168+
os.path.dirname(__file__), '..')
169+
plugins = getPluginsInDirectory(installedPluginsDirectory)
170+
for directory in conf.supybot.directories.plugins()[:]:
171+
plugins.extend(getPluginsInDirectory(directory))
172+
# Remove loaded plugins:
173+
loadedPlugins = [x.name() for x in irc.callbacks]
174+
plugins = [x for x in plugins if x not in loadedPlugins]
175+
176+
plugins.sort()
177+
irc.reply(format('%L', plugins))
147178
else:
148-
if private:
149-
irc.reply(_('There are no private plugins.'))
179+
def isPublic(cb):
180+
name = cb.name()
181+
return conf.supybot.plugins.get(name).public()
182+
names = [cb.name() for cb in irc.callbacks
183+
if (private and not isPublic(cb)) or
184+
(not private and isPublic(cb))]
185+
names.sort()
186+
if names:
187+
irc.reply(format('%L', names))
150188
else:
151-
irc.reply(_('There are no public plugins.'))
189+
if private:
190+
irc.reply(_('There are no private plugins.'))
191+
else:
192+
irc.reply(_('There are no public plugins.'))
152193
else:
153194
commands = cb.listCommands()
154195
if commands:
@@ -162,7 +203,8 @@ def isPublic(cb):
162203
'Try "config list supybot.plugins.%s" to see '
163204
'what configuration variables it has.'),
164205
cb.name()))
165-
list = wrap(list, [getopts({'private':''}), additional('plugin')])
206+
list = wrap(list, [getopts({'private':'', 'unloaded':''}),
207+
additional('plugin')])
166208

167209
@internationalizeDocstring
168210
def apropos(self, irc, msg, args, s):

plugins/Misc/test.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ def testListPrivate(self):
114114
self.assertRegexp('list', name)
115115
self.assertNotRegexp('list --private', name)
116116

117+
def testListUnloaded(self):
118+
unloadedPlugin = 'Alias'
119+
loadedPlugin = 'Anonymous'
120+
self.assertRegexp('list --unloaded', 'Alias')
121+
self.assertNotRegexp('list --unloaded', 'Anonymous')
122+
117123
def testListDoesNotIncludeNonCanonicalName(self):
118124
self.assertNotRegexp('list Owner', '_exec')
119125

src/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""stick the various versioning attributes in here, so we only have to change
22
them once."""
3-
version = '0.83.4.1+limnoria (2011-08-30T17:21:39+0000)'
3+
version = '0.83.4.1+limnoria (2011-09-01T17:48:08+0000)'

0 commit comments

Comments
 (0)