Redid startup/configuration junk.

This commit is contained in:
Jeremy Fincher 2003-08-28 16:33:45 +00:00
parent 5860657194
commit a0bf562d7a
7 changed files with 549 additions and 464 deletions

View File

@ -36,31 +36,38 @@
# Provide a list of modules to load by default. # Provide a list of modules to load by default.
# See what other commands the user would like to run by default. # See what other commands the user would like to run by default.
# Go through conf.py options and see which ones the user would like. # Go through conf.py options and see which ones the user would like.
import sys
sys.path.insert(0, 'src')
from fix import *
from questions import *
import os import os
import imp import imp
import sys
import socket
import pprint
sys.path.insert(0, 'src')
from fix import *
from questions import *
import conf import conf
import ircdb import ircdb
import ircutils
sys.path.insert(0, conf.pluginDir) sys.path.insert(0, conf.pluginDir)
import socket
if __name__ == '__main__': if __name__ == '__main__':
fd = file('src/template.py')
template = fd.read()
fd.close()
### ###
# First things first. # First things first.
### ###
if ny('Are you an advanced Supybot/IRC user?') == 'y': if yn('Are you an advanced Supybot/IRC user?') == 'y':
advanced = True advanced = True
else: else:
advanced = False advanced = False
### ###
# Basic stuff. # Basic stuff.
### ###
name = anything('What would you like to name your config file?')
if not name.endswith('.conf'): # Server.
name += '.conf'
configfd = file(os.path.join(conf.confDir, name), 'w')
server = '' server = ''
while not server: while not server:
server = anything('What server would you like to connect to?') server = anything('What server would you like to connect to?')
@ -71,28 +78,48 @@ if __name__ == '__main__':
except: except:
print 'Sorry, but I couldn\'t find that server.' print 'Sorry, but I couldn\'t find that server.'
server = '' server = ''
if ny('Does that server require connection on a non-standard port?')=='y': if yn('Does that server require connection on a non-standard port?')=='y':
server = ':'.join(server, anything('What port is that?')) port = ''
configfd.write('Server: %s\n' % server) while not port:
if ny('Does the server require a password to connect?') == 'y': port = something('What port is that?')
try:
i = int(port)
if not (0 < i < 65536):
raise ValueError
except ValueError:
print 'That\'s not a valid port.'
port = ''
server = ':'.join((server, port))
template = template.replace('%%server%%', repr(server))
# Password.
password = ''
if yn('Does the server require a password to connect?') == 'y':
password = anything('What password would you like the bot to use?') password = anything('What password would you like the bot to use?')
configfd.write('Pass: ' + password) template = template.replace('%%password%%', repr(password))
nick = anything('What nick would you like the bot to use?')
configfd.write('Nick: %s\n' % nick) # Nick.
if advanced and ny('Would you like to set a user/ident?') == 'y': nick = something('What nick would you like the bot to use?')
while not ircutils.isNick(nick):
print 'That\'s not a valid nick.'
nick = something('What nick would you like the bot use?')
template = template.replace('%%nick%%', repr(nick))
# User/Ident.
user = nick
ident = nick
if advanced and yn('Would you like to set a user/ident?') == 'y':
user = anything('What user would you like the bot to use?') user = anything('What user would you like the bot to use?')
configfd.write('User: %s\n' % user)
ident = anything('What ident would you like the bot to use?') ident = anything('What ident would you like the bot to use?')
configfd.write('Ident: %s\n' % ident) template = template.replace('%%user%%', repr(user))
configfd.write('\n') template = template.replace('%%ident%%', repr(ident))
onStart = [] onStart = []
onStart.append('# Commands to run before connecting.') afterConnect = []
onStart.append('load AdminCommands') onStart.append('load AdminCommands')
onStart.append('load UserCommands') onStart.append('load UserCommands')
onStart.append('load ChannelCommands') onStart.append('load ChannelCommands')
onStart.append('load MiscCommands') onStart.append('load MiscCommands')
afterConnect = []
afterConnect.append('# Commands to run after connecting.')
### ###
# Modules. # Modules.
@ -141,6 +168,7 @@ if __name__ == '__main__':
postConnect = 'Would you like any other commands to run ' \ postConnect = 'Would you like any other commands to run ' \
'when the bot is finished connecting to the server?' 'when the bot is finished connecting to the server?'
afterConnect.append(anything('What command?')) afterConnect.append(anything('What command?'))
### ###
# Set owner user. # Set owner user.
### ###
@ -157,18 +185,31 @@ if __name__ == '__main__':
### ###
# Finito! # Finito!
### ###
for command in onStart: template = template.replace('%%onStart%%', pprint.pformat(onStart))
configfd.write(command) template = template.replace('%%afterConnect%%',
configfd.write('\n') pprint.pformat(afterConnect))
configfd.write('\n')
for command in afterConnect: ###
configfd.write(command) # Configuration variables in conf.py.
configfd.write('\n') ###
configfd.close() configVariables = {}
if advanced and \
yn('Would you like to modify the default config variables?')=='y':
pass
template = template.replace('%%configVariables%%',
pprint.pformat(configVariables))
filename = '%s.py' % nick
fd = open(filename, 'w')
fd.write(template)
fd.close()
os.chmod(filename, 0755)
print print
print 'You\'re done! Now run the bot with the command line:' print 'You\'re done! Now run the bot with the command line:'
print 'src/bot.py conf/%s' % name print './%s' % filename
print print
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:

278
src/OwnerCommands.py Normal file
View File

@ -0,0 +1,278 @@
#!/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 gc
import imp
import sys
import linecache
import conf
import debug
import world
import ircmsgs
import drivers
import privmsgs
import callbacks
class OwnerCommands(privmsgs.CapabilityCheckingPrivmsg):
capability = 'owner'
def __init__(self):
callbacks.Privmsg.__init__(self)
setattr(self.__class__, 'exec', self._exec)
def eval(self, irc, msg, args):
"""<string to be evaluated by the Python interpreter>"""
if conf.allowEval:
s = privmsgs.getArgs(args)
try:
irc.reply(msg, repr(eval(s)))
except Exception, e:
irc.reply(msg, debug.exnToString(e))
else:
irc.error(msg, conf.replyEvalNotAllowed)
def _exec(self, irc, msg, args):
"""<code to exec>"""
if conf.allowEval:
s = privmsgs.getArgs(args)
try:
exec s
irc.reply(msg, conf.replySuccess)
except Exception, e:
irc.reply(msg, debug.exnToString(e))
else:
irc.error(msg, conf.replyEvalNotAllowed)
def setdefaultcapability(self, irc, msg, args):
"""<capability>
Sets the default capability to be allowed for any command.
"""
capability = privmsgs.getArgs(args)
conf.defaultCapabilities[capability] = True
irc.reply(msg, conf.replySuccess)
def unsetdefaultcapability(self, irc, msg, args):
"""<capability>
Unsets the default capability for any command.
"""
capability = privmsgs.getArgs(args)
del conf.defaultCapabilities[capability]
irc.reply(msg, conf.replySuccess)
def settrace(self, irc, msg, args):
"""takes no arguments
Starts the function-tracing debug mode; beware that this makes *huge*
logfiles.
"""
sys.settrace(debug.tracer)
irc.reply(msg, conf.replySuccess)
def unsettrace(self, irc, msg, args):
"""takes no arguments
Stops the function-tracing debug mode."""
sys.settrace(None)
irc.reply(msg, conf.replySuccess)
def ircquote(self, irc, msg, args):
"""<string to be sent to the server>
Sends the raw string given to the server.
"""
s = privmsgs.getArgs(args)
try:
m = ircmsgs.IrcMsg(s)
irc.queueMsg(m)
except Exception:
debug.recoverableException()
irc.error(msg, conf.replyError)
def quit(self, irc, msg, args):
"""[<int return value>]
Exits the program with the given return value (the default is 0)
"""
try:
i = int(args[0])
except (ValueError, IndexError):
i = 0
for driver in drivers._drivers.itervalues():
driver.die()
for irc in world.ircs[:]:
irc.die()
debug.exit(i)
def flush(self, irc, msg, args):
"""takes no arguments
Runs all the periodic flushers in world.flushers.
"""
world.flush()
irc.reply(msg, conf.replySuccess)
def upkeep(self, irc, msg, args):
"""takes no arguments
Runs the standard upkeep stuff (flushes and gc.collects()).
"""
world.upkeep()
if gc.garbage:
if len(gc.garbage) < 10:
irc.reply(msg, 'Garbage! %r' % gc.garbage)
else:
irc.reply(msg, 'Garbage! %s items.' % len(gc.garbage))
else:
irc.reply(msg, conf.replySuccess)
def set(self, irc, msg, args):
"""<name> <value>
Sets the runtime variable <name> to <value>. Currently used variables
include "noflush" which, if set to true value, will prevent the
periodic flushing that normally occurs.
"""
(name, value) = privmsgs.getArgs(args, optional=1)
world.tempvars[name] = value
irc.reply(msg, conf.replySuccess)
def unset(self, irc, msg, args):
"""<name>
Unsets the value of variables set via the 'set' command.
"""
name = privmsgs.getArgs(args)
try:
del world.tempvars[name]
irc.reply(msg, conf.replySuccess)
except KeyError:
irc.error(msg, 'That variable wasn\'t set.')
def load(self, irc, msg, args):
"""<plugin>
Loads the plugin <plugin> from the plugins/ directory.
"""
name = privmsgs.getArgs(args)
for cb in irc.callbacks:
if cb.name() == name:
irc.error(msg, 'That module is already loaded.')
return
try:
moduleInfo = imp.find_module(name)
except ImportError:
irc.error(msg, 'No plugin %s exists.' % name)
return
module = imp.load_module(name, *moduleInfo)
linecache.checkcache()
callback = module.Class()
if hasattr(callback, 'configure'):
callback.configure(irc)
irc.addCallback(callback)
irc.reply(msg, conf.replySuccess)
'''
def superreload(self, irc, msg, args):
"""<module name>
Reloads a module, hopefully such that all vestiges of the old module
are gone.
"""
name = privmsgs.getArgs(args)
world.superReload(__import__(name))
irc.reply(msg, conf.replySuccess)
'''
def reload(self, irc, msg, args):
"""<callback name>
Unloads and subsequently reloads the callback by name; use the 'list'
command to see a list of the currently loaded callbacks.
"""
name = privmsgs.getArgs(args)
callbacks = irc.removeCallback(name)
if callbacks:
for callback in callbacks:
callback.die()
del callback
gc.collect()
try:
moduleInfo = imp.find_module(name)
module = imp.load_module(name, *moduleInfo)
linecache.checkcache()
callback = module.Class()
if hasattr(callback, 'configure'):
callback.configure(irc)
irc.addCallback(callback)
irc.reply(msg, conf.replySuccess)
except ImportError:
for callback in callbacks:
irc.addCallback(callback)
irc.error(msg, 'No plugin %s exists.' % name)
else:
irc.error(msg, 'There was no callback %s.' % name)
def unload(self, irc, msg, args):
"""<callback name>
Unloads the callback by name; use the 'list' command to see a list
of the currently loaded callbacks.
"""
name = privmsgs.getArgs(args)
callbacks = irc.removeCallback(name)
if callbacks:
for callback in callbacks:
callback.die()
del callback
gc.collect()
irc.reply(msg, conf.replySuccess)
else:
irc.error(msg, 'There was no callback %s' % name)
def cvsup(self, irc, msg, args):
"""takes no arguments"""
irc.reply(msg, str(os.system('cvs up')))
def say(self, irc, msg, args):
"""<channel> <text>"""
(channel, text) = privmsgs.getArgs(args, needed=2)
irc.queueMsg(ircmsgs.privmsg(channel, text))
Class = OwnerCommands
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:

View File

@ -1,119 +0,0 @@
#!/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.
###
"""
Main program file for running the bot.
"""
from fix import *
import sys
import time
import getopt
import conf
import debug
import world
import irclib
import drivers
import ircmsgs
import privmsgs
import schedule
sys.path.append(conf.pluginDir)
world.startedAt = time.time()
class ConfigAfter376(irclib.IrcCallback):
public = False
def __init__(self, commands):
self.commands = commands
def do376(self, irc, msg):
for command in self.commands:
msg = ircmsgs.privmsg(irc.nick, command, prefix=irc.prefix)
irc.queueMsg(msg)
def handleConfigFile():
nick = conf.config['nick']
user = conf.config['user']
ident = conf.config['ident']
password = conf.config['password']
irc = irclib.Irc(nick, user, ident, password)
for Class in privmsgs.standardPrivmsgModules:
callback = Class()
if hasattr(callback, 'configure'):
callback.configure(irc)
irc.addCallback(callback)
irc.addCallback(ConfigAfter376(conf.config['afterConnect']))
drivers.newDriver(conf.config['server'], irc)
def main():
(optlist, filenames) = getopt.getopt(sys.argv[1:], 'Opc:')
if len(filenames) != 1:
conf.reportConfigError('Command line', 'No configuration file given.')
for (option, argument) in optlist:
if option == '-c':
myLocals = {}
myGlobals = {}
execfile(argument, myGlobals, myLocals)
for (key, value) in myGlobals.iteritems():
setattr(conf, key, value)
for (key, value) in myLocals.iteritems():
setattr(conf, key, value)
else:
print 'Unexpected argument %s; ignoring.' % option
filename = filenames[0]
conf.processConfig(filename)
handleConfigFile()
schedule.addPeriodicEvent(world.upkeep, 300)
try:
while world.ircs:
drivers.run()
except:
try:
debug.recoverableException()
except: # It must have been deadly on purpose.
sys.exit(0)
if __name__ == '__main__':
if '-p' in sys.argv:
import profile
sys.argv.remove('-p')
profile.run('main()', '%i.prof' % time.time())
if '-O' in sys.argv:
import psyco
psyco.full()
main()
else:
main()
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:

View File

@ -443,7 +443,7 @@ class Privmsg(irclib.IrcCallback):
def configure(self, irc): def configure(self, irc):
fakeIrc = ConfigIrcProxy(irc) fakeIrc = ConfigIrcProxy(irc)
for args in conf.config['onStart']: for args in conf.commandsOnStart:
args = args[:] args = args[:]
command = args.pop(0) command = args.pop(0)
if self.isCommand(command): if self.isCommand(command):
@ -461,13 +461,14 @@ class Privmsg(irclib.IrcCallback):
irclib.IrcCallback.__call__(self, irc, msg) irclib.IrcCallback.__call__(self, irc, msg)
# Now, if there's anything in the rateLimiter... # Now, if there's anything in the rateLimiter...
msg = self.rateLimiter.get() msg = self.rateLimiter.get()
if msg: while msg:
s = addressed(irc.nick, msg) s = addressed(irc.nick, msg)
try: try:
args = tokenize(s) args = tokenize(s)
self.Proxy(irc, msg, args) self.Proxy(irc, msg, args)
except SyntaxError, e: except SyntaxError, e:
irc.queueMsg(reply(msg, str(e))) irc.queueMsg(reply(msg, str(e)))
msg = self.rateLimiter.get()
def isCommand(self, methodName): def isCommand(self, methodName):
# This function is ugly, but I don't want users to call methods like # This function is ugly, but I don't want users to call methods like
@ -496,7 +497,7 @@ class Privmsg(irclib.IrcCallback):
funcname = f.im_func.func_name funcname = f.im_func.func_name
debug.msg('%s took %s seconds' % (funcname, elapsed), 'verbose') debug.msg('%s took %s seconds' % (funcname, elapsed), 'verbose')
_r = re.compile(r'^([\w_-]+)(?:\s+|$)') _r = re.compile(r'^([\w_-]+)(?:\[|\s+|$)')
def doPrivmsg(self, irc, msg): def doPrivmsg(self, irc, msg):
s = addressed(irc.nick, msg) s = addressed(irc.nick, msg)
#debug.printf('Privmsg.doPrivmsg: s == %r' % s) #debug.printf('Privmsg.doPrivmsg: s == %r' % s)

View File

@ -197,78 +197,4 @@ driverModule = 'asyncoreDrivers'
############################### ###############################
version ='0.70.0' version ='0.70.0'
import debug
class ConfigurationDict(dict):
def __init__(self, L=()):
L = [(key.lower(), value) for (key, value) in L]
dict.__init__(self, L)
def __setitem__(self, key, value):
dict.__setitem__(self, key.lower(), value)
def __getitem__(self, key):
try:
return dict.__getitem__(self, key.lower())
except KeyError:
return ''
def __contains__(self, key):
return dict.__contains__(self, key.lower())
config = ConfigurationDict()
def reportConfigError(filename, msg):
debug.unrecoverableError('%s: %s' % (filename, msg))
def processConfig(filename):
import email
from callbacks import tokenize
try:
fd = file(filename)
m = email.message_from_file(fd)
for (k, v) in m.items():
config[k] = v
if 'nick' not in config:
reportConfigError(filename, 'No nick defined.')
if 'server' not in config:
reportConfigError(filename, 'No server defined.')
if 'user' not in config:
config['user'] = config['nick']
if 'ident' not in config:
config['ident'] = config['nick']
server = config['server']
if ':' in server:
(server, port) = server.split(':', 1)
try:
server = (server, int(port))
except ValueError:
reportConfigError(filename, 'Server has an invalid port.')
else:
server = (server, 6667)
config['server'] = server
text = m.get_payload()
while 1:
# Gotta remove all extra newlines.
newtext = text.replace('\n\n\n', '\n\n')
if newtext == text:
break
else:
text = newtext
lines = text.splitlines()
# There are 2 newlines separating the commands to be run on startup
# from the commands to be run after connecting. This separates them
# based on those newlines.
(onStart, afterConnect) = tuple(itersplit(lines,lambda s: not s,True))
config['onStart'] = [tokenize(s) for s in onStart if s and s[0] != '#']
config['afterConnect'] = [s for s in afterConnect if s and s[0] != '#']
except IOError, e:
reportConfigError(filename, e)
except email.Errors.HeaderParseError, e:
s = str(e)
problem = s[s.rfind('`')+1:-2]
msg = 'Invalid configuration format: %s' % problem
reportConfigError(filename, msg)
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:

View File

@ -31,19 +31,13 @@
from fix import * from fix import *
import gc
import os
import new import new
import sys
import imp
import linecache
import conf import conf
import debug import debug
import world import world
import ircdb import ircdb
import ircmsgs import ircmsgs
import drivers
import ircutils import ircutils
import callbacks import callbacks
@ -109,233 +103,4 @@ class CapabilityCheckingPrivmsg(callbacks.Privmsg):
else: else:
irc.error(msg, conf.replyNoCapability % self.capability) irc.error(msg, conf.replyNoCapability % self.capability)
class OwnerCommands(CapabilityCheckingPrivmsg):
capability = 'owner'
def __init__(self):
callbacks.Privmsg.__init__(self)
setattr(self.__class__, 'exec', self._exec)
def eval(self, irc, msg, args):
"""<string to be evaluated by the Python interpreter>"""
if conf.allowEval:
s = getArgs(args)
try:
irc.reply(msg, repr(eval(s)))
except Exception, e:
irc.reply(msg, debug.exnToString(e))
else:
irc.error(msg, conf.replyEvalNotAllowed)
def _exec(self, irc, msg, args):
"""<code to exec>"""
if conf.allowEval:
s = getArgs(args)
try:
exec s
irc.reply(msg, conf.replySuccess)
except Exception, e:
irc.reply(msg, debug.exnToString(e))
else:
irc.error(msg, conf.replyEvalNotAllowed)
def setdefaultcapability(self, irc, msg, args):
"""<capability>
Sets the default capability to be allowed for any command.
"""
capability = getArgs(args)
conf.defaultCapabilities[capability] = True
irc.reply(msg, conf.replySuccess)
def unsetdefaultcapability(self, irc, msg, args):
"""<capability>
Unsets the default capability for any command.
"""
capability = getArgs(args)
del conf.defaultCapabilities[capability]
irc.reply(msg, conf.replySuccess)
def settrace(self, irc, msg, args):
"""takes no arguments
Starts the function-tracing debug mode; beware that this makes *huge*
logfiles.
"""
sys.settrace(debug.tracer)
irc.reply(msg, conf.replySuccess)
def unsettrace(self, irc, msg, args):
"""takes no arguments
Stops the function-tracing debug mode."""
sys.settrace(None)
irc.reply(msg, conf.replySuccess)
def ircquote(self, irc, msg, args):
"""<string to be sent to the server>
Sends the raw string given to the server.
"""
s = getArgs(args)
try:
m = ircmsgs.IrcMsg(s)
irc.queueMsg(m)
except Exception:
debug.recoverableException()
irc.error(msg, conf.replyError)
def quit(self, irc, msg, args):
"""[<int return value>]
Exits the program with the given return value (the default is 0)
"""
try:
i = int(args[0])
except (ValueError, IndexError):
i = 0
for driver in drivers._drivers.itervalues():
driver.die()
for irc in world.ircs[:]:
irc.die()
debug.exit(i)
def flush(self, irc, msg, args):
"""takes no arguments
Runs all the periodic flushers in world.flushers.
"""
world.flush()
irc.reply(msg, conf.replySuccess)
def upkeep(self, irc, msg, args):
"""takes no arguments
Runs the standard upkeep stuff (flushes and gc.collects()).
"""
world.upkeep()
if gc.garbage:
if len(gc.garbage) < 10:
irc.reply(msg, 'Garbage! %r' % gc.garbage)
else:
irc.reply(msg, 'Garbage! %s items.' % len(gc.garbage))
else:
irc.reply(msg, conf.replySuccess)
def set(self, irc, msg, args):
"""<name> <value>
Sets the runtime variable <name> to <value>. Currently used variables
include "noflush" which, if set to true value, will prevent the
periodic flushing that normally occurs.
"""
(name, value) = getArgs(args, optional=1)
world.tempvars[name] = value
irc.reply(msg, conf.replySuccess)
def unset(self, irc, msg, args):
"""<name>
Unsets the value of variables set via the 'set' command.
"""
name = getArgs(args)
try:
del world.tempvars[name]
irc.reply(msg, conf.replySuccess)
except KeyError:
irc.error(msg, 'That variable wasn\'t set.')
def load(self, irc, msg, args):
"""<plugin>
Loads the plugin <plugin> from the plugins/ directory.
"""
name = getArgs(args)
if name in [cb.name() for cb in irc.callbacks]:
irc.error(msg, 'That module is already loaded.')
return
try:
moduleInfo = imp.find_module(name)
except ImportError:
irc.error(msg, 'No plugin %s exists.' % name)
return
module = imp.load_module(name, *moduleInfo)
linecache.checkcache()
callback = module.Class()
if hasattr(callback, 'configure'):
callback.configure(irc)
irc.addCallback(callback)
irc.reply(msg, conf.replySuccess)
'''
def superreload(self, irc, msg, args):
"""<module name>
Reloads a module, hopefully such that all vestiges of the old module
are gone.
"""
name = getArgs(args)
world.superReload(__import__(name))
irc.reply(msg, conf.replySuccess)
'''
def reload(self, irc, msg, args):
"""<callback name>
Unloads and subsequently reloads the callback by name; use the 'list'
command to see a list of the currently loaded callbacks.
"""
name = getArgs(args)
callbacks = irc.removeCallback(name)
if callbacks:
for callback in callbacks:
callback.die()
del callback
gc.collect()
try:
moduleInfo = imp.find_module(name)
module = imp.load_module(name, *moduleInfo)
linecache.checkcache()
callback = module.Class()
if hasattr(callback, 'configure'):
callback.configure(irc)
irc.addCallback(callback)
irc.reply(msg, conf.replySuccess)
except ImportError:
for callback in callbacks:
irc.addCallback(callback)
irc.error(msg, 'No plugin %s exists.' % name)
else:
irc.error(msg, 'There was no callback %s.' % name)
def unload(self, irc, msg, args):
"""<callback name>
Unloads the callback by name; use the 'list' command to see a list
of the currently loaded callbacks.
"""
name = getArgs(args)
callbacks = irc.removeCallback(name)
if callbacks:
for callback in callbacks:
callback.die()
del callback
gc.collect()
irc.reply(msg, conf.replySuccess)
else:
irc.error(msg, 'There was no callback %s' % name)
def cvsup(self, irc, msg, args):
"""takes no arguments"""
irc.reply(msg, str(os.system('cvs up')))
def say(self, irc, msg, args):
"""<channel> <text>"""
(channel, text) = getArgs(args, needed=2)
irc.queueMsg(ircmsgs.privmsg(channel, text))
standardPrivmsgModules = [OwnerCommands]
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:

