mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-11-19 08:59:27 +01:00
Merge branch 'maint/0.83.4'
This commit is contained in:
commit
232aa86a1e
15
INSTALL
15
INSTALL
@ -41,17 +41,12 @@ registry file for your bot.
|
|||||||
|
|
||||||
Local Install
|
Local Install
|
||||||
|
|
||||||
You can install Supybot in a local directory by using the '--prefix'
|
You can install Supybot in a local directory by using the '--user'
|
||||||
option when running 'setup.py'. E.g., 'python setup.py install
|
option when running 'setup.py'. E.g., 'python setup.py install
|
||||||
--prefix=$HOME' to install into your home directory. You'll now have
|
--user' to install into your home directory. You'll now have
|
||||||
a $HOME/bin directory containing Supybot programs ('supybot',
|
a $HOME/.local/bin directory containing Supybot programs ('supybot',
|
||||||
'supybot-wizard', etc.) and a $HOME/lib directory containing the
|
'supybot-wizard', etc.) and a $HOME/.local/lib directory containing the
|
||||||
Supybot libraries. It is also recommended that you setup a proper
|
Supybot libraries.
|
||||||
PYTHONPATH environment variable in your shell's init file.
|
|
||||||
|
|
||||||
bash -- 'export PYTHONPATH=$HOME/lib/python2.x/site-packages'
|
|
||||||
|
|
||||||
(t)csh -- 'setenv PYTHONPATH $HOME/lib/python2.x/site-packages'
|
|
||||||
|
|
||||||
Windows
|
Windows
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
###
|
###
|
||||||
# Copyright (c) 2002-2005, Jeremiah Fincher
|
# Copyright (c) 2002-2005, Jeremiah Fincher
|
||||||
# Copyright (c) 2009, James Vega
|
# Copyright (c) 2009-2012, James McCoy
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without
|
# Redistribution and use in source and binary forms, with or without
|
||||||
@ -153,14 +153,7 @@ class Channel(callbacks.Plugin):
|
|||||||
halfop = wrap(halfop, ['halfop', ('haveOp', 'halfop someone'),
|
halfop = wrap(halfop, ['halfop', ('haveOp', 'halfop someone'),
|
||||||
any('nickInChannel')])
|
any('nickInChannel')])
|
||||||
|
|
||||||
def voice(self, irc, msg, args, channel, nicks):
|
def _voice(self, irc, msg, args, channel, nicks, fn):
|
||||||
"""[<channel>] [<nick> ...]
|
|
||||||
|
|
||||||
If you have the #channel,voice capability, this will voice all the
|
|
||||||
<nick>s you provide. If you don't provide any <nick>s, this will
|
|
||||||
voice you. <channel> is only necessary if the message isn't sent in the
|
|
||||||
channel itself.
|
|
||||||
"""
|
|
||||||
if nicks:
|
if nicks:
|
||||||
if len(nicks) == 1 and msg.nick in nicks:
|
if len(nicks) == 1 and msg.nick in nicks:
|
||||||
capability = 'voice'
|
capability = 'voice'
|
||||||
@ -172,10 +165,20 @@ class Channel(callbacks.Plugin):
|
|||||||
capability = ircdb.makeChannelCapability(channel, capability)
|
capability = ircdb.makeChannelCapability(channel, capability)
|
||||||
if ircdb.checkCapability(msg.prefix, capability):
|
if ircdb.checkCapability(msg.prefix, capability):
|
||||||
def f(L):
|
def f(L):
|
||||||
return ircmsgs.voices(channel, L)
|
return fn(channel, L)
|
||||||
self._sendMsgs(irc, nicks, f)
|
self._sendMsgs(irc, nicks, f)
|
||||||
else:
|
else:
|
||||||
irc.errorNoCapability(capability)
|
irc.errorNoCapability(capability)
|
||||||
|
|
||||||
|
def voice(self, irc, msg, args, channel, nicks):
|
||||||
|
"""[<channel>] [<nick> ...]
|
||||||
|
|
||||||
|
If you have the #channel,voice capability, this will voice all the
|
||||||
|
<nick>s you provide. If you don't provide any <nick>s, this will
|
||||||
|
voice you. <channel> is only necessary if the message isn't sent in the
|
||||||
|
channel itself.
|
||||||
|
"""
|
||||||
|
self._voice(irc, msg, args, channel, nicks, ircmsgs.voices)
|
||||||
voice = wrap(voice, ['channel', ('haveOp', 'voice someone'),
|
voice = wrap(voice, ['channel', ('haveOp', 'voice someone'),
|
||||||
any('nickInChannel')])
|
any('nickInChannel')])
|
||||||
|
|
||||||
@ -228,12 +231,8 @@ class Channel(callbacks.Plugin):
|
|||||||
irc.error('I cowardly refuse to devoice myself. If you really '
|
irc.error('I cowardly refuse to devoice myself. If you really '
|
||||||
'want me devoiced, tell me to op you and then devoice '
|
'want me devoiced, tell me to op you and then devoice '
|
||||||
'me yourself.', Raise=True)
|
'me yourself.', Raise=True)
|
||||||
if not nicks:
|
self._voice(irc, msg, args, channel, nicks, ircmsgs.devoices)
|
||||||
nicks = [msg.nick]
|
devoice = wrap(devoice, ['channel', ('haveOp', 'devoice someone'),
|
||||||
def f(L):
|
|
||||||
return ircmsgs.devoices(channel, L)
|
|
||||||
self._sendMsgs(irc, nicks, f)
|
|
||||||
devoice = wrap(devoice, ['voice', ('haveOp', 'devoice someone'),
|
|
||||||
any('nickInChannel')])
|
any('nickInChannel')])
|
||||||
|
|
||||||
def cycle(self, irc, msg, args, channel):
|
def cycle(self, irc, msg, args, channel):
|
||||||
|
@ -205,11 +205,19 @@ class ChannelTestCase(ChannelPluginTestCase):
|
|||||||
|
|
||||||
def testIgnore(self):
|
def testIgnore(self):
|
||||||
orig = conf.supybot.protocols.irc.banmask()
|
orig = conf.supybot.protocols.irc.banmask()
|
||||||
|
def ignore(given, expect=None):
|
||||||
|
if expect is None:
|
||||||
|
expect = given
|
||||||
|
self.assertNotError('channel ignore add %s' % given)
|
||||||
|
self.assertResponse('channel ignore list', "'%s'" % expect)
|
||||||
|
self.assertNotError('channel ignore remove %s' % expect)
|
||||||
|
self.assertRegexp('channel ignore list', 'not currently')
|
||||||
try:
|
try:
|
||||||
|
ignore('foo!bar@baz', '*!bar@baz')
|
||||||
|
ignore('foo!*@*')
|
||||||
conf.supybot.protocols.irc.banmask.setValue(['exact'])
|
conf.supybot.protocols.irc.banmask.setValue(['exact'])
|
||||||
self.assertNotError('channel ignore add foo!bar@baz')
|
ignore('foo!bar@baz')
|
||||||
self.assertResponse('channel ignore list', "'foo!bar@baz'")
|
ignore('foo!*@*')
|
||||||
self.assertNotError('channel ignore remove foo!bar@baz')
|
|
||||||
self.assertError('ban add not!a.hostmask')
|
self.assertError('ban add not!a.hostmask')
|
||||||
finally:
|
finally:
|
||||||
conf.supybot.protocols.irc.banmask.setValue(orig)
|
conf.supybot.protocols.irc.banmask.setValue(orig)
|
||||||
|
@ -354,7 +354,8 @@ class Filter(callbacks.Plugin):
|
|||||||
if c == ' ':
|
if c == ' ':
|
||||||
return c
|
return c
|
||||||
if fg is None:
|
if fg is None:
|
||||||
fg = str(random.randint(2, 15)).zfill(2)
|
fg = random.randint(2, 15)
|
||||||
|
fg = str(fg).zfill(2)
|
||||||
return '\x03%s%s' % (fg, c)
|
return '\x03%s%s' % (fg, c)
|
||||||
|
|
||||||
def colorize(self, irc, msg, args, text):
|
def colorize(self, irc, msg, args, text):
|
||||||
|
@ -103,6 +103,8 @@ class Math(callbacks.Plugin):
|
|||||||
_mathEnv['abs'] = abs
|
_mathEnv['abs'] = abs
|
||||||
_mathEnv['max'] = max
|
_mathEnv['max'] = max
|
||||||
_mathEnv['min'] = min
|
_mathEnv['min'] = min
|
||||||
|
_mathSafeEnv = dict([(x,y) for x,y in _mathEnv.items()
|
||||||
|
if x not in ['factorial']])
|
||||||
_mathRe = re.compile(r'((?:(?<![A-Fa-f\d)])-)?'
|
_mathRe = re.compile(r'((?:(?<![A-Fa-f\d)])-)?'
|
||||||
r'(?:0x[A-Fa-f\d]+|'
|
r'(?:0x[A-Fa-f\d]+|'
|
||||||
r'0[0-7]+|'
|
r'0[0-7]+|'
|
||||||
@ -191,7 +193,7 @@ class Math(callbacks.Plugin):
|
|||||||
text = self._mathRe.sub(handleMatch, text)
|
text = self._mathRe.sub(handleMatch, text)
|
||||||
try:
|
try:
|
||||||
self.log.info('evaluating %q from %s', text, msg.prefix)
|
self.log.info('evaluating %q from %s', text, msg.prefix)
|
||||||
x = complex(eval(text, self._mathEnv, self._mathEnv))
|
x = complex(eval(text, self._mathSafeEnv, self._mathSafeEnv))
|
||||||
irc.reply(self._complexToString(x))
|
irc.reply(self._complexToString(x))
|
||||||
except OverflowError:
|
except OverflowError:
|
||||||
maxFloat = math.ldexp(0.9999999999999999, 1024)
|
maxFloat = math.ldexp(0.9999999999999999, 1024)
|
||||||
|
@ -110,6 +110,7 @@ class MathTestCase(PluginTestCase):
|
|||||||
self.assertNotError('calc (1600 * 1200) - 2*(1024*1280)')
|
self.assertNotError('calc (1600 * 1200) - 2*(1024*1280)')
|
||||||
self.assertNotError('calc 3-2*4')
|
self.assertNotError('calc 3-2*4')
|
||||||
self.assertNotError('calc (1600 * 1200)-2*(1024*1280)')
|
self.assertNotError('calc (1600 * 1200)-2*(1024*1280)')
|
||||||
|
self.assertError('calc factorial(99)')
|
||||||
|
|
||||||
def testCalcNoNameError(self):
|
def testCalcNoNameError(self):
|
||||||
self.assertNotRegexp('calc foobar(x)', 'NameError')
|
self.assertNotRegexp('calc foobar(x)', 'NameError')
|
||||||
@ -134,6 +135,7 @@ class MathTestCase(PluginTestCase):
|
|||||||
self.assertResponse('icalc 1^1', '0')
|
self.assertResponse('icalc 1^1', '0')
|
||||||
self.assertResponse('icalc 10**24', '1' + '0'*24)
|
self.assertResponse('icalc 10**24', '1' + '0'*24)
|
||||||
self.assertRegexp('icalc 49/6', '8.16')
|
self.assertRegexp('icalc 49/6', '8.16')
|
||||||
|
self.assertNotError('icalc factorial(99)')
|
||||||
|
|
||||||
def testRpn(self):
|
def testRpn(self):
|
||||||
self.assertResponse('rpn 5 2 +', '7')
|
self.assertResponse('rpn 5 2 +', '7')
|
||||||
|
@ -47,7 +47,7 @@ class Success(plugins.ChannelIdDatabasePlugin):
|
|||||||
self.originalClass = conf.supybot.replies.success.__class__
|
self.originalClass = conf.supybot.replies.success.__class__
|
||||||
class MySuccessClass(self.originalClass):
|
class MySuccessClass(self.originalClass):
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
ret = pluginSelf.db.random(pluginSelf.target)
|
ret = pluginSelf.db.random(dynamic.msg.args[0])
|
||||||
if ret is None:
|
if ret is None:
|
||||||
try:
|
try:
|
||||||
self.__class__ = pluginSelf.originalClass
|
self.__class__ = pluginSelf.originalClass
|
||||||
@ -68,14 +68,6 @@ class Success(plugins.ChannelIdDatabasePlugin):
|
|||||||
self.__parent.die()
|
self.__parent.die()
|
||||||
conf.supybot.replies.success.__class__ = self.originalClass
|
conf.supybot.replies.success.__class__ = self.originalClass
|
||||||
|
|
||||||
def inFilter(self, irc, msg):
|
|
||||||
# We need the target, but we need it before Owner.doPrivmsg is called,
|
|
||||||
# so this seems like the only way to do it.
|
|
||||||
self.target = msg.args[0]
|
|
||||||
return msg
|
|
||||||
|
|
||||||
|
|
||||||
Class = Success
|
Class = Success
|
||||||
|
|
||||||
|
|
||||||
# vim:set shiftwidth=4 softtabstop=8 expandtab textwidth=78:
|
# vim:set shiftwidth=4 softtabstop=8 expandtab textwidth=78:
|
||||||
|
@ -4,6 +4,9 @@ import os
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import shutil
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
from optparse import OptionParser
|
||||||
|
|
||||||
def firstLines(filename, n):
|
def firstLines(filename, n):
|
||||||
fd = file(filename)
|
fd = file(filename)
|
||||||
@ -11,6 +14,7 @@ def firstLines(filename, n):
|
|||||||
while n:
|
while n:
|
||||||
n -= 1
|
n -= 1
|
||||||
lines.append(fd.readline().rstrip('\r\n'))
|
lines.append(fd.readline().rstrip('\r\n'))
|
||||||
|
fd.close()
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
def firstLine(filename):
|
def firstLine(filename):
|
||||||
@ -20,62 +24,64 @@ def error(s):
|
|||||||
sys.stderr.write(s+'\n')
|
sys.stderr.write(s+'\n')
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
def system(sh, errmsg=None):
|
def system(sh, errmsg=None, **kwargs):
|
||||||
if errmsg is None:
|
if errmsg is None:
|
||||||
|
if isinstance(sh, basestring):
|
||||||
errmsg = repr(sh)
|
errmsg = repr(sh)
|
||||||
ret = os.system(sh)
|
else:
|
||||||
|
errmsg = repr(' '.join(sh))
|
||||||
|
ret = subprocess.call(sh, **kwargs)
|
||||||
if ret:
|
if ret:
|
||||||
error(errmsg + ' (error code: %s)' % ret)
|
error(errmsg + ' (error code: %s)' % ret)
|
||||||
|
|
||||||
def usage():
|
|
||||||
error('Usage: %s [-s|-n] <sf username> <version>\nSpecify -s to pass it on '
|
|
||||||
'to the relevant git commands.\nSpecify -n to perform a dry-run '
|
|
||||||
'release. No commits or tags are pushed and no files are uploaded.'
|
|
||||||
'\nMust be called from a git checkout.'
|
|
||||||
% sys.argv[0])
|
|
||||||
|
|
||||||
def checkGitRepo():
|
def checkGitRepo():
|
||||||
system('test "$(git rev-parse --is-inside-work-tree)" = "true"',
|
system('test "$(git rev-parse --is-inside-work-tree)" = "true"',
|
||||||
'Must be run from a git checkout.')
|
'Must be run from a git checkout.',
|
||||||
|
shell=True)
|
||||||
system('test "$(git rev-parse --show-cdup >/dev/null)" = ""',
|
system('test "$(git rev-parse --show-cdup >/dev/null)" = ""',
|
||||||
'Must be run from the top-level directory of the git checkout.')
|
'Must be run from the top-level directory of the git checkout.',
|
||||||
|
shell=True)
|
||||||
system('git rev-parse --verify HEAD >/dev/null '
|
system('git rev-parse --verify HEAD >/dev/null '
|
||||||
'&& git update-index --refresh'
|
'&& git update-index --refresh'
|
||||||
'&& git diff-files --quiet'
|
'&& git diff-files --quiet'
|
||||||
'&& git diff-index --cached --quiet HEAD --',
|
'&& git diff-index --cached --quiet HEAD --',
|
||||||
'Your tree is unclean. Can\'t run from here.')
|
'Your tree is unclean. Can\'t run from here.',
|
||||||
|
shell=True)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if len(sys.argv) < 3 or len(sys.argv) > 5:
|
usage = 'usage: %prog [options] <username> <version>'
|
||||||
usage()
|
parser = OptionParser(usage=usage)
|
||||||
|
parser.set_defaults(sign=False, verbose=False, branch='master')
|
||||||
|
parser.add_option('-s', '--sign', action='store_true', dest='sign',
|
||||||
|
help='Pass on -s to relevant git commands')
|
||||||
|
parser.add_option('-n', '--dry-run', action='store_true', dest='dry_run',
|
||||||
|
help='Build the release, but do not push to the git '
|
||||||
|
'remote or upload the release archives.')
|
||||||
|
parser.add_option('-b', '--branch', metavar='BRANCH', dest='branch',
|
||||||
|
help='Branch to use for the release. Default: %default')
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
if len(args) != 2:
|
||||||
|
parser.error('Both username and version must be specified')
|
||||||
|
|
||||||
|
(u, v) = args
|
||||||
|
if not re.match(r'^\d+\.\d+\.\d+(\.\d+)?\w*$', v):
|
||||||
|
parser.error('Invalid version string: '
|
||||||
|
'must be of the form MAJOR.MINOR.PATCHLEVEL')
|
||||||
|
|
||||||
checkGitRepo()
|
checkGitRepo()
|
||||||
|
|
||||||
sign = ''
|
sign = options.sign
|
||||||
dryrun = False
|
dryrun = options.dry_run
|
||||||
while len(sys.argv) > 3:
|
branch = options.branch
|
||||||
if sys.argv[1] == '-s':
|
|
||||||
sign = '-s'
|
|
||||||
sys.argv.pop(1)
|
|
||||||
elif sys.argv[1] == '-n':
|
|
||||||
dryrun = True
|
|
||||||
sys.argv.pop(1)
|
|
||||||
else:
|
|
||||||
usage()
|
|
||||||
|
|
||||||
print 'Check version string for validity.'
|
|
||||||
(u, v) = sys.argv[1:]
|
|
||||||
if not re.match(r'^\d+\.\d+\.\d+(\.\d+)?\w*$', v):
|
|
||||||
error('Invalid version string: '
|
|
||||||
'must be of the form MAJOR.MINOR.PATCHLEVEL.')
|
|
||||||
|
|
||||||
if os.path.exists('supybot'):
|
if os.path.exists('supybot'):
|
||||||
error('I need to make the directory "supybot" but it already exists.'
|
error('I need to make the directory "supybot" but it already exists.'
|
||||||
' Change to an appropriate directory or remove the supybot '
|
' Change to an appropriate directory or remove the supybot '
|
||||||
'directory to continue.')
|
'directory to continue.')
|
||||||
print 'Checking out fresh tree from git.'
|
print 'Checking out fresh tree from git.'
|
||||||
system('git clone git+ssh://%s@supybot.git.sourceforge.net/gitroot/supybot'
|
repo = 'git+ssh://%s@supybot.git.sourceforge.net/gitroot/supybot/supybot' % u
|
||||||
% u)
|
system(['git', 'clone', '-b', branch, repo])
|
||||||
os.chdir('supybot')
|
os.chdir('supybot')
|
||||||
|
|
||||||
print 'Checking RELNOTES version line.'
|
print 'Checking RELNOTES version line.'
|
||||||
@ -90,38 +96,47 @@ if __name__ == '__main__':
|
|||||||
error('Invalid third line in ChangeLog.')
|
error('Invalid third line in ChangeLog.')
|
||||||
|
|
||||||
print 'Updating version in version files.'
|
print 'Updating version in version files.'
|
||||||
versionFiles = ('src/conf.py', 'scripts/supybot', 'setup.py')
|
versionFiles = ['src/version.py']
|
||||||
for fn in versionFiles:
|
for fn in versionFiles:
|
||||||
sh = 'perl -pi -e "s/^version\s*=.*/version = \'%s\'/" %s' % (v, fn)
|
sh = ['perl', '-pi', '-e', 's/^version\s*=.*/version = \'%s\'/' % v, fn]
|
||||||
system(sh, 'Error changing version in %s' % fn)
|
system(sh, 'Error changing version in %s' % fn)
|
||||||
system('git commit %s -m \'Updated to %s.\' %s'
|
commit = ['git', 'commit']
|
||||||
% (sign, v, ' '.join(versionFiles)))
|
if sign:
|
||||||
|
commit.append('-s')
|
||||||
|
system(commit + ['-m', 'Updated to %s.' % v] + versionFiles)
|
||||||
|
|
||||||
print 'Tagging release.'
|
print 'Tagging release.'
|
||||||
system('git tag %s -m "Release %s" %s' % (sign or '-a', v, v))
|
tag = ['git', 'tag']
|
||||||
|
if sign:
|
||||||
|
tag.append('-s')
|
||||||
|
system(tag + ['-m', "Release %s" % v, 'v%s' % v])
|
||||||
|
|
||||||
print 'Committing %s+git to version files.' % v
|
print 'Committing %s+git to version files.' % v
|
||||||
for fn in versionFiles:
|
for fn in versionFiles:
|
||||||
sh = 'perl -pi -e "s/^version\s*=.*/version = \'%s\'/" %s' % \
|
system(['perl', '-pi', '-e',
|
||||||
(v + '+git', fn)
|
's/^version\s*=.*/version = \'%s+git\'/' % v, fn],
|
||||||
system(sh, 'Error changing version in %s' % fn)
|
'Error changing version in %s' % fn)
|
||||||
system('git commit %s -m \'Updated to %s+git.\' %s'
|
system(commit + ['-m', 'Updated to %s+git.' % v] + versionFiles)
|
||||||
% (sign, v, ' '.join(versionFiles)))
|
|
||||||
|
|
||||||
if not dryrun:
|
if not dryrun:
|
||||||
print 'Pushing commits and tag.'
|
print 'Pushing commits and tag.'
|
||||||
system('git push origin master')
|
system(['git', 'push', 'origin', branch])
|
||||||
system('git push --tags')
|
system(['git', 'push', '--tags'])
|
||||||
|
|
||||||
|
archive = ['git', 'archive', '--prefix=Supybot-%s/' % v]
|
||||||
print 'Creating tarball (gzip).'
|
print 'Creating tarball (gzip).'
|
||||||
system('git archive --prefix=Supybot-%s/ --format=tar %s '
|
system(archive + ['-o', '../Supybot-%s.tar.gz' % v,
|
||||||
'| gzip -c >../Supybot-%s.tar.gz' % (v, v, v))
|
'--format=tgz', 'v%s' % v])
|
||||||
|
|
||||||
|
system(['git', 'config', 'tar.bz2.command', 'bzip2 -c'])
|
||||||
|
|
||||||
print 'Creating tarball (bzip2).'
|
print 'Creating tarball (bzip2).'
|
||||||
system('git archive --prefix=Supybot-%s/ --format=tar %s '
|
system(archive + ['-o', '../Supybot-%s.tar.bz2' % v,
|
||||||
'| bzip2 -c >../Supybot-%s.tar.bz2' % (v, v, v))
|
'--format=bz2', 'v%s' % v])
|
||||||
|
|
||||||
print 'Creating zip.'
|
print 'Creating zip.'
|
||||||
system('git archive --prefix=Supybot-%s/ --format=zip %s '
|
system(archive + ['-o', '../Supybot-%s.zip' % v,
|
||||||
'>../Supybot-%s.zip' % (v, v, v))
|
'--format=zip', 'v%s' % v])
|
||||||
|
|
||||||
os.chdir('..')
|
os.chdir('..')
|
||||||
shutil.rmtree('supybot')
|
shutil.rmtree('supybot')
|
||||||
|
@ -65,6 +65,8 @@ import supybot.utils as utils
|
|||||||
import supybot.registry as registry
|
import supybot.registry as registry
|
||||||
import supybot.questions as questions
|
import supybot.questions as questions
|
||||||
|
|
||||||
|
from supybot.version import version
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
import supybot.conf as conf
|
import supybot.conf as conf
|
||||||
import supybot.world as world
|
import supybot.world as world
|
||||||
@ -125,7 +127,6 @@ def main():
|
|||||||
log.info('Total CPU time taken: %s seconds.', user+system)
|
log.info('Total CPU time taken: %s seconds.', user+system)
|
||||||
log.info('No more Irc objects, exiting.')
|
log.info('No more Irc objects, exiting.')
|
||||||
|
|
||||||
version = '0.83.4.1+git'
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
parser = optparse.OptionParser(usage='Usage: %prog [options] configFile',
|
parser = optparse.OptionParser(usage='Usage: %prog [options] configFile',
|
||||||
version='Supybot %s' % version)
|
version='Supybot %s' % version)
|
||||||
@ -296,7 +297,7 @@ if __name__ == '__main__':
|
|||||||
log.error('Could not remove pid file: %s', e)
|
log.error('Could not remove pid file: %s', e)
|
||||||
atexit.register(removePidFile)
|
atexit.register(removePidFile)
|
||||||
except EnvironmentError, e:
|
except EnvironmentError, e:
|
||||||
log.fatal('Error opening/writing pid file %s: %s', pidFile, e)
|
log.critical('Error opening/writing pid file %s: %s', pidFile, e)
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
conf.allowDefaultOwner = options.allowDefaultOwner
|
conf.allowDefaultOwner = options.allowDefaultOwner
|
||||||
|
5
setup.py
5
setup.py
@ -47,6 +47,8 @@ import glob
|
|||||||
import shutil
|
import shutil
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
|
from src.version import version
|
||||||
|
|
||||||
plugins = [s for s in os.listdir('plugins') if
|
plugins = [s for s in os.listdir('plugins') if
|
||||||
os.path.exists(os.path.join('plugins', s, 'plugin.py'))]
|
os.path.exists(os.path.join('plugins', s, 'plugin.py'))]
|
||||||
|
|
||||||
@ -116,13 +118,12 @@ package_dir = {'supybot': 'src',
|
|||||||
for plugin in plugins:
|
for plugin in plugins:
|
||||||
package_dir['supybot.plugins.' + plugin] = 'plugins/' + plugin
|
package_dir['supybot.plugins.' + plugin] = 'plugins/' + plugin
|
||||||
|
|
||||||
version = '0.83.4.1+git'
|
|
||||||
setup(
|
setup(
|
||||||
# Metadata
|
# Metadata
|
||||||
name='supybot',
|
name='supybot',
|
||||||
version=version,
|
version=version,
|
||||||
author='Jeremy Fincher',
|
author='Jeremy Fincher',
|
||||||
url='http://supybot.com/',
|
url='http://sourceforge.net/projects/supybot/',
|
||||||
author_email='jemfinch@supybot.com',
|
author_email='jemfinch@supybot.com',
|
||||||
download_url='http://www.sf.net/project/showfiles.php?group_id=58965',
|
download_url='http://www.sf.net/project/showfiles.php?group_id=58965',
|
||||||
description='A flexible and extensible Python IRC bot and framework.',
|
description='A flexible and extensible Python IRC bot and framework.',
|
||||||
|
@ -465,13 +465,15 @@ class RichReplyMethods(object):
|
|||||||
if isinstance(capability, basestring): # checkCommandCapability!
|
if isinstance(capability, basestring): # checkCommandCapability!
|
||||||
log.warning('Denying %s for lacking %q capability.',
|
log.warning('Denying %s for lacking %q capability.',
|
||||||
self.msg.prefix, capability)
|
self.msg.prefix, capability)
|
||||||
if not self._getConfig(conf.supybot.reply.error.noCapability):
|
# noCapability means "don't send a specific capability error
|
||||||
|
# message" not "don't send a capability error message at all", like
|
||||||
|
# one would think
|
||||||
|
if self._getConfig(conf.supybot.reply.error.noCapability):
|
||||||
|
v = self._getConfig(conf.supybot.replies.genericNoCapability)
|
||||||
|
else:
|
||||||
v = self._getConfig(conf.supybot.replies.noCapability)
|
v = self._getConfig(conf.supybot.replies.noCapability)
|
||||||
s = self.__makeReply(v % capability, s)
|
s = self.__makeReply(v % capability, s)
|
||||||
return self._error(s, **kwargs)
|
return self._error(s, **kwargs)
|
||||||
else:
|
|
||||||
log.debug('Not sending capability error, '
|
|
||||||
'supybot.reply.error.noCapability is False.')
|
|
||||||
else:
|
else:
|
||||||
log.warning('Denying %s for some unspecified capability '
|
log.warning('Denying %s for some unspecified capability '
|
||||||
'(or a default).', self.msg.prefix)
|
'(or a default).', self.msg.prefix)
|
||||||
@ -1167,7 +1169,12 @@ class Commands(BasePlugin):
|
|||||||
method(irc, msg, *args, **kwargs)
|
method(irc, msg, *args, **kwargs)
|
||||||
|
|
||||||
def _callCommand(self, command, irc, msg, *args, **kwargs):
|
def _callCommand(self, command, irc, msg, *args, **kwargs):
|
||||||
self.log.info('%s called by %q.', formatCommand(command), msg.prefix)
|
if irc.nick == msg.args[0]:
|
||||||
|
self.log.info('%s called in private by %q.', formatCommand(command),
|
||||||
|
msg.prefix)
|
||||||
|
else:
|
||||||
|
self.log.info('%s called on %s by %q.', formatCommand(command),
|
||||||
|
msg.args[0], msg.prefix)
|
||||||
# XXX I'm being extra-special-careful here, but we need to refactor
|
# XXX I'm being extra-special-careful here, but we need to refactor
|
||||||
# this.
|
# this.
|
||||||
try:
|
try:
|
||||||
|
@ -40,7 +40,7 @@ import supybot.ircutils as ircutils
|
|||||||
###
|
###
|
||||||
# version: This should be pretty obvious.
|
# version: This should be pretty obvious.
|
||||||
###
|
###
|
||||||
version = '0.83.4.1+git'
|
from supybot.version import version
|
||||||
|
|
||||||
###
|
###
|
||||||
# *** The following variables are affected by command-line options. They are
|
# *** The following variables are affected by command-line options. They are
|
||||||
@ -949,6 +949,9 @@ class Banmask(registry.SpaceSeparatedSetOfStrings):
|
|||||||
bhost = host
|
bhost = host
|
||||||
elif option == 'exact':
|
elif option == 'exact':
|
||||||
return hostmask
|
return hostmask
|
||||||
|
if (bnick, buser, bhost) == ('*', '*', '*') and \
|
||||||
|
ircutils.isUserHostmask(hostmask):
|
||||||
|
return hostmask
|
||||||
return ircutils.joinHostmask(bnick, buser, bhost)
|
return ircutils.joinHostmask(bnick, buser, bhost)
|
||||||
|
|
||||||
registerChannelValue(supybot.protocols.irc, 'banmask',
|
registerChannelValue(supybot.protocols.irc, 'banmask',
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
Module for some slight database-independence for simple databases.
|
Module for some slight database-independence for simple databases.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
import csv
|
import csv
|
||||||
import math
|
import math
|
||||||
|
|
||||||
@ -113,7 +114,7 @@ class DirMapping(MappingInterface):
|
|||||||
def _makeFilename(self, id):
|
def _makeFilename(self, id):
|
||||||
return os.path.join(self.dirname, str(id))
|
return os.path.join(self.dirname, str(id))
|
||||||
|
|
||||||
def get(id):
|
def get(self, id):
|
||||||
try:
|
try:
|
||||||
fd = file(self._makeFilename(id))
|
fd = file(self._makeFilename(id))
|
||||||
return fd.read()
|
return fd.read()
|
||||||
@ -122,7 +123,7 @@ class DirMapping(MappingInterface):
|
|||||||
exn.realException = e
|
exn.realException = e
|
||||||
raise exn
|
raise exn
|
||||||
|
|
||||||
def set(id, s):
|
def set(self, id, s):
|
||||||
fd = file(self._makeFilename(id), 'w')
|
fd = file(self._makeFilename(id), 'w')
|
||||||
fd.write(s)
|
fd.write(s)
|
||||||
fd.close()
|
fd.close()
|
||||||
|
@ -155,9 +155,6 @@ class SupyReconnectingFactory(ReconnectingClientFactory, drivers.ServersMixin):
|
|||||||
return protocol
|
return protocol
|
||||||
|
|
||||||
Driver = SupyReconnectingFactory
|
Driver = SupyReconnectingFactory
|
||||||
|
|
||||||
try:
|
|
||||||
ignore(poller)
|
|
||||||
except NameError:
|
|
||||||
poller = TwistedRunnerDriver()
|
poller = TwistedRunnerDriver()
|
||||||
|
|
||||||
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|
||||||
|
@ -240,7 +240,7 @@ class ChannelState(utils.python.Object):
|
|||||||
self.users = ircutils.IrcSet()
|
self.users = ircutils.IrcSet()
|
||||||
self.voices = ircutils.IrcSet()
|
self.voices = ircutils.IrcSet()
|
||||||
self.halfops = ircutils.IrcSet()
|
self.halfops = ircutils.IrcSet()
|
||||||
self.modes = ircutils.IrcDict()
|
self.modes = {}
|
||||||
|
|
||||||
def isOp(self, nick):
|
def isOp(self, nick):
|
||||||
return nick in self.ops
|
return nick in self.ops
|
||||||
@ -405,10 +405,10 @@ class IrcState(IrcCommandDispatcher):
|
|||||||
"""Handles parsing the 004 reply
|
"""Handles parsing the 004 reply
|
||||||
|
|
||||||
Supported user and channel modes are cached"""
|
Supported user and channel modes are cached"""
|
||||||
# msg.args = [server, ircd-version, umodes, modes,
|
# msg.args = [nick, server, ircd-version, umodes, modes,
|
||||||
# modes that require arguments? (non-standard)]
|
# modes that require arguments? (non-standard)]
|
||||||
self.supported['umodes'] = msg.args[2]
|
self.supported['umodes'] = msg.args[3]
|
||||||
self.supported['chanmodes'] = msg.args[3]
|
self.supported['chanmodes'] = msg.args[4]
|
||||||
|
|
||||||
_005converters = utils.InsensitivePreservingDict({
|
_005converters = utils.InsensitivePreservingDict({
|
||||||
'modes': int,
|
'modes': int,
|
||||||
|
@ -519,11 +519,11 @@ def unbans(channel, hostmasks, prefix='', msg=None):
|
|||||||
if conf.supybot.protocols.irc.strictRfc():
|
if conf.supybot.protocols.irc.strictRfc():
|
||||||
assert isChannel(channel), repr(channel)
|
assert isChannel(channel), repr(channel)
|
||||||
assert all(isUserHostmask, hostmasks), hostmasks
|
assert all(isUserHostmask, hostmasks), hostmasks
|
||||||
|
modes = [('-b', s) for s in hostmasks]
|
||||||
if msg and not prefix:
|
if msg and not prefix:
|
||||||
prefix = msg.prefix
|
prefix = msg.prefix
|
||||||
return IrcMsg(prefix=prefix, command='MODE', msg=msg,
|
return IrcMsg(prefix=prefix, command='MODE',
|
||||||
args=(channel, '-' + ('b'*len(hostmasks)),
|
args=[channel] + ircutils.joinModes(modes), msg=msg)
|
||||||
' '.join(hostmasks)))
|
|
||||||
|
|
||||||
def kick(channel, nick, s='', prefix='', msg=None):
|
def kick(channel, nick, s='', prefix='', msg=None):
|
||||||
"""Returns a KICK to kick nick from channel with the message msg."""
|
"""Returns a KICK to kick nick from channel with the message msg."""
|
||||||
|
@ -406,10 +406,15 @@ class FormatParser(object):
|
|||||||
i = 0
|
i = 0
|
||||||
setI = False
|
setI = False
|
||||||
c = self.getChar()
|
c = self.getChar()
|
||||||
while c.isdigit() and i < 100:
|
while c.isdigit():
|
||||||
|
j = i * 10
|
||||||
|
j += int(c)
|
||||||
|
if j >= 16:
|
||||||
|
self.ungetChar(c)
|
||||||
|
break
|
||||||
|
else:
|
||||||
setI = True
|
setI = True
|
||||||
i *= 10
|
i = j
|
||||||
i += int(c)
|
|
||||||
c = self.getChar()
|
c = self.getChar()
|
||||||
self.ungetChar(c)
|
self.ungetChar(c)
|
||||||
if setI:
|
if setI:
|
||||||
@ -422,6 +427,8 @@ class FormatParser(object):
|
|||||||
c = self.getChar()
|
c = self.getChar()
|
||||||
if c == ',':
|
if c == ',':
|
||||||
context.bg = self.getInt()
|
context.bg = self.getInt()
|
||||||
|
else:
|
||||||
|
self.ungetChar(c)
|
||||||
|
|
||||||
def wrap(s, length):
|
def wrap(s, length):
|
||||||
processed = []
|
processed = []
|
||||||
|
@ -116,12 +116,12 @@ def close(registry, filename, private=True):
|
|||||||
try:
|
try:
|
||||||
x = value.__class__(value._default, value._help)
|
x = value.__class__(value._default, value._help)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
exception('Exception instantiating default for %s:',
|
exception('Exception instantiating default for %s:' %
|
||||||
value._name)
|
value._name)
|
||||||
try:
|
try:
|
||||||
lines.append('# Default value: %s\n' % x)
|
lines.append('# Default value: %s\n' % x)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
exception('Exception printing default value of %s:',
|
exception('Exception printing default value of %s:' %
|
||||||
value._name)
|
value._name)
|
||||||
lines.append('###\n')
|
lines.append('###\n')
|
||||||
fd.writelines(lines)
|
fd.writelines(lines)
|
||||||
@ -231,7 +231,7 @@ class Group(object):
|
|||||||
parts = split(rest)
|
parts = split(rest)
|
||||||
if len(parts) == 1 and parts[0] == name:
|
if len(parts) == 1 and parts[0] == name:
|
||||||
try:
|
try:
|
||||||
self.__makeChild(group, v)
|
self.__makeChild(name, v)
|
||||||
except InvalidRegistryValue:
|
except InvalidRegistryValue:
|
||||||
# It's probably supposed to be registered later.
|
# It's probably supposed to be registered later.
|
||||||
pass
|
pass
|
||||||
|
@ -131,11 +131,8 @@ class Schedule(drivers.IrcDriver):
|
|||||||
except Exception, e:
|
except Exception, e:
|
||||||
log.exception('Uncaught exception in scheduled function:')
|
log.exception('Uncaught exception in scheduled function:')
|
||||||
|
|
||||||
try:
|
|
||||||
ignore(schedule)
|
|
||||||
except NameError:
|
|
||||||
schedule = Schedule()
|
|
||||||
|
|
||||||
|
schedule = Schedule()
|
||||||
addEvent = schedule.addEvent
|
addEvent = schedule.addEvent
|
||||||
removeEvent = schedule.removeEvent
|
removeEvent = schedule.removeEvent
|
||||||
rescheduleEvent = schedule.rescheduleEvent
|
rescheduleEvent = schedule.rescheduleEvent
|
||||||
|
3
src/version.py
Normal file
3
src/version.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
"""stick the various versioning attributes in here, so we only have to change
|
||||||
|
them once."""
|
||||||
|
version = '0.83.4.1+git'
|
@ -30,6 +30,7 @@
|
|||||||
from supybot.test import *
|
from supybot.test import *
|
||||||
|
|
||||||
from supybot.commands import *
|
from supybot.commands import *
|
||||||
|
import supybot.conf as conf
|
||||||
import supybot.irclib as irclib
|
import supybot.irclib as irclib
|
||||||
import supybot.ircmsgs as ircmsgs
|
import supybot.ircmsgs as ircmsgs
|
||||||
import supybot.callbacks as callbacks
|
import supybot.callbacks as callbacks
|
||||||
@ -72,6 +73,16 @@ class GeneralContextTestCase(CommandsTestCase):
|
|||||||
self.assertState(['int'], ['1'], [1])
|
self.assertState(['int'], ['1'], [1])
|
||||||
self.assertState(['int', 'int', 'int'], ['1', '2', '3'], [1, 2, 3])
|
self.assertState(['int', 'int', 'int'], ['1', '2', '3'], [1, 2, 3])
|
||||||
|
|
||||||
|
def testSpecNick(self):
|
||||||
|
strict = conf.supybot.protocols.irc.strictRfc()
|
||||||
|
try:
|
||||||
|
conf.supybot.protocols.irc.strictRfc.setValue(True)
|
||||||
|
self.assertError(['nick'], ['1abc'])
|
||||||
|
conf.supybot.protocols.irc.strictRfc.setValue(False)
|
||||||
|
self.assertState(['nick'], ['1abc'], ['1abc'])
|
||||||
|
finally:
|
||||||
|
conf.supybot.protocols.irc.strictRfc.setValue(strict)
|
||||||
|
|
||||||
def testSpecLong(self):
|
def testSpecLong(self):
|
||||||
self.assertState(['long'], ['1'], [1L])
|
self.assertState(['long'], ['1'], [1L])
|
||||||
self.assertState(['long', 'long', 'long'], ['1', '2', '3'],
|
self.assertState(['long', 'long', 'long'], ['1', '2', '3'],
|
||||||
|
@ -292,7 +292,7 @@ class IrcStateTestCase(SupyTestCase):
|
|||||||
|
|
||||||
def testSupportedUmodes(self):
|
def testSupportedUmodes(self):
|
||||||
state = irclib.IrcState()
|
state = irclib.IrcState()
|
||||||
state.addMsg(self.irc, ircmsgs.IrcMsg(':charm.oftc.net 004 charm.oftc.net hybrid-7.2.2+oftc1.6.8 CDGPRSabcdfgiklnorsuwxyz biklmnopstveI bkloveI'))
|
state.addMsg(self.irc, ircmsgs.IrcMsg(':coulomb.oftc.net 004 testnick coulomb.oftc.net hybrid-7.2.2+oftc1.6.8 CDGPRSabcdfgiklnorsuwxyz biklmnopstveI bkloveI'))
|
||||||
self.assertEqual(state.supported['umodes'], 'CDGPRSabcdfgiklnorsuwxyz')
|
self.assertEqual(state.supported['umodes'], 'CDGPRSabcdfgiklnorsuwxyz')
|
||||||
self.assertEqual(state.supported['chanmodes'],
|
self.assertEqual(state.supported['chanmodes'],
|
||||||
'biklmnopstveI')
|
'biklmnopstveI')
|
||||||
|
Loading…
Reference in New Issue
Block a user