diff --git a/plugins/PluginDownloader/README.txt b/plugins/PluginDownloader/README.txt new file mode 100644 index 000000000..d60b47a97 --- /dev/null +++ b/plugins/PluginDownloader/README.txt @@ -0,0 +1 @@ +Insert a description of your plugin here, with any notes, etc. about using it. diff --git a/plugins/PluginDownloader/__init__.py b/plugins/PluginDownloader/__init__.py new file mode 100644 index 000000000..7d92643b3 --- /dev/null +++ b/plugins/PluginDownloader/__init__.py @@ -0,0 +1,66 @@ +### +# Copyright (c) 2011, Valentin Lorentz +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +### + +""" +Add a description of the plugin (to be presented to the user inside the wizard) +here. This should describe *what* the plugin does. +""" + +import supybot +import supybot.world as world + +# Use this for the version of this plugin. You may wish to put a CVS keyword +# in here if you're keeping the plugin in CVS or some similar system. +__version__ = "" + +# XXX Replace this with an appropriate author or supybot.Author instance. +__author__ = supybot.authors.progval + +# This is a dictionary mapping supybot.Author instances to lists of +# contributions. +__contributors__ = {} + +# This is a url where the most recent plugin package can be downloaded. +__url__ = '' # 'http://supybot.com/Members/yourname/PluginDownloader/download' + +import config +import plugin +reload(plugin) # In case we're being reloaded. +# Add more reloads here if you add third-party modules and want them to be +# reloaded when this plugin is reloaded. Don't forget to import them as well! + +if world.testing: + import test + +Class = plugin.Class +configure = config.configure + + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/plugins/PluginDownloader/config.py b/plugins/PluginDownloader/config.py new file mode 100644 index 000000000..0a8db927f --- /dev/null +++ b/plugins/PluginDownloader/config.py @@ -0,0 +1,52 @@ +### +# Copyright (c) 2011, Valentin Lorentz +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +### + +import supybot.conf as conf +import supybot.registry as registry +from supybot.i18n import PluginInternationalization, internationalizeDocstring + +_ = PluginInternationalization('PluginDownloader') + +def configure(advanced): + # This will be called by supybot to configure this module. advanced is + # a bool that specifies whether the user identified himself as an advanced + # user or not. You should effect your configuration by manipulating the + # registry as appropriate. + from supybot.questions import expect, anything, something, yn + conf.registerPlugin('PluginDownloader', True) + + +PluginDownloader = conf.registerPlugin('PluginDownloader') +# This is where your configuration variables (if any) should go. For example: +# conf.registerGlobalValue(PluginDownloader, 'someConfigVariableName', +# registry.Boolean(False, _("""Help for someConfigVariableName."""))) + + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/plugins/PluginDownloader/local/__init__.py b/plugins/PluginDownloader/local/__init__.py new file mode 100644 index 000000000..e86e97b86 --- /dev/null +++ b/plugins/PluginDownloader/local/__init__.py @@ -0,0 +1 @@ +# Stub so local is a module, used for third-party modules diff --git a/plugins/PluginDownloader/plugin.py b/plugins/PluginDownloader/plugin.py new file mode 100644 index 000000000..cd8e95d7a --- /dev/null +++ b/plugins/PluginDownloader/plugin.py @@ -0,0 +1,153 @@ +### +# Copyright (c) 2011, Valentin Lorentz +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +### + +import json +import urllib + +import git + +import supybot.log as log +import supybot.utils as utils +from supybot.commands import * +import supybot.plugins as plugins +import supybot.ircutils as ircutils +import supybot.callbacks as callbacks +from supybot.i18n import PluginInternationalization, internationalizeDocstring + +_ = PluginInternationalization('PluginDownloader') + +class Repository: + pass + +class VersionnedRepository(Repository): + pass + +class GitRepository(VersionnedRepository): + pass + +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 != ''] + + + _apiUrl = 'http://github.com/api/v2/json' + def _query(self, type_, uri_end, args={}): + args = dict([(x,y) for x,y in args.items() if y is not None]) + url = '%s/%s/%s?%s' % (self._apiUrl, type_, uri_end, + urllib.urlencode(args)) + return json.load(utils.web.getUrlFd(url)) + + def getPluginList(self): + latestCommit = self._query( + 'repos', + 'show/%s/%s/branches' % ( + self._username, + self._reponame, + ) + )['branches']['master'] + treeHash = self._navigate(latestCommit, self._path) + if treeHash is None: + log.error(( + 'Cannot get plugins list from repository %s/%s ' + 'at Github' + ) % (self._username, self._reponame)) + return [] + nodes = self._query( + 'tree', + 'show/%s/%s/%s' % ( + self._username, + self._reponame, + treeHash, + ) + )['tree'] + plugins = [x['name'] for x in nodes if x['type'] == 'tree'] + return plugins + + def _navigate(self, treeHash, path): + if path == []: + return treeHash + tree = self._query( + 'tree', + 'show/%s/%s/%s' % ( + self._username, + self._reponame, + treeHash, + ) + )['tree'] + nodeName = path.pop(0) + for node in tree: + if node['name'] != nodeName: + continue + if node['type'] != 'tree': + return None + else: + return self._navigate(node['sha'], path) + # Remember we pop(0)ed the path + return None + +repositories = { + 'ProgVal': GithubRepository('ProgVal', 'Supybot-plugins'), + 'quantumlemur': GithubRepository( + 'quantumlemur', + 'Supybot-plugins' + ), + } + +class PluginDownloader(callbacks.Plugin): + """Add the help for "@plugin help PluginDownloader" here + This should describe *how* to use this plugin.""" + + @internationalizeDocstring + def repolist(self, irc, msg, args, repository): + """[] + + Displays the list of plugins in the . + If is not given, returns a list of available + repositories.""" + + global repositories + if repository is None: + irc.reply(_(', ').join([x for x in repositories])) + else: + plugins = repositories[repository].getPluginList() + if plugins == []: + irc.error(_('No plugin found in this repository.')) + else: + irc.reply(_(', ').join([x for x in plugins])) + repolist = wrap(repolist, [optional('something')]) + + +PluginDownloader = internationalizeDocstring(PluginDownloader) +Class = PluginDownloader + + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/PluginDownloader/test.py b/plugins/PluginDownloader/test.py new file mode 100644 index 000000000..6e49d0c20 --- /dev/null +++ b/plugins/PluginDownloader/test.py @@ -0,0 +1,41 @@ +### +# Copyright (c) 2011, Valentin Lorentz +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +### + +from supybot.test import * + +class PluginDownloaderTestCase(PluginTestCase): + plugins = ('PluginDownloader',) + + def testRepolist(self): + self.assertResponse('repolist', 'quantumlemur, ProgVal') + self.assertRegexp('repolist ProgVal', '(.*, )?AttackProtector(, .*)?') + + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: