From fbb37025dc5f6ea1de8dc869b2ad95f71c6384af Mon Sep 17 00:00:00 2001 From: James Vega Date: Mon, 27 Oct 2003 20:24:32 +0000 Subject: [PATCH] plugins/Sourceforge.py: lots of cleanups to the code. Also changed how togglesnarfer works. test/test_Sourceforge.py: updated to follow the plugin changes --- plugins/Sourceforge.py | 278 ++++++++++++++++++++------------------- test/test_Sourceforge.py | 27 ++-- 2 files changed, 161 insertions(+), 144 deletions(-) diff --git a/plugins/Sourceforge.py b/plugins/Sourceforge.py index ef5a8aaa7..882a6a499 100644 --- a/plugins/Sourceforge.py +++ b/plugins/Sourceforge.py @@ -54,12 +54,24 @@ def configure(onStart, afterConnect, advanced): # commands you would like to be run when the bot has finished connecting. from questions import expect, anything, something, yn onStart.append('load Sourceforge') - print 'The Sourceforge plugin has the functionality to watch for URLs' - print 'that match a specific pattern (we call this a snarfer). When' - print 'supybot sees such a URL, he will parse the web page for information' - print 'and reply with the results.\n' - if yn('Do you want the Sourceforge snarfer enabled by default?') == 'n': - onStart.append('Sourceforge togglesnarfer') + if advanced: + print 'The Sourceforge plugin has the functionality to watch for URLs' + print 'that match a specific pattern (we call this a snarfer). When' + print 'supybot sees such a URL, he will parse the web page for' + print 'information and reply with the results.\n' + if yn('Do you want the Sourceforge snarfer enabled by default?') =='n': + onStart.append('Sourceforge togglesnarfer tracker off') + + print 'The bugs and rfes commands of the Sourceforge plugin can be set' + print 'to query a default project when no project is specified. If this' + print 'project is not set, calling either of those commands will display' + print 'the associated help. With the default project set, calling' + print 'bugs/rfes with no arguments will find the most recent bugs/rfes' + print 'for the default project.\n' + if yn('Do you want to specify a default project?') == 'y': + project = anything('Project name:') + if project: + onStart.append('Sourceforge setdefault %s' % project) example = utils.wrapLines(""" <@jamessan|work> @bugs @@ -84,36 +96,23 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp): regexps = ['sfSnarfer'] _reopts = re.I - - _infoRe = re.compile(r'(\d+)'\ - '([^<]+)', _reopts) - _hrefOpts = '&set=custom&_assigned_to=0&_status=1&_category=100&'\ - '_group=100&order=artifact_id&sort=DESC' - - _resolution = re.compile(r'Resolution: (.+?)', - _reopts) - _getRes = lambda self, s: '%s: %s' % (ircutils.bold('Resolution'), - self._resolution.search(s).group(1)) - + _infoRe = re.compile(r'(\d+)([^<]+)', _reopts) + _hrefOpts = '&set=custom&_assigned_to=0&_status=1&_category'\ + '=100&_group=100&order=artifact_id&sort=DESC' + _resolution = re.compile(r'Resolution: (.+?)',_reopts) _assigned = re.compile(r'Assigned To: (.+?)', _reopts) - _getAssign = lambda self, s: '%s: %s' % (ircutils.bold('Assigned to'), - self._assigned.search(s).group(1)) - _submitted = re.compile(r'Submitted By:
([^<]+)', _reopts) - _getSubmit = lambda self, s: '%s: %s' % (ircutils.bold('Submmited by'), - self._submitted.search(s).group(1)) - _priority = re.compile(r'Priority: (.+?)', _reopts) - _getPri = lambda self, s: '%s: %s' % (ircutils.bold('Priority'), - self._priority.search(s).group(1)) - _status = re.compile(r'Status: (.+?)', _reopts) - _getStatus = lambda self, s: '%s: %s' % (ircutils.bold('Status'), - self._status.search(s).group(1)) + _res ={'Resolution':_resolution,'Assigned to':_assigned, + 'Submitted by':_submitted, 'Priority':_priority, + 'Status':_status} def __init__(self): callbacks.PrivmsgCommandAndRegexp.__init__(self) - self.snarfer = True + self.snarfers = {'tracker' : True} + self.project = None def _formatResp(self, num, text): """ @@ -133,17 +132,98 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp): matches.append((item[0], utils.htmlToText(item[2]))) return matches - def togglesnarfer(self, irc, msg, args): - """takes no argument + def setdefault(self, irc, msg, args): + """ - Disables the snarfer that responds to all Sourceforge Tracker links + Sets the default project to be used with bugs and rfes """ - self.snarfer = not self.snarfer - if self.snarfer: - irc.reply(msg, '%s (Snarfer is enabled)' % conf.replySuccess) - else: - irc.reply(msg, '%s (Snarfer is disabled)' % conf.replySuccess) - togglesnarfer=privmsgs.checkCapability(togglesnarfer,'admin') + project = privmsgs.getArgs(args) + self.project = project + irc.reply(msg, conf.replySuccess) + setdefault = privmsgs.checkCapability(setdefault, 'admin') + + def _toggleHelper(self, irc, msg, state, snarfer): + if not state: + self.snarfers[snarfer] = not self.snarfers[snarfer] + elif state in self._enable: + self.snarfers[snarfer] = True + elif state in self._disable: + self.snarfers[snarfer] = False + resp = [] + for k in self.snarfers: + if self.snarfers[k]: + resp.append('%s%s: On' % (k[0].upper(), k[1:])) + else: + resp.append('%s%s: Off' % (k[0].upper(), k[1:])) + irc.reply(msg, '%s (%s)' % (conf.replySuccess, '; '.join(resp))) + + _enable = ('on', 'enable') + _disable = ('off', 'disable') + def togglesnarfer(self, irc, msg, args): + """ [] + + Toggles the snarfer that responds to Sourceforge Tracker links. If + nothing is specified, all snarfers will have their states + toggled (on -> off, off -> on). If only a state is specified, all + snarfers will have their state set to the specified state. If a + specific snarfer is specified, the changes will apply only to that + snarfer. + """ + (snarfer, state) = privmsgs.getArgs(args, optional=1) + snarfer = snarfer.lower() + state = state.lower() + if snarfer not in self.snarfers: + raise callbacks.ArgumentError + if state and state not in self._enable and state not in self._disable: + raise callbacks.ArgumentError + self._toggleHelper(irc, msg, state, snarfer) + togglesnarfer=privmsgs.checkCapability(togglesnarfer, 'admin') + + def _getTrackerInfo(self, irc, msg, url, regex, num): + try: + fd = urllib2.urlopen(url) + text = fd.read() + fd.close() + m = regex.search(text) + if m is None: + irc.reply(msg, 'Can\'t find the proper Tracker link.') + return + else: + url = 'http://sourceforge.net%s%s' %\ + (utils.htmlToText(m.group(1)), self._hrefOpts) + except ValueError, e: + irc.error(msg, str(e)) + except urllib2.HTTPError, e: + irc.error(msg, e.msg()) + except Exception, e: + irc.error(msg, debug.exnToString(e)) + + try: + fd = urllib2.urlopen(url) + text = fd.read() + fd.close() + resp = [] + if num != '': + head = '%s ' + for match in self._formatResp(num, text): + resp.append(head % match) + if resp: + irc.reply(msg, resp[0]) + return + else: + head = '#%s: %s' + for entry in self._formatResp(num, text): + resp.append(head % entry) + if resp: + if len(resp) > 10: + resp = map(lambda s: utils.ellipsisify(s, 50), resp) + irc.reply(msg, '%s' % utils.commaAndify(resp)) + return + irc.reply(msg, 'No Trackers were found.') + except ValueError, e: + irc.error(msg, str(e)) + except Exception, e: + irc.error(msg, debug.exnToString(e)) _bugLink = re.compile(r'"([^"]+)">Bugs') def bugs(self, irc, msg, args): @@ -155,52 +235,18 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp): """ (project, bugnum) = privmsgs.getArgs(args, needed=0, optional=2) if not project: - project = 'supybot' + if self.project is None: + raise callbacks.ArgumentError + else: + project = self.project + elif not bugnum: + try: + bugnum = int(project) + project = self.project + except ValueError: + pass url = 'http://sourceforge.net/projects/%s' % project - try: - fd = urllib2.urlopen(url) - text = fd.read() - fd.close() - m = self._bugLink.search(text) - if m is None: - irc.reply(msg, 'Can\'t find the "Bugs" link.') - return - else: - url = 'http://sourceforge.net%s%s' %\ - (utils.htmlToText(m.group(1)), self._hrefOpts) - except ValueError, e: - irc.error(msg, str(e)) - except urllib2.HTTPError, e: - irc.error(msg, e.msg()) - except Exception, e: - irc.error(msg, debug.exnToString(e)) - - try: - fd = urllib2.urlopen(url) - text = fd.read() - fd.close() - resp = [] - if bugnum != '': - head = '%s ' - for bug in self._formatResp(bugnum, text): - resp.append(head % bug) - if resp: - irc.reply(msg, resp[0]) - return - else: - head = 'Bug #%s: %s' - for bug in self._formatResp(bugnum, text): - resp.append(head % bug) - if resp: - if len(resp) > 10: - resp = map(lambda s: utils.ellipsisify(s, 50), resp) - irc.reply(msg, '%s' % utils.commaAndify(resp)) - return - irc.reply(msg, 'No bugs were found.') - except ValueError, e: - irc.error(msg, str(e)) - except Exception, e: - irc.error(msg, debug.exnToString(e)) + self._getTrackerInfo(irc, msg, url, self._bugLink, bugnum) _rfeLink = re.compile(r'"([^"]+)">RFE') def rfes(self, irc, msg, args): @@ -212,72 +258,38 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp): """ (project, rfenum) = privmsgs.getArgs(args, needed=0, optional=2) if not project: - project = 'supybot' + if self.project is None: + raise callbacks.ArgumentError + else: + project = self.project + elif not rfenum: + try: + rfenum = int(project) + project = self.project + except ValueError: + pass url = 'http://sourceforge.net/projects/%s' % project - try: - fd = urllib2.urlopen(url) - text = fd.read() - fd.close() - m = self._rfeLink.search(text) - if m is None: - irc.reply(msg, 'Can\'t find the "RFE" link.') - return - else: - url = 'http://sourceforge.net%s%s' %\ - (utils.htmlToText(m.group(1)), self._hrefOpts) - except ValueError, e: - irc.error(msg, str(e)) - except urllib2.HTTPError, e: - irc.error(msg, e.msg()) - except Exception, e: - irc.error(msg, debug.exnToString(e)) - - try: - fd = urllib2.urlopen(url) - text = fd.read() - fd.close() - resp = [] - if rfenum != '': - head = '%s ' - for rfe in self._formatResp(rfenum, text): - resp.append(head % rfe) - if resp: - irc.reply(msg, resp[0]) - return - else: - head = 'RFE #%s: %s' - for rfe in self._formatResp(rfenum, text): - resp.append(head % rfe) - if resp: - if len(resp) > 10: - resp = map(lambda s: utils.ellipsisify(s, 50), resp) - irc.reply(msg, '%s' % utils.commaAndify(resp)) - return - irc.reply(msg, 'No rfes were found.') - except ValueError, e: - irc.error(msg, str(e)) - except Exception, e: - irc.error(msg, debug.exnToString(e)) + self._getTrackerInfo(irc, msg, url, self._rfeLink, rfenum) + _getSnarferInfo = lambda self, k, v, s: '%s: %s' % (ircutils.bold(k), + v.search(s).group(1)) _sfTitle = re.compile(r'Detail:(\d+) - ([^<]+)', re.I) _linkType = re.compile(r'(\w+ \w+|\w+): Tracker Detailed View', re.I) def sfSnarfer(self, irc, msg, match): r"https?://(?:www\.)?(?:sourceforge|sf)\.net/tracker/(?:index\.php)?\?(?:&?func=detail|&?aid=\d+|&?group_id=\d+|&?atid=\d+){4}" - if not self.snarfer: + if not self.snarfers['tracker']: return url = match.group(0) fd = urllib2.urlopen(url) s = fd.read() fd.close() - searches = (self._getSubmit, self._getStatus, self._getRes, - self._getPri, self._getAssign) try: (num, desc) = self._sfTitle.search(s).groups() resp = [desc] linktype = self._linkType.search(s).group(1) - for i in searches: + for k,v in self._res.iteritems(): try: - resp.append('%s' % i(s)) + resp.append(self._getSnarferInfo(k, v, s)) except AttributeError: pass linktype = utils.depluralize(linktype) diff --git a/test/test_Sourceforge.py b/test/test_Sourceforge.py index 6f7f7243e..b01447e47 100644 --- a/test/test_Sourceforge.py +++ b/test/test_Sourceforge.py @@ -36,23 +36,29 @@ from test import * class SourceforgeTest(PluginTestCase, PluginDocumentation): plugins = ('Sourceforge',) def testBugs(self): - self.assertNotError('bugs') - self.assertResponse('bugs alkjfi83fa8', 'Can\'t find the "Bugs" link.') + self.assertHelp('bugs') + self.assertResponse('bugs alkjfi83fa8', 'Can\'t find the proper '\ + 'Tracker link.') self.assertNotError('bugs gaim') m = self.getMsg('bugs gaim') n = re.search('#(\d+)', m.args[1]).group(1) self.assertNotError('bugs gaim %s' % n) def testRfes(self): - self.assertNotError('rfes') - self.assertResponse('rfes alkjfi83hfa8', 'Can\'t find the "RFE" link.') + self.assertHelp('rfes') + self.assertResponse('rfes alkjfi83hfa8', 'Can\'t find the proper '\ + 'Tracker link.') self.assertNotError('rfes gaim') m = self.getMsg('rfes gaim') n = re.search('#(\d+)', m.args[1]).group(1) self.assertNotError('rfes gaim %s' % n) + def testSetdefault(self): + self.assertNotError('setdefault supybot') + self.assertNotError('rfes') + def testSnarfer(self): - s = r';.*Status.*: \w+;' + s = r'.*Status.*: \w+' self.assertRegexp('http://sourceforge.net/tracker/index.php?'\ 'func=detail&aid=589953&group_id=58965&atid=489447', s) self.assertRegexp('http://sourceforge.net/tracker/index.php?'\ @@ -83,16 +89,15 @@ class SourceforgeTest(PluginTestCase, PluginDocumentation): 'group_id=58965&atid=489447') def testDisablesfsnarfer(self): + s = r'.*Status.*: \w+' self.assertRegexp('http://sourceforge.net/tracker/index.php?'\ - 'func=detail&aid=540223&group_id=235&atid=300235', - r';.*Status.*: \w+;') - self.assertNotError('togglesnarfer') + 'func=detail&aid=540223&group_id=235&atid=300235', s) + self.assertNotError('togglesnarfer tracker off') self.assertNoResponse('http://sourceforge.net/tracker/index.php?'\ 'func=detail&aid=540223&group_id=235&atid=300235') - self.assertNotError('togglesnarfer') + self.assertNotError('togglesnarfer tracker on') self.assertRegexp('http://sourceforge.net/tracker/index.php?'\ - 'func=detail&aid=540223&group_id=235&atid=300235', - r';.*Status.*: \w+;') + 'func=detail&aid=540223&group_id=235&atid=300235', s) # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: