PluginDownloader: add the @install command.

This commit is contained in:
Valentin Lorentz 2011-04-28 11:38:48 +02:00
parent 187ed38ecc
commit f18429fdf7
2 changed files with 116 additions and 2 deletions

View File

@ -28,12 +28,17 @@
###
import os
import json
import urllib
import urllib2
import tarfile
from cStringIO import StringIO
import git
import supybot.log as log
import supybot.conf as conf
import supybot.utils as utils
from supybot.commands import *
import supybot.plugins as plugins
@ -56,8 +61,18 @@ class GithubRepository(GitRepository):
def __init__(self, username, reponame, path='/'):
self._username = username
self._reponame = reponame
self._path = [x for x in path.split('/') if x != '']
if not path.startswith('/'):
path = '/' + path
if not path.endswith('/'):
path += '/'
self._path = path
self._downloadUrl = 'https://github.com/%s/%s/tarball/master' % \
(
self._username,
self._reponame,
)
_apiUrl = 'http://github.com/api/v2/json'
def _query(self, type_, uri_end, args={}):
@ -74,7 +89,8 @@ class GithubRepository(GitRepository):
self._reponame,
)
)['branches']['master']
treeHash = self._navigate(latestCommit, self._path)
path = [x for x in self._path.split('/') if x != '']
treeHash = self._navigate(latestCommit, path)
if treeHash is None:
log.error((
'Cannot get plugins list from repository %s/%s '
@ -114,6 +130,41 @@ class GithubRepository(GitRepository):
# Remember we pop(0)ed the path
return None
def install(self, plugin):
directories = conf.supybot.directories.plugins()
directory = self._getWritableDirectoryFromList(directories)
assert directory is not None
dirname = ''.join((self._path, plugin))
fileObject = urllib2.urlopen(self._downloadUrl)
fileObject2 = StringIO()
fileObject2.write(fileObject.read())
fileObject.close()
fileObject2.seek(0)
archive = tarfile.open(fileobj=fileObject2, mode='r:gz')
prefix = archive.getnames()[0]
try:
assert archive.getmember(prefix + dirname).isdir()
for file in archive.getmembers():
if file.name.startswith(prefix + dirname):
extractedFile = archive.extractfile(file)
newFileName = os.path.join(*file.name.split('/')[1:])
newFileName = os.path.join(directory, newFileName)
if extractedFile is None:
os.mkdir(newFileName)
else:
open(newFileName, 'a').write(extractedFile.read())
finally:
archive.close()
def _getWritableDirectoryFromList(self, directories):
for directory in directories:
if os.access(directory, os.W_OK):
return directory
return None
repositories = {
'ProgVal': GithubRepository('ProgVal', 'Supybot-plugins'),
'quantumlemur': GithubRepository(
@ -137,6 +188,11 @@ class PluginDownloader(callbacks.Plugin):
global repositories
if repository is None:
irc.reply(_(', ').join([x for x in repositories]))
elif repository not in repositories:
irc.error(_(
'This repository does not exist or is not known by '
'this bot.'
))
else:
plugins = repositories[repository].getPluginList()
if plugins == []:
@ -145,6 +201,28 @@ class PluginDownloader(callbacks.Plugin):
irc.reply(_(', ').join([x for x in plugins]))
repolist = wrap(repolist, [optional('something')])
@internationalizeDocstring
def install(self, irc, msg, args, repository, plugin):
"""<repository> <plugin>
Downloads and installs the <plugin> from the <repository>."""
global repositories
if repository not in repositories:
irc.error(_(
'This repository does not exist or is not known by '
'this bot.'
))
else:
try:
repositories[repository].install(plugin)
irc.replySuccess()
except Exception as e:
#FIXME: more detailed error message
log.error(str(e))
irc.error('The plugin could not be installed.')
install = wrap(install, ['owner', 'something', 'something'])
PluginDownloader = internationalizeDocstring(PluginDownloader)
Class = PluginDownloader

View File

@ -28,14 +28,50 @@
###
import os
import shutil
from supybot.test import *
pluginsPath = '%s/test-plugins' % os.getcwd()
class PluginDownloaderTestCase(PluginTestCase):
plugins = ('PluginDownloader',)
config = {'supybot.directories.plugins': [pluginsPath]}
def setUp(self):
PluginTestCase.setUp(self)
try:
shutil.rmtree(pluginsPath)
except:
pass
os.mkdir(pluginsPath)
def tearDown(self):
try:
shutil.rmtree(pluginsPath)
finally:
PluginTestCase.tearDown(self)
def testRepolist(self):
self.assertResponse('repolist', 'quantumlemur, ProgVal')
self.assertRegexp('repolist ProgVal', '(.*, )?AttackProtector(, .*)?')
def testInstallProgVal(self):
self.assertError('plugindownloader install ProgVal Listener')
self.assertNotError('plugindownloader install ProgVal AttackProtector')
self.assertError('plugindownloader install ProgVal Listener')
assert os.path.isdir(pluginsPath + '/AttackProtector/')
assert os.path.isfile(pluginsPath + '/AttackProtector/plugin.py')
assert os.path.isfile(pluginsPath + '/AttackProtector/config.py')
def testInstallQuantumlemur(self):
self.assertError('plugindownloader install quantumlemur AttackProtector')
self.assertNotError('plugindownloader install quantumlemur Listener')
self.assertError('plugindownloader install quantumlemur AttackProtector')
assert os.path.isdir(pluginsPath + '/Listener/')
assert os.path.isfile(pluginsPath + '/Listener/plugin.py')
assert os.path.isfile(pluginsPath + '/Listener/config.py')
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: