Updates to PkgInfo

- In exception handling, only catch utils.web.Error instead of all possible exceptions
- Rename 'package' command to 'pkg'
- vlist/pkgsearch: guess distribution from release name as with 'pkg', so that 'vlist trusty <app>' is accepted
This commit is contained in:
James Lu 2014-11-02 17:31:41 -08:00
parent 523e0f9fad
commit afe692e8c9
2 changed files with 53 additions and 34 deletions

View File

@ -35,7 +35,7 @@ import supybot.plugins as plugins
import supybot.ircutils as ircutils import supybot.ircutils as ircutils
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
from collections import OrderedDict, defaultdict from collections import OrderedDict, defaultdict
try: # Python 3 try: # Python 3
from urllib.parse import urlencode, quote from urllib.parse import urlencode, quote
except ImportError: # Python 2 except ImportError: # Python 2
from urllib import urlencode, quote from urllib import urlencode, quote
@ -60,7 +60,7 @@ except ImportError:
_ = lambda x:x _ = lambda x:x
class PkgInfo(callbacks.Plugin): class PkgInfo(callbacks.Plugin):
"""Fetches package information from the repositories of """Fetches package information from the repositories of
Debian, Arch Linux, and Ubuntu.""" Debian, Arch Linux, and Ubuntu."""
threaded = True threaded = True
@ -70,6 +70,21 @@ class PkgInfo(callbacks.Plugin):
self.addrs = {'ubuntu':'http://packages.ubuntu.com/', self.addrs = {'ubuntu':'http://packages.ubuntu.com/',
'debian':"https://packages.debian.org/"} 'debian':"https://packages.debian.org/"}
def _getDistro(self, release):
"""<release>
Guesses the distribution from the release name."""
release = release.lower()
if release.startswith(("oldstable","squeeze","wheezy","stable",
"jessie","testing","sid","unstable")):
distro = "debian"
elif release.startswith(("hardy","lucid","maverick","natty","oneiric",
"precise","quantal","raring","saucy","trusty","utopic","vivid")):
distro = "ubuntu"
else:
distro = None
return distro
def MadisonParse(self, pkg, dist, codenames='', suite='', useSource=False): def MadisonParse(self, pkg, dist, codenames='', suite='', useSource=False):
arch = ','.join(self.registryValue("archs")) arch = ','.join(self.registryValue("archs"))
self.arg = {'package':pkg,'table':dist,'a':arch,'c':codenames,'s':suite, self.arg = {'package':pkg,'table':dist,'a':arch,'c':codenames,'s':suite,
@ -96,27 +111,26 @@ class PkgInfo(callbacks.Plugin):
"\x02({!s})\x02".format(k,v[0]) for (k,v) in d.items()) "\x02({!s})\x02".format(k,v[0]) for (k,v) in d.items())
else: else:
self.log.debug("PkgInfo: No results found for URL %s" % url) self.log.debug("PkgInfo: No results found for URL %s" % url)
def package(self, irc, msg, args, suite, pkg): def package(self, irc, msg, args, release, pkg):
"""<suite> <package> """<release> <package>
Fetches information for <package> from Debian or Ubuntu's repositories. Fetches information for <package> from Debian or Ubuntu's repositories.
<suite> is the codename/release name (e.g. 'trusty', 'squeeze'). <release> is the codename/release name (e.g. 'trusty', 'squeeze').
For Arch Linux packages, please use 'archpkg' and 'archaur' instead.""" For Arch Linux packages, please use 'archpkg' and 'archaur' instead."""
if not bs4Present: if not bs4Present:
irc.error("This command requires the Beautiful Soup 4 library. See" irc.error("This command requires the Beautiful Soup 4 library. See"
" https://github.com/GLolol/SupyPlugins/blob/master/README.md" " https://github.com/GLolol/SupyPlugins/blob/master/README.md"
"#pkginfo for instructions on how to install it.", Raise=True) "#pkginfo for instructions on how to install it.", Raise=True)
# Guess the distro from the suite name pkg = pkg.lower()
pkg, suite, pkg = map(str.lower, (pkg, suite, pkg)) distro = self._getDistro(release)
if suite.startswith(("oldstable","squeeze","wheezy","stable", try:
"jessie","testing","sid","unstable")): url = self.addrs[distro] + "{}/{}".format(release, pkg)
distro = "debian" except KeyError:
else: distro = "ubuntu" irc.error('Unknown distribution.', Raise=True)
url = self.addrs[distro] + "{}/{}".format(suite, pkg)
try: try:
fd = utils.web.getUrl(url).decode("utf-8") fd = utils.web.getUrl(url).decode("utf-8")
except Exception as e: except utils.web.Error as e:
irc.error(str(e), Raise=True) irc.error(str(e), Raise=True)
soup = BeautifulSoup(fd) soup = BeautifulSoup(fd)
if "Error" in soup.title.string: if "Error" in soup.title.string:
@ -129,31 +143,34 @@ class PkgInfo(callbacks.Plugin):
# Get package information from the meta tags # Get package information from the meta tags
keywords = soup.find('meta', attrs={"name":"Keywords"})["content"] keywords = soup.find('meta', attrs={"name":"Keywords"})["content"]
keywords = keywords.replace(",","").split() keywords = keywords.replace(",","").split()
irc.reply("Package: \x02{} ({})\x02 in {} - {}; View more at: {}".format(pkg, irc.reply("Package: \x02{} ({})\x02 in {} - {}; View more at: {}".format(pkg,
keywords[-1], keywords[1], desc, url)) keywords[-1], keywords[1], desc, url))
package = wrap(package, ['somethingWithoutSpaces', 'somethingWithoutSpaces']) pkg = wrap(package, ['somethingWithoutSpaces', 'somethingWithoutSpaces'])
def vlist(self, irc, msg, args, distro, pkg, opts): def vlist(self, irc, msg, args, distro, pkg, opts):
"""<distribution> <package> [--source] """<distribution> <package> [--source]
Fetches all available version of <package> in <distribution>, if Fetches all available version of <package> in <distribution>, if
such package exists. Supported entries for <distribution> such package exists. Supported entries for <distribution>
include: 'debian', 'ubuntu', 'derivatives', and 'all'. If include 'debian', 'ubuntu', 'derivatives', and 'all'. If
--source is given, search for packages by source package --source is given, search for packages by source package
name.""" name."""
pkg, distro = map(str.lower, (pkg, distro)) pkg, distro = map(str.lower, (pkg, distro))
supported = ("debian", "ubuntu", "derivatives", "all")
if distro not in supported:
distro = self._getDistro(distro)
d = self.MadisonParse(pkg, distro, useSource='source' in dict(opts)) d = self.MadisonParse(pkg, distro, useSource='source' in dict(opts))
if not d: irc.error("No results found.",Raise=True) if not d: irc.error("No results found.",Raise=True)
try: try:
d += " View more at: {}search?keywords={}".format(self.addrs[distro], pkg) d += " View more at: {}search?keywords={}".format(self.addrs[distro], pkg)
except KeyError: except KeyError:
pass pass
irc.reply(d) irc.reply(d)
vlist = wrap(vlist, ['somethingWithoutSpaces', 'somethingWithoutSpaces', getopts({'source':''})]) vlist = wrap(vlist, ['somethingWithoutSpaces', 'somethingWithoutSpaces', getopts({'source':''})])
def archpkg(self, irc, msg, args, pkg, opts): def archpkg(self, irc, msg, args, pkg, opts):
"""<package> [--exact] """<package> [--exact]
Looks up <package> in the Arch Linux package repositories. Looks up <package> in the Arch Linux package repositories.
If --exact is given, will output only exact matches. If --exact is given, will output only exact matches.
""" """
@ -179,10 +196,10 @@ class PkgInfo(callbacks.Plugin):
irc.reply('Found {} results: {}'.format(count,', '.join(f))) irc.reply('Found {} results: {}'.format(count,', '.join(f)))
else: irc.error("No results found.",Raise=True) else: irc.error("No results found.",Raise=True)
archpkg = wrap(archpkg, ['somethingWithoutSpaces', getopts({'exact':''})]) archpkg = wrap(archpkg, ['somethingWithoutSpaces', getopts({'exact':''})])
def archaur(self, irc, msg, args, pkg): def archaur(self, irc, msg, args, pkg):
"""<package> """<package>
Looks up <package> in the Arch Linux AUR.""" Looks up <package> in the Arch Linux AUR."""
pkg = pkg.lower() pkg = pkg.lower()
baseurl = 'https://aur.archlinux.org/rpc.php?type=search&' baseurl = 'https://aur.archlinux.org/rpc.php?type=search&'
@ -204,7 +221,7 @@ class PkgInfo(callbacks.Plugin):
verboseInfo = " [ID:{} Votes:{}]".format(x['ID'], x['NumVotes']) verboseInfo = " [ID:{} Votes:{}]".format(x['ID'], x['NumVotes'])
s += "{} - {} \x02({}{})\x02, ".format(x['Name'],x['Description'],x['Version'], verboseInfo) s += "{} - {} \x02({}{})\x02, ".format(x['Name'],x['Description'],x['Version'], verboseInfo)
irc.reply(s[:-2]) # cut off the ", " at the end irc.reply(s[:-2]) # cut off the ", " at the end
else: else:
irc.error("No results found.", Raise=True) irc.error("No results found.", Raise=True)
archaur = wrap(archaur, ['somethingWithoutSpaces']) archaur = wrap(archaur, ['somethingWithoutSpaces'])
@ -217,13 +234,15 @@ class PkgInfo(callbacks.Plugin):
" https://github.com/GLolol/SupyPlugins/blob/master/README.md" " https://github.com/GLolol/SupyPlugins/blob/master/README.md"
"#pkginfo for instructions on how to install it.", Raise=True) "#pkginfo for instructions on how to install it.", Raise=True)
distro = distro.lower() distro = distro.lower()
if distro not in ("debian", "ubuntu"):
distro = self._getDistro(distro)
try: try:
url = '%ssearch?keywords=%s' % (self.addrs[distro], quote(query)) url = '%ssearch?keywords=%s' % (self.addrs[distro], quote(query))
except KeyError: except KeyError:
irc.error('Unknown distribution.', Raise=True) irc.error('Unknown distribution.', Raise=True)
try: try:
fd = utils.web.getUrl(url).decode("utf-8") fd = utils.web.getUrl(url).decode("utf-8")
except Exception as e: except utils.web.Error as e:
irc.error(str(e), Raise=True) irc.error(str(e), Raise=True)
soup = BeautifulSoup(fd) soup = BeautifulSoup(fd)
# Debian/Ubuntu use h3 for result names in the format 'Package abcd' # Debian/Ubuntu use h3 for result names in the format 'Package abcd'
@ -250,7 +269,7 @@ class PkgInfo(callbacks.Plugin):
def mintpkg(self, irc, msg, args, release, query, opts): def mintpkg(self, irc, msg, args, release, query, opts):
"""<release> <package> [--exact] """<release> <package> [--exact]
Looks up <package> in Linux Mint's repositories.""" Looks up <package> in Linux Mint's repositories."""
if not bs4Present: if not bs4Present:
irc.error("This command requires the Beautiful Soup 4 library. See" irc.error("This command requires the Beautiful Soup 4 library. See"
@ -259,7 +278,7 @@ class PkgInfo(callbacks.Plugin):
addr = 'http://packages.linuxmint.com/list.php?release=' + quote(release) addr = 'http://packages.linuxmint.com/list.php?release=' + quote(release)
try: try:
fd = utils.web.getUrl(addr).decode("utf-8") fd = utils.web.getUrl(addr).decode("utf-8")
except Exception as e: except utils.web.Error as e:
irc.error(str(e), Raise=True) irc.error(str(e), Raise=True)
soup = BeautifulSoup(fd) soup = BeautifulSoup(fd)
# Linux Mint puts their package lists in tables # Linux Mint puts their package lists in tables

View File

@ -33,13 +33,13 @@ from supybot.test import *
class PkgInfoTestCase(PluginTestCase): class PkgInfoTestCase(PluginTestCase):
plugins = ('PkgInfo',) plugins = ('PkgInfo',)
def testPackageCommandBasics(self): def testPkgCommand(self):
self.assertRegexp('package sid bash', 'Package: .*?bash' self.assertRegexp('pkg sid bash', 'Package: .*?bash'
' .*?; View more at: .*?packages.debian.org/sid/bash') ' .*?; View more at: .*?packages.debian.org/sid/bash')
self.assertRegexp('package trusty apt', 'Package: .*?apt' self.assertRegexp('pkg trusty apt', 'Package: .*?apt'
' .*?; View more at: .*?packages.ubuntu.com/trusty/apt') ' .*?; View more at: .*?packages.ubuntu.com/trusty/apt')
self.assertError('package afdsfsadf asfasfasf') self.assertError('pkg afdsfsadf asfasfasf')
self.assertRegexp('package sid afsadfasfsa', 'no such package', re.I) self.assertRegexp('pkg sid afsadfasfsa', 'no such package', re.I)
def testVlistCommandBasics(self): def testVlistCommandBasics(self):
self.assertError('vlist all afdsafas') self.assertError('vlist all afdsafas')