Various improvements.

* Encyclopedia, PackageInfo:
  + Make repeat delay a setting.
  + Update default configuration.
* Bugtracker: Fix inconsistencies in network specificity.
This commit is contained in:
Krytarik Raido 2021-12-02 22:13:04 +01:00
parent df480587c9
commit e9306925c0
9 changed files with 106 additions and 70 deletions

View File

@ -23,7 +23,7 @@ import supybot
import supybot.world as world import supybot.world as world
from importlib import reload from importlib import reload
__version__ = "4.9.0" __version__ = "5.0.0"
__author__ = supybot.Author("Krytarik Raido", "krytarik", "krytarik@gmail.com") __author__ = supybot.Author("Krytarik Raido", "krytarik", "krytarik@gmail.com")
__contributors__ = { __contributors__ = {
supybot.Author("Dennis Kaarsemaker", "Seveas", "dennis@kaarsemaker.net"): ['Original Author'], supybot.Author("Dennis Kaarsemaker", "Seveas", "dennis@kaarsemaker.net"): ['Original Author'],

View File

@ -54,6 +54,7 @@ def configure(advanced):
commitSnarfer = yn("Enable detecting commit hashes and URLs in all channels?", default=Bugtracker.commitSnarfer._default) commitSnarfer = yn("Enable detecting commit hashes and URLs in all channels?", default=Bugtracker.commitSnarfer._default)
cveSnarfer = yn("Enable detecting CVE numbers and URLs in all channels?", default=Bugtracker.cveSnarfer._default) cveSnarfer = yn("Enable detecting CVE numbers and URLs in all channels?", default=Bugtracker.cveSnarfer._default)
oopsSnarfer = yn("Enable detecting Launchpad OOPS IDs in all channels?", default=Bugtracker.oopsSnarfer._default) oopsSnarfer = yn("Enable detecting Launchpad OOPS IDs in all channels?", default=Bugtracker.oopsSnarfer._default)
if advanced: if advanced:
replyNoBugtracker = something("What should the bot reply with when a user requests information from an unknown bug tracker?", default=Bugtracker.replyNoBugtracker._default) replyNoBugtracker = something("What should the bot reply with when a user requests information from an unknown bug tracker?", default=Bugtracker.replyNoBugtracker._default)
snarfTarget = something("What should be the default bug tracker used when none is specified?", default=Bugtracker.snarfTarget._default) snarfTarget = something("What should be the default bug tracker used when none is specified?", default=Bugtracker.snarfTarget._default)

View File

@ -103,8 +103,8 @@ class Bugtracker(callbacks.PluginRegexp):
for k in list(self.shown.keys()): for k in list(self.shown.keys()):
if self.shown[k] < now - self.registryValue('repeatdelay', channel, network): if self.shown[k] < now - self.registryValue('repeatdelay', channel, network):
self.shown.pop(k) self.shown.pop(k)
if (channel, tracker, bugid) not in self.shown: if (network, channel, tracker, bugid) not in self.shown:
self.shown[(channel, tracker, bugid)] = now self.shown[(network, channel, tracker, bugid)] = now
return True return True
return False return False
@ -320,7 +320,7 @@ class Bugtracker(callbacks.PluginRegexp):
channel = msg.channel channel = msg.channel
if checkAddressed(msg.args[1].strip(), channel): if checkAddressed(msg.args[1].strip(), channel):
return return
if not self.registryValue('{}Snarfer'.format(termtype), channel): if not self.registryValue('{}Snarfer'.format(termtype), channel, irc.network):
return return
nbugs = msg.tagged('nbugs') or 0 nbugs = msg.tagged('nbugs') or 0
if nbugs >= 5: if nbugs >= 5:
@ -418,7 +418,7 @@ class Bugtracker(callbacks.PluginRegexp):
channel = msg.channel channel = msg.channel
if checkAddressed(msg.args[1].strip(), channel): if checkAddressed(msg.args[1].strip(), channel):
return return
if not self.registryValue('{}Snarfer'.format(urltype), channel): if not self.registryValue('{}Snarfer'.format(urltype), channel, irc.network):
return return
nbugs = msg.tagged('nbugs') or 0 nbugs = msg.tagged('nbugs') or 0
if nbugs >= 5: if nbugs >= 5:

View File

@ -24,7 +24,7 @@ import supybot
import supybot.world as world import supybot.world as world
from importlib import reload from importlib import reload
__version__ = "4.1.1" __version__ = "4.2.0"
__author__ = supybot.Author("Krytarik Raido", "krytarik", "krytarik@gmail.com") __author__ = supybot.Author("Krytarik Raido", "krytarik", "krytarik@gmail.com")
__contributors__ = { __contributors__ = {
supybot.Author("Dennis Kaarsemaker", "Seveas", "dennis@kaarsemaker.net"): ['Original Author'], supybot.Author("Dennis Kaarsemaker", "Seveas", "dennis@kaarsemaker.net"): ['Original Author'],

View File

@ -29,7 +29,22 @@ def configure(advanced):
Encyclopedia = conf.registerPlugin('Encyclopedia', True) Encyclopedia = conf.registerPlugin('Encyclopedia', True)
def getRepeatdelay():
output("How many seconds should the bot wait before repeating factoids?")
repeatdelay = something("Enter a number greater or equal to 0.", default=Encyclopedia.repeatdelay._default)
try:
repeatdelay = int(repeatdelay)
if repeatdelay < 0:
raise TypeError
except TypeError:
output("Invalid value '%s', it must be an integer greater or equal to 0." % repeatdelay)
return getRepeatdelay()
else:
return repeatdelay
enabled = yn("Enable Encyclopedia for all channels?", default=Encyclopedia.enabled._default) enabled = yn("Enable Encyclopedia for all channels?", default=Encyclopedia.enabled._default)
if advanced: if advanced:
datadir = something("Which directory should the factoids database be in?", default=Encyclopedia.datadir._default) datadir = something("Which directory should the factoids database be in?", default=Encyclopedia.datadir._default)
database = something("What should be the name of the default database (without the .db extension)?", default=Encyclopedia.database._default) database = something("What should be the name of the default database (without the .db extension)?", default=Encyclopedia.database._default)
@ -40,6 +55,7 @@ def configure(advanced):
ignores_i = anything("Which factoid requests should the bot always ignore?", default=', '.join(Encyclopedia.ignores._default)) ignores_i = anything("Which factoid requests should the bot always ignore?", default=', '.join(Encyclopedia.ignores._default))
for name in re.split(r'[,\s]+', ignores_i): for name in re.split(r'[,\s]+', ignores_i):
ignores.add(name.lower()) ignores.add(name.lower())
repeatdelay = getRepeatdelay()
curStable = something("What is short name of the current stable release?", default=Encyclopedia.curStable._default) curStable = something("What is short name of the current stable release?", default=Encyclopedia.curStable._default)
curStableLong = something("What is long name of the current stable release?", default=Encyclopedia.curStableLong._default) curStableLong = something("What is long name of the current stable release?", default=Encyclopedia.curStableLong._default)
@ -57,6 +73,7 @@ def configure(advanced):
database = Encyclopedia.database._default database = Encyclopedia.database._default
prefixchar = Encyclopedia.prefixchar._default prefixchar = Encyclopedia.prefixchar._default
ignores = Encyclopedia.ignores._default ignores = Encyclopedia.ignores._default
repeatdelay = Encyclopedia.repeatdelay._default
curStable = Encyclopedia.curStable._default curStable = Encyclopedia.curStable._default
curStableLong = Encyclopedia.curStableLong._default curStableLong = Encyclopedia.curStableLong._default
curStableNum = Encyclopedia.curStableNum._default curStableNum = Encyclopedia.curStableNum._default
@ -68,7 +85,7 @@ def configure(advanced):
curLTSNum = Encyclopedia.curLTSNum._default curLTSNum = Encyclopedia.curLTSNum._default
relaychannel = anything("What channel/nick should the bot forward edit messages to?", default=Encyclopedia.relaychannel._default) relaychannel = anything("What channel/nick should the bot forward edit messages to?", default=Encyclopedia.relaychannel._default)
output("What message should the bot reply with when a factoid can not be found?") output("What message should the bot reply with when a factoid cannot be found?")
notfoundmsg = something("If you include a '%s' in the message, it will be replaced with the requested factoid", default=Encyclopedia.notfoundmsg._default) notfoundmsg = something("If you include a '%s' in the message, it will be replaced with the requested factoid", default=Encyclopedia.notfoundmsg._default)
alert = set([]) alert = set([])
output("When certain factoids are called an alert can be forwarded to a channel/nick") output("When certain factoids are called an alert can be forwarded to a channel/nick")
@ -96,6 +113,7 @@ def configure(advanced):
Encyclopedia.relaychannel.setValue(relaychannel) Encyclopedia.relaychannel.setValue(relaychannel)
Encyclopedia.notfoundmsg.setValue(notfoundmsg) Encyclopedia.notfoundmsg.setValue(notfoundmsg)
Encyclopedia.alert.setValue(alert) Encyclopedia.alert.setValue(alert)
Encyclopedia.remotedb.setValue(remotedb)
Encyclopedia.privateNotFound.setValue(privateNotFound) Encyclopedia.privateNotFound.setValue(privateNotFound)
# Create the initial database # Create the initial database
@ -189,6 +207,9 @@ conf.registerChannelValue(Encyclopedia, 'remotedb',
conf.registerChannelValue(Encyclopedia, 'ignores', conf.registerChannelValue(Encyclopedia, 'ignores',
registry.SpaceSeparatedListOfStrings(['info', 'depends', 'find'], 'Factoid names to ignore', private=True)) registry.SpaceSeparatedListOfStrings(['info', 'depends', 'find'], 'Factoid names to ignore', private=True))
conf.registerChannelValue(Encyclopedia, 'repeatdelay',
registry.Integer(60, "Number of seconds to wait between repeated factoid calls"))
conf.registerChannelValue(Encyclopedia, 'privateNotFound', conf.registerChannelValue(Encyclopedia, 'privateNotFound',
registry.Boolean(False, "Send notfoundmsg in private rather than in the channel")) registry.Boolean(False, "Send notfoundmsg in private rather than in the channel"))
@ -197,22 +218,22 @@ conf.registerChannelValue(Encyclopedia, 'forcedFactoid',
conf.registerGlobalValue(Encyclopedia, 'curStable', conf.registerGlobalValue(Encyclopedia, 'curStable',
registry.String('Artful', "Current stable release")) registry.String('Impish', "Current stable release"))
conf.registerGlobalValue(Encyclopedia, 'curStableLong', conf.registerGlobalValue(Encyclopedia, 'curStableLong',
registry.String('Artful Aardvark', "Current stable release")) registry.String('Impish Indri', "Current stable release"))
conf.registerGlobalValue(Encyclopedia, 'curStableNum', conf.registerGlobalValue(Encyclopedia, 'curStableNum',
registry.String('17.10', "Current stable release")) registry.String('21.10', "Current stable release"))
conf.registerGlobalValue(Encyclopedia, 'curDevel', conf.registerGlobalValue(Encyclopedia, 'curDevel',
registry.String('Bionic', "Current development release")) registry.String('Jammy', "Current development release"))
conf.registerGlobalValue(Encyclopedia, 'curDevelLong', conf.registerGlobalValue(Encyclopedia, 'curDevelLong',
registry.String('Bionic Beaver', "Current development release")) registry.String('Jammy Jellyfish', "Current development release"))
conf.registerGlobalValue(Encyclopedia, 'curDevelNum', conf.registerGlobalValue(Encyclopedia, 'curDevelNum',
registry.String('18.04', "Current development release")) registry.String('22.04', "Current development release"))
conf.registerGlobalValue(Encyclopedia, 'curLTS', conf.registerGlobalValue(Encyclopedia, 'curLTS',
registry.String('Xenial', "Current LTS release")) registry.String('Focal', "Current LTS release"))
conf.registerGlobalValue(Encyclopedia, 'curLTSLong', conf.registerGlobalValue(Encyclopedia, 'curLTSLong',
registry.String('Xenial Xerus', "Current LTS release")) registry.String('Focal Fossa', "Current LTS release"))
conf.registerGlobalValue(Encyclopedia, 'curLTSNum', conf.registerGlobalValue(Encyclopedia, 'curLTSNum',
registry.String('16.04', "Current LTS release")) registry.String('20.04', "Current LTS release"))

View File

@ -84,28 +84,6 @@ class FactoidSet:
self.global_primary = self.global_secondary = \ self.global_primary = self.global_secondary = \
self.channel_primary = self.channel_secondary = None self.channel_primary = self.channel_secondary = None
# Repeat filtering message queue
msgcache = {}
def queue(irc, target, msg):
if world.testing:
# don't mess up testcases
irc.reply(msg, to=target, private=True)
return
now = time.time()
for m in list(msgcache.keys()):
if msgcache[m] < now - 30:
msgcache.pop(m)
for m in msgcache:
if m[0] == irc and m[1] == target:
oldmsg = m[2]
if oldmsg.endswith(msg):
break
if msg.endswith(oldmsg) and msg[:-len(oldmsg)].endswith(': '):
msg = msg[:-len(oldmsg)] + 'Please see above'
else:
msgcache[(irc, target, msg)] = now
irc.reply(msg, to=target, private=True)
def capab(prefix, capability): def capab(prefix, capability):
# too bad people don't use supybot's own methods, # too bad people don't use supybot's own methods,
# it would save me the trouble of hacking this up # it would save me the trouble of hacking this up
@ -172,6 +150,7 @@ class Encyclopedia(callbacks.Plugin):
self.databases = {} self.databases = {}
self.times = {} self.times = {}
self.edits = {} self.edits = {}
self.shown = {}
self.alert = False self.alert = False
self.defaultIrc = irc self.defaultIrc = irc
@ -224,6 +203,26 @@ class Encyclopedia(callbacks.Plugin):
irc.reply(', '.join([u.name for u in list(ircdb.users.users.values()) if capab(u.name, 'addeditors')]), private=True) irc.reply(', '.join([u.name for u in list(ircdb.users.users.values()) if capab(u.name, 'addeditors')]), private=True)
moderators = wrap(moderators) moderators = wrap(moderators)
# Repeat filtering message queue
def queue(self, irc, target, msg):
if world.testing:
# don't mess up testcases
irc.reply(msg, to=target, private=True)
return
now = time.time()
for m in list(self.shown.keys()):
if self.shown[m] < now - self.registryValue('repeatdelay', target):
self.shown.pop(m)
for (net, tgt, oldmsg) in list(self.shown.keys()):
if net == irc.network and tgt == target:
if oldmsg.endswith(msg):
break
if msg.endswith(oldmsg) and msg[:-len(oldmsg)].endswith(': '):
msg = msg[:-len(oldmsg)] + 'Please see above'
else:
self.shown[(irc.network, target, msg)] = now
irc.reply(msg, to=target, private=True)
def get_target(self, irc, nick, text, target): def get_target(self, irc, nick, text, target):
ret, retmsg = text, '' ret, retmsg = text, ''
orig_target = target orig_target = target
@ -411,7 +410,7 @@ class Encyclopedia(callbacks.Plugin):
def noqueue(irc, target, msg): def noqueue(irc, target, msg):
irc.reply(msg, to=target, private=True) irc.reply(msg, to=target, private=True)
def myqueue(irc, target, msg): def myqueue(irc, target, msg):
(queue if queue_msg else noqueue)(irc, target, msg) (self.queue if queue_msg else noqueue)(irc, target, msg)
# Filter CTCP # Filter CTCP
if chr(1) in msg.args[1]: if chr(1) in msg.args[1]:

View File

@ -22,7 +22,7 @@ import supybot
import supybot.world as world import supybot.world as world
from importlib import reload from importlib import reload
__version__ = "2.4.0" __version__ = "2.5.0"
__author__ = supybot.Author("Krytarik Raido", "krytarik", "krytarik@gmail.com") __author__ = supybot.Author("Krytarik Raido", "krytarik", "krytarik@gmail.com")
__contributors__ = { __contributors__ = {
supybot.Author("Dennis Kaarsemaker", "Seveas", "dennis@kaarsemaker.net"): ['Original Concept'], supybot.Author("Dennis Kaarsemaker", "Seveas", "dennis@kaarsemaker.net"): ['Original Concept'],

View File

@ -47,30 +47,44 @@ deb-src deb http://security.debian.org/ %s/updates main contrib non-free
PackageInfo = conf.registerPlugin('PackageInfo', True) PackageInfo = conf.registerPlugin('PackageInfo', True)
enabled = yn("Enable this plugin in all channels?", default=True) def getRepeatdelay():
output("How many seconds should the bot wait before repeating package information?")
repeatdelay = something("Enter a number greater or equal to 0.", default=PackageInfo.repeatdelay._default)
if enabled and advanced: try:
repeatdelay = int(repeatdelay)
if repeatdelay < 0:
raise TypeError
except TypeError:
output("Invalid value '%s', it must be an integer greater or equal to 0." % repeatdelay)
return getRepeatdelay()
else:
return repeatdelay
enabled = yn("Enable this plugin in all channels?", default=PackageInfo.enabled._default)
if advanced:
prefixchar = something("Which prefix character should the bot respond to?", default=PackageInfo.prefixchar._default) prefixchar = something("Which prefix character should the bot respond to?", default=PackageInfo.prefixchar._default)
defaultRelease = something("What should be the default release when none is specified?", default=PackageInfo.defaultRelease._default) defaultRelease = something("What should be the default release when none is specified?", default=PackageInfo.defaultRelease._default)
repeatdelay = getRepeatdelay()
aptdir = something("Which directory should be used for the apt cache when looking up packages?", default=PackageInfo.aptdir._default) aptdir = something("Which directory should be used for the apt cache when looking up packages?", default=PackageInfo.aptdir._default)
# People tend to think this should be /var/cache/apt # People tend to think this should be /var/cache/apt
while aptdir.startswith('/var'): #NOTE: This is not a good hack. Maybe just blacklist /var/cache/apt (or use apt to report back the cache dir) while aptdir.startswith('/var'): #NOTE: This is not a good hack. Maybe just blacklist /var/cache/apt (or use apt to report back the cache dir)
output("NO! Do not use your system's apt directory") output("NO! Do not use your system's apt directory")
aptdir = something("Which directory should be used for the apt cache when looking up packages?", default=PackageInfo.aptdir._default) aptdir = something("Which directory should be used for the apt cache when looking up packages?", default=PackageInfo.aptdir._default)
else: else:
prefixchar = PackageInfo.prefixchar._default prefixchar = PackageInfo.prefixchar._default
defaultRelease = PackageInfo.defaultRelease._default defaultRelease = PackageInfo.defaultRelease._default
repeatdelay = PackageInfo.repeatdelay._default
aptdir = PackageInfo.aptdir._default aptdir = PackageInfo.aptdir._default
PackageInfo.enabled.setValue(enabled) PackageInfo.enabled.setValue(enabled)
PackageInfo.aptdir.setValue(aptdir)
PackageInfo.prefixchar.setValue(prefixchar) PackageInfo.prefixchar.setValue(prefixchar)
PackageInfo.defaultRelease.setValue(defaultRelease) PackageInfo.defaultRelease.setValue(defaultRelease)
PackageInfo.repeatdelay.setValue(repeatdelay)
PackageInfo.aptdir.setValue(aptdir)
default_dists = set(['bionic', 'focal', 'groovy', 'hirsute', 'impish', default_dists = set(['bionic', 'focal', 'hirsute', 'impish', 'jammy',
'oldstable', 'stable', 'unstable', 'testing', 'experimental']) 'oldstable', 'stable', 'unstable', 'testing', 'experimental'])
pluginDir = os.path.abspath(os.path.dirname(__file__)) pluginDir = os.path.abspath(os.path.dirname(__file__))
update_apt = os.path.join(pluginDir, 'update_apt') update_apt = os.path.join(pluginDir, 'update_apt')
@ -134,7 +148,10 @@ conf.registerChannelValue(PackageInfo, 'prefixchar',
conf.ValidPrefixChars('!', "Character the bot will respond to")) conf.ValidPrefixChars('!', "Character the bot will respond to"))
conf.registerChannelValue(PackageInfo, 'defaultRelease', conf.registerChannelValue(PackageInfo, 'defaultRelease',
registry.String('hirsute', "Default release to use when none is specified")) registry.String('impish', "Default release to use when none is specified"))
conf.registerChannelValue(PackageInfo, 'repeatdelay',
registry.Integer(60, "Number of seconds to wait between repeated package info calls"))
conf.registerChannelValue(PackageInfo, 'listReleasesOnError', conf.registerChannelValue(PackageInfo, 'listReleasesOnError',
registry.Boolean(True, "Send list of all valid releases in private on error")) registry.Boolean(True, "Send list of all valid releases in private on error"))

View File

@ -59,25 +59,6 @@ def checkIgnored(hostmask, channel):
return True return True
return False return False
## Taken from Encyclopedia ##
# Repeat filtering message queue
msgcache = {}
def queue(irc, target, msg):
now = time.time()
for m in list(msgcache.keys()):
if msgcache[m] < now - 30:
msgcache.pop(m)
for m in msgcache:
if m[0] == irc and m[1] == target:
oldmsg = m[2]
if oldmsg.endswith(msg):
break
if msg.endswith(oldmsg) and msg[:-len(oldmsg)].endswith(': '):
msg = msg[:-len(oldmsg)] + 'Please see above'
else:
msgcache[(irc, target, msg)] = now
irc.reply(msg, to=target, private=True)
class PackageInfo(callbacks.Plugin): class PackageInfo(callbacks.Plugin):
"""Look up package information via apt-cache/apt-file""" """Look up package information via apt-cache/apt-file"""
threaded = True threaded = True
@ -86,6 +67,7 @@ class PackageInfo(callbacks.Plugin):
self.__parent = super(PackageInfo, self) self.__parent = super(PackageInfo, self)
self.__parent.__init__(irc) self.__parent.__init__(irc)
self.Apt = packages.Apt(self) self.Apt = packages.Apt(self)
self.shown = {}
def __getRelease(self, irc, release, channel, doError=True): def __getRelease(self, irc, release, channel, doError=True):
if release: if release:
@ -136,6 +118,22 @@ class PackageInfo(callbacks.Plugin):
return (target, prefix + reply) return (target, prefix + reply)
# Repeat filtering message queue
def queue(self, irc, target, msg):
now = time.time()
for m in list(self.shown.keys()):
if self.shown[m] < now - self.registryValue('repeatdelay', target, irc.network):
self.shown.pop(m)
for (net, tgt, oldmsg) in list(self.shown.keys()):
if net == irc.network and tgt == target:
if oldmsg.endswith(msg):
break
if msg.endswith(oldmsg) and msg[:-len(oldmsg)].endswith(': '):
msg = msg[:-len(oldmsg)] + 'Please see above'
else:
self.shown[(irc.network, target, msg)] = now
irc.reply(msg, to=target, private=True)
def info(self, irc, msg, args, package, release=None): def info(self, irc, msg, args, package, release=None):
"""<[src:]package> [<release>] """<[src:]package> [<release>]
@ -157,7 +155,7 @@ class PackageInfo(callbacks.Plugin):
reply = self.Apt.info(package, release, isSource) reply = self.Apt.info(package, release, isSource)
if rest: if rest:
(target, reply) = self.__handleRest(irc, msg, target, reply, rest) (target, reply) = self.__handleRest(irc, msg, target, reply, rest)
queue(irc, target, reply) self.queue(irc, target, reply)
info = wrap(info, ['anything', optional('text')]) info = wrap(info, ['anything', optional('text')])
def depends(self, irc, msg, args, package, release=None): def depends(self, irc, msg, args, package, release=None):
@ -181,7 +179,7 @@ class PackageInfo(callbacks.Plugin):
reply = self.Apt.depends(package, release, isSource) reply = self.Apt.depends(package, release, isSource)
if rest: if rest:
(target, reply) = self.__handleRest(irc, msg, target, reply, rest) (target, reply) = self.__handleRest(irc, msg, target, reply, rest)
queue(irc, target, reply) self.queue(irc, target, reply)
depends = wrap(depends, ['anything', optional('text')]) depends = wrap(depends, ['anything', optional('text')])
def find(self, irc, msg, args, package, release=None): def find(self, irc, msg, args, package, release=None):
@ -205,7 +203,7 @@ class PackageInfo(callbacks.Plugin):
reply = self.Apt.find(package, release) reply = self.Apt.find(package, release)
if rest: if rest:
(target, reply) = self.__handleRest(irc, msg, target, reply, rest) (target, reply) = self.__handleRest(irc, msg, target, reply, rest)
queue(irc, target, reply) self.queue(irc, target, reply)
find = wrap(find, ['anything', optional('text')]) find = wrap(find, ['anything', optional('text')])
def releases(self, irc, msg, args): def releases(self, irc, msg, args):