193
src/template.py Executable file
View File

@ -0,0 +1,193 @@
#!/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.
###
"""
This is the template for bots. scripts/setup.py uses this file to make
customized startup files for bots.
"""
import re
import sys
import time
import optparse
started = time.time()
sys.path.insert(0, 'src')
import conf
conf.commandsOnStart = %%onStart%%
afterConnect = %%afterConnect%%
configVariables = %%configVariables%%
for (name, value) in configVariables.iteritems():
setattr(conf, name, value)
def main():
import debug
import world
import drivers
world.startedAt = started
try:
while world.ircs:
drivers.run()
except:
try:
debug.recoverableException()
except: # It must've been deadly for a reason :)
sys.exit(0)
if __name__ == '__main__':
###
# Options:
# -p (profiling)
# -O (optimizing)
# -n, --nick (nick)
# -s, --server (server)
# --startup (commands to run onStart)
# --connect (commands to run afterConnect)
# --config (configuration values)
parser = optparse.OptionParser(usage='Usage: %prog [options]',
version='supybot %s' % conf.version)
parser.add_option('-P', '--profile', action='store_true', dest='profile',
help='enables profiling')
parser.add_option('-O', action='count', dest='optimize',
help='-O optimizes asserts out of the code; ' \
'-OO optimizes asserts and uses psyco.')
parser.add_option('-n', '--nick', action='store',
dest='nick', default=%%nick%%,
help='nick the bot should use') # FIXME (quotes)
parser.add_option('-s', '--server', action='store',
dest='server', default=%%server%%,
help='server to connect to') # FIXME (quotes)
parser.add_option('-u', '--user', action='store',
dest='user', default=%%user%%,
help='full username the bot should use')
parser.add_option('-i', '--ident', action='store',
dest='ident', default=%%ident%%,
help='ident the bot should use')
parser.add_option('-p', '--password', action='store',
dest='password', default=%%password%%,
help='server password the bot should use')
parser.add_option('--startup', action='append', dest='onStart',
help='file of additional commands to run at startup.')
parser.add_option('--connect', action='append', dest='afterConnect',
help='file of additional commands to run after connect')
parser.add_option('--config', action='append', dest='conf',
help='file of configuration variables to set')
(options, args) = parser.parse_args()
if options.optimize:
__builtins__.__debug__ = False
if options.optimize > 1:
import psyco
psyco.full()
if options.onStart:
for filename in options.onStart:
fd = file(filename)
for line in fd:
conf.commandsOnStart.append(line.rstrip())
fd.close()
if options.afterConnect:
for filename in options.afterConnect:
fd = file(filename)
for line in fd:
afterConnect.append(line.rstrip())
fd.close()
assignmentRe = re.compile('\s*[:=]\s*')
if options.conf:
for filename in options.conf:
fd = file(filename)
for line in fd:
(name, valueString) = assignmentRe.split(line.rstrip(), 1)
try:
value = eval(valueString)
except Exception, e:
sys.stderr.write('Invalid configuration value: %r' % \
valueString)
sys.exit(-1)
sys.path.append(conf.pluginDir)
nick = options.nick
user = options.user
ident = options.ident
password = options.password
if ':' in options.server:
serverAndPort = options.server.split(':', 1)
serverAndPort[1] = int(serverAndPort[1])
server = tuple(serverAndPort)
else:
server = (options.server, 6667)
import irclib
import ircmsgs
import drivers
import callbacks
import OwnerCommands
class ConfigAfter376(irclib.IrcCallback):
public = False
def __init__(self, commands):
self.commands = commands
def do376(self, irc, msg):
for command in self.commands:
msg = ircmsgs.privmsg(irc.nick, command, prefix=irc.prefix)
irc.queueMsg(msg)
do377 = do376
# We pre-tokenize the commands just to save on significant amounts of work.
conf.commandsOnStart = map(callbacks.tokenize, conf.commandsOnStart)
irc = irclib.Irc(nick, user, ident, password)
callback = OwnerCommands.Class()
callback.configure(irc)
irc.addCallback(callback)
irc.addCallback(ConfigAfter376(afterConnect))
driver = drivers.newDriver(server, irc)
if options.profile:
import profile
profile.run('main()')
else:
main()
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: