Packages: Remove plugin.
parent
0096931e15
commit
5f4817d40f
|
@ -1,39 +0,0 @@
|
|||
This plugin is a packages downloadeder and installer.
|
||||
It handles basic dependencies, based on tags.
|
||||
|
||||
Repositories must have a root JSON file, that uses the fellowing
|
||||
format:
|
||||
{
|
||||
"repository": {
|
||||
"maintainers": {
|
||||
"ProgVal": "progval@gmail.com",
|
||||
},
|
||||
"repo-name": "Main packages repository",
|
||||
"repo-url": "http://packages.supybot.fr.cr",
|
||||
"project-name": "Supybot-fr",
|
||||
"project-url": "http://supybot.fr.cr"
|
||||
}
|
||||
"packages": [
|
||||
{
|
||||
"name": "Trigger",
|
||||
"version": "0.1",
|
||||
"author": [
|
||||
"Valentin Lorentz",
|
||||
"ProgVal",
|
||||
"progval@gmail.com"
|
||||
],
|
||||
"info-url": "http://supybot.fr.cr/Trigger",
|
||||
"download-url": "./Trigger-0.1.tar",
|
||||
"requires": {
|
||||
"package-installer": "0.1"
|
||||
},
|
||||
"suggests": {
|
||||
"i18n": "0.1",
|
||||
"conditional": "0.1"
|
||||
},
|
||||
"provides": {
|
||||
"trigger": "0.1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
###
|
||||
# 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.
|
||||
|
||||
###
|
||||
|
||||
"""
|
||||
Packages is a packaging system for Supybot plugins.
|
||||
"""
|
||||
|
||||
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__ = "0.2.1"
|
||||
|
||||
# XXX Replace this with an appropriate author or supybot.Author instance.
|
||||
if not hasattr(supybot.authors, 'progval'):
|
||||
supybot.authors.progval = supybot.Author('Valentin Lorentz', 'ProgVal',
|
||||
'progval@gmail.com')
|
||||
__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/Packages/download'
|
||||
|
||||
import config
|
||||
import plugin
|
||||
import packaging
|
||||
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
|
||||
|
||||
try:
|
||||
world.features.update(provides)
|
||||
except:
|
||||
world.features = packaging.provides
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
|
@ -1,58 +0,0 @@
|
|||
###
|
||||
# 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
|
||||
try:
|
||||
from supybot.i18n import PluginInternationalization
|
||||
from supybot.i18n import internationalizeDocstring
|
||||
_ = PluginInternationalization('Packages')
|
||||
except:
|
||||
# This are useless functions that's allow to run the plugin on a bot
|
||||
# without the i18n plugin
|
||||
_ = lambda x:x
|
||||
internationalizeDocstring = lambda x:x
|
||||
|
||||
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('Packages', True)
|
||||
|
||||
|
||||
Packages = conf.registerPlugin('Packages')
|
||||
# This is where your configuration variables (if any) should go. For example:
|
||||
# conf.registerGlobalValue(Packages, 'someConfigVariableName',
|
||||
# registry.Boolean(False, _("""Help for someConfigVariableName.""")))
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
|
@ -1,148 +0,0 @@
|
|||
#!/usr/bin/env python2.7
|
||||
|
||||
###
|
||||
# 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 __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import atexit
|
||||
import tarfile
|
||||
import optparse
|
||||
|
||||
import supybot.world as world
|
||||
unregister = [world.makeDriversDie, world.makeIrcsDie, world.startDying,
|
||||
world.finished, world.upkeep]
|
||||
|
||||
import plugin # I mean the Supybot plugin, the one which should be distributed
|
||||
# with this script and is runned by Supybot.
|
||||
|
||||
def main(filename):
|
||||
with tarfile.open(name=filename, mode='r:*') as file_:
|
||||
directory = plugin.getDirectory(file_)
|
||||
if not directory:
|
||||
print('%s is not a valid package.' % filename)
|
||||
return
|
||||
class packaging:
|
||||
"""Namespace for runned code"""
|
||||
exec(file_.extractfile('%s/packaging.py' % directory).read())
|
||||
class init:
|
||||
"""Namespace for runned code"""
|
||||
exec(file_.extractfile('%s/__init__.py' % directory).read())
|
||||
def getPrettyJsonFromDict(dict_):
|
||||
output = ''
|
||||
for key, value in dict_.items():
|
||||
output += """
|
||||
"%s": "%s",""" % (key, value)
|
||||
if output != '':
|
||||
output = output[0:-1] # Remove the ending comma
|
||||
return output
|
||||
doc = init.__doc__
|
||||
if doc.startswith('\n'):
|
||||
doc = doc[1:]
|
||||
if doc.endswith('\n'):
|
||||
doc = doc[0:-1]
|
||||
doc = doc.replace('\n', ' ')
|
||||
if doc.startswith('Add a description of the plugin'):
|
||||
doc = ''
|
||||
output = """
|
||||
{
|
||||
"name": "%(name)s",
|
||||
"version": "%(version)s",
|
||||
"author": [
|
||||
"%(author_name)s",
|
||||
"%(author_nick)s",
|
||||
"%(author_email)s"
|
||||
],
|
||||
"info-url": "%(info_url)s",
|
||||
"download-url": "./%(name)s-%(version)s.tar",
|
||||
"description": "%(description)s",
|
||||
"requires": {%(requires)s
|
||||
},
|
||||
"suggests": {%(suggests)s
|
||||
},
|
||||
"provides": {%(provides)s
|
||||
}
|
||||
}""" % {'name': directory,
|
||||
'version': init.__version__,
|
||||
'author_name': init.__author__.name,
|
||||
'author_nick': init.__author__.nick,
|
||||
'author_email': init.__author__.email,
|
||||
'info_url': init.__url__,
|
||||
'description': doc.replace('"', '\\"'),
|
||||
'requires': getPrettyJsonFromDict(packaging.requires),
|
||||
'suggests': getPrettyJsonFromDict(packaging.suggests),
|
||||
'provides': getPrettyJsonFromDict(packaging.provides)}
|
||||
return output
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = optparse.OptionParser(usage='Usage: %prog Package.tar',
|
||||
version='Supybot Packager 0.1')
|
||||
(options, args) = parser.parse_args()
|
||||
if len(args) > 0:
|
||||
filename = args[0]
|
||||
output = main(filename)
|
||||
else:
|
||||
output = """
|
||||
{
|
||||
"repository": {
|
||||
"maintainers": {
|
||||
"ProgVal": "progval@gmail.com"
|
||||
},
|
||||
"repo-name": "Main packages repository",
|
||||
"repo-url": "http://packages.supybot.fr.cr",
|
||||
"project-name": "Supybot-fr",
|
||||
"project-url": "http://supybot.fr.cr"
|
||||
},
|
||||
"packages": ["""
|
||||
addComma = False
|
||||
for filename in os.listdir('.'):
|
||||
if not filename.endswith('.tar'):
|
||||
continue
|
||||
if addComma:
|
||||
output += ','
|
||||
output += main(filename)
|
||||
addComma = True
|
||||
output += """
|
||||
]
|
||||
}"""
|
||||
if sys.version_info > (3, 0, 0):
|
||||
# clean
|
||||
for function in unregister:
|
||||
atexit.unregister(function)
|
||||
else:
|
||||
# less clean
|
||||
for function in unregister:
|
||||
atexit._exithandlers.remove((function, (), {}))
|
||||
if output is not None:
|
||||
print(output)
|
|
@ -1 +0,0 @@
|
|||
# Stub so local is a module, used for third-party modules
|
|
@ -1,152 +0,0 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Supybot-fr\n"
|
||||
"POT-Creation-Date: 2011-08-21 02:16+CEST\n"
|
||||
"PO-Revision-Date: 2011-08-23 19:33+0200\n"
|
||||
"Last-Translator: skizzhg <skizzhg@gmx.com>\n"
|
||||
"Language-Team: Italian <skizzhg@gmx.com>\n"
|
||||
"Language: it\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
|
||||
#: plugin.py:62
|
||||
#, docstring
|
||||
msgid "Returns -1, 0, or 1, depending on the newest version."
|
||||
msgstr "Restituisce -1, 0 o 1 a seconda della versione più recente."
|
||||
|
||||
#: plugin.py:80
|
||||
#, docstring
|
||||
msgid ""
|
||||
"Tries to find the directory where plugin files are. Returns None\n"
|
||||
" if it is not found or if any file is missing."
|
||||
msgstr ""
|
||||
"Tenta di trovare la directory dove risiedono i file dei plugin. Restituisce\n"
|
||||
" \"None\" se non trovata o se un file è mancante."
|
||||
|
||||
#: plugin.py:118
|
||||
#, docstring
|
||||
msgid ""
|
||||
"Add the help for \"@plugin help Packages\" here\n"
|
||||
" This should describe *how* to use this plugin."
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:124
|
||||
#, docstring
|
||||
msgid ""
|
||||
"<filename> [--force]\n"
|
||||
"\n"
|
||||
" Installs the package. If the package has been downloaded with Packages,\n"
|
||||
" just give the package name; otherwise, give the full path (including\n"
|
||||
" the extension).\n"
|
||||
" If given, --force disables sanity checks (usage is deprecated)."
|
||||
msgstr ""
|
||||
"<nome_file> [--force]\n"
|
||||
"\n"
|
||||
" Installa un pacchetto. Se questo è stato scaricato con Packages è sufficiente\n"
|
||||
" il nome del pacchetto, altrimenti è necessario fornire il percorso completo\n"
|
||||
" (inclusa l'estensione). Se specificato, --force disabilita il controllo\n"
|
||||
" dell'integrità dei dati (il suo uso è deprecato)."
|
||||
|
||||
#: plugin.py:137
|
||||
msgid "Cannot open the package. Are you sure it is readable, it is a tarball and it is not corrupted?"
|
||||
msgstr "Impossibile aprire il pacchetto; sei certo che sia un archivio tar leggibile e non danneggiato?"
|
||||
|
||||
#: plugin.py:143
|
||||
msgid "The file is not a valid package."
|
||||
msgstr "Il file non è un pacchetto valido."
|
||||
|
||||
#: plugin.py:146
|
||||
#, docstring
|
||||
msgid "Namespace for runned code"
|
||||
msgstr "Namespace per il codice eseguito"
|
||||
|
||||
#: plugin.py:152
|
||||
msgid "%s (missing)"
|
||||
msgstr "%s (mancante)"
|
||||
|
||||
#: plugin.py:154
|
||||
msgid "%s (>=%s needed, but %s available)"
|
||||
msgstr "%s (>=%s necessaria ma %s disponibile)"
|
||||
|
||||
#: plugin.py:157
|
||||
msgid "Missing dependency(ies): "
|
||||
msgstr "Dipendenze mancanti:"
|
||||
|
||||
#: plugin.py:163
|
||||
msgid "No writable plugin directory found."
|
||||
msgstr "Non è stata trovata nessuna directory del plugin scrivibile."
|
||||
|
||||
#: plugin.py:174
|
||||
#, docstring
|
||||
msgid ""
|
||||
"<package> [--version <version>] [--repo <repository url>]\n"
|
||||
"\n"
|
||||
" Downloads the <package> at the <repository url>.\n"
|
||||
" <version> defaults to the latest version available.\n"
|
||||
" <repository url> defaults to http://packages.supybot.fr.cr/"
|
||||
msgstr ""
|
||||
"<pacchetto> [--version <versione>] [--repo <URL repository>]\n"
|
||||
"\n"
|
||||
" Scarica <pacchetto> da <URL repository>.\n"
|
||||
" <versione> è in modo predefinito l'ultima disponibile, mentre\n"
|
||||
" <URL repository> predefinito è http://packages.supybot.fr.cr/"
|
||||
|
||||
#: plugin.py:187
|
||||
msgid "Bad formed url."
|
||||
msgstr "Formato URL errato."
|
||||
|
||||
#: plugin.py:195 plugin.py:258 plugin.py:308 plugin.py:350
|
||||
msgid "Server's JSON is bad formed."
|
||||
msgstr "Il server JSON è errato."
|
||||
|
||||
#: plugin.py:212
|
||||
msgid "No packages matches your query."
|
||||
msgstr "Nessun pacchetto corrisponde alla richiesta."
|
||||
|
||||
#: plugin.py:247
|
||||
#, docstring
|
||||
msgid ""
|
||||
"[<repository url>]\n"
|
||||
"\n"
|
||||
" Checks for updates for loaded plugins at the <repository url>.\n"
|
||||
" <repository url> defaults to http://packages.supybot.fr.cr/"
|
||||
msgstr ""
|
||||
"[<URL repository>]\n"
|
||||
"\n"
|
||||
" Cerca aggiornamenti per i plugin caricati su <URL repository>,\n"
|
||||
" l'indirizzo predefinito è http://packages.supybot.fr.cr/"
|
||||
|
||||
#: plugin.py:276
|
||||
msgid "All loaded plugins are up to date :)"
|
||||
msgstr "Tutti i plugin caricati sono aggiornati :)"
|
||||
|
||||
#: plugin.py:283
|
||||
#, docstring
|
||||
msgid ""
|
||||
"[<repository url>] [--name <name>] [--version <version>] [--author <author>] [<description>]\n"
|
||||
"\n"
|
||||
" Searches the packages matching the query in the <repository url>.\n"
|
||||
" <repository url> defaults to http://packages.supybot.fr.cr"
|
||||
msgstr ""
|
||||
"[<URL repository>] [--name <nome>] [--version <versione>] [--author <autore>] [<descrizione>]\n"
|
||||
"\n"
|
||||
" Cerca i pacchetti corrispondenti alla richiesta in <URL repository>,\n"
|
||||
" l'indirizzo predefinito è http://packages.supybot.fr.cr"
|
||||
|
||||
#: plugin.py:334
|
||||
#, docstring
|
||||
msgid ""
|
||||
"[<repository url>] <package> [<version>] [--author-full]\n"
|
||||
"\n"
|
||||
" Displays informations about the <package>, at the given <version>.\n"
|
||||
" <repository url> defaults to http://packages.supybot.fr.cr/ and\n"
|
||||
" <version> defaults to the latest available."
|
||||
msgstr ""
|
||||
"[<URL repository>] <pacchetto> [<versione>] [--author-full]\n"
|
||||
"\n"
|
||||
" Mostra le informazioni di <pacchetto> alla data <versione>.\n"
|
||||
" <URL repository> predefinito è http://packages.supybot.fr.cr/\n"
|
||||
" mentre <versione> è in modo predefinito l'ultima disponibile."
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
#!/usr/bin/env python2.7
|
||||
|
||||
###
|
||||
# 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 os
|
||||
import sys
|
||||
import atexit
|
||||
import tarfile
|
||||
import optparse
|
||||
|
||||
import supybot.world as world
|
||||
unregister = [world.makeDriversDie, world.makeIrcsDie, world.startDying,
|
||||
world.finished, world.upkeep]
|
||||
if sys.version_info > (3, 0, 0):
|
||||
# clean
|
||||
for function in unregister:
|
||||
atexit.unregister(function)
|
||||
else:
|
||||
# less clean
|
||||
for function in unregister:
|
||||
atexit._exithandlers.remove((function, (), {}))
|
||||
|
||||
def addToArchive(archive, path):
|
||||
for item in os.listdir(path):
|
||||
if item.startswith('.') or item.endswith('~') or \
|
||||
item.endswith('.swp') or item.endswith('.swo') or \
|
||||
item.endswith('.pyc') or item.endswith('.pyo'):
|
||||
continue
|
||||
itemPath = os.path.join(path, item)
|
||||
archive.add(itemPath, recursive=False)
|
||||
if os.path.isdir(itemPath):
|
||||
addToArchive(archive, itemPath)
|
||||
|
||||
def main(dirname):
|
||||
if dirname.endswith('/'):
|
||||
dirname = dirname[0:-1]
|
||||
class init:
|
||||
"""Namespace for runned code"""
|
||||
exec(open('%s/__init__.py' % dirname))
|
||||
assert init.__version__ != '', 'Version is empty'
|
||||
assert hasattr(init, '__url__'), 'Has no __url__'
|
||||
path = '%s-%s.tar' % (dirname, init.__version__)
|
||||
try:
|
||||
os.unlink(path)
|
||||
except OSError:
|
||||
# Does not exist
|
||||
pass
|
||||
with tarfile.open(path, 'a') as archive:
|
||||
addToArchive(archive, dirname)
|
||||
names = archive.getnames()
|
||||
for name in ('__init__', 'config', 'plugin', 'test', 'packaging'):
|
||||
assert '%s/%s.py' % (dirname, name) in names, \
|
||||
'%s.py is missing' % name
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = optparse.OptionParser(usage='Usage: %prog Package.tar',
|
||||
version='Supybot Packager 0.1')
|
||||
(options, args) = parser.parse_args()
|
||||
assert len(args) > 0
|
||||
dirname = args[0]
|
||||
output = main(dirname)
|
|
@ -1,130 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2011-08-21 02:16+CEST\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: ENCODING\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
#: plugin.py:62
|
||||
#, docstring
|
||||
msgid "Returns -1, 0, or 1, depending on the newest version."
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:80
|
||||
#, docstring
|
||||
msgid ""
|
||||
"Tries to find the directory where plugin files are. Returns None\n"
|
||||
" if it is not found or if any file is missing."
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:118
|
||||
#, docstring
|
||||
msgid ""
|
||||
"Add the help for \"@plugin help Packages\" here\n"
|
||||
" This should describe *how* to use this plugin."
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:124
|
||||
#, docstring
|
||||
msgid ""
|
||||
"<filename> [--force]\n"
|
||||
"\n"
|
||||
" Installs the package. If the package has been downloaded with Package,\n"
|
||||
" just give the package name; otherwise, give the full path (including\n"
|
||||
" the extension).\n"
|
||||
" If given, --force disables sanity checks (usage is deprecated)."
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:137
|
||||
msgid "Cannot open the package. Are you sure it is readable, it is a tarball and it is not corrupted?"
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:143
|
||||
msgid "The file is not a valid package."
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:146
|
||||
#, docstring
|
||||
msgid "Namespace for runned code"
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:152
|
||||
msgid "%s (missing)"
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:154
|
||||
msgid "%s (>=%s needed, but %s available)"
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:157
|
||||
msgid "Missing dependency(ies) : "
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:163
|
||||
msgid "No writable plugin directory found."
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:174
|
||||
#, docstring
|
||||
msgid ""
|
||||
"<package> [--version <version>] [--repo <repository url>]\n"
|
||||
"\n"
|
||||
" Downloads the <package> at the <repository url>.\n"
|
||||
" <version> defaults to the latest version available.\n"
|
||||
" <repository url> defaults to http://packages.supybot.fr.cr/"
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:187
|
||||
msgid "Bad formed url."
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:195 plugin.py:258 plugin.py:308 plugin.py:350
|
||||
msgid "Server's JSON is bad formed."
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:212
|
||||
msgid "No packages matches your query."
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:247
|
||||
#, docstring
|
||||
msgid ""
|
||||
"[<repository url>]\n"
|
||||
"\n"
|
||||
" Checks for updates for loaded plugins at the <repository url>.\n"
|
||||
" <repository url> defaults to http://packages.supybot.fr.cr/"
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:276
|
||||
msgid "All loaded plugins are up to date :)"
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:283
|
||||
#, docstring
|
||||
msgid ""
|
||||
"[<repository url>] [--name <name>] [--version <version>] [--author <author>] [<description>]\n"
|
||||
"\n"
|
||||
" Searches the packages matching the query in the <repository url>.\n"
|
||||
" <repository url> defaults to http://packages.supybot.fr.cr"
|
||||
msgstr ""
|
||||
|
||||
#: plugin.py:334
|
||||
#, docstring
|
||||
msgid ""
|
||||
"[<repository url>] <package> [<version>] [--author-full]\n"
|
||||
"\n"
|
||||
" Displays informations about the <package>, at the given <version>.\n"
|
||||
" <repository url> defaults to http://packages.supybot.fr.cr/ and\n"
|
||||
" <version> defaults to the latest available."
|
||||
msgstr ""
|
||||
|
|
@ -1,392 +0,0 @@
|
|||
###
|
||||
# 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 re
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import tarfile
|
||||
import supybot.conf as conf
|
||||
import supybot.utils as utils
|
||||
import supybot.world as world
|
||||
from supybot.commands import *
|
||||
import supybot.plugins as plugins
|
||||
import supybot.ircutils as ircutils
|
||||
import supybot.callbacks as callbacks
|
||||
try:
|
||||
from supybot.i18n import PluginInternationalization
|
||||
from supybot.i18n import internationalizeDocstring
|
||||
_ = PluginInternationalization('Packages')
|
||||
except:
|
||||
# This are useless functions that's allow to run the plugin on a bot
|
||||
# without the i18n plugin
|
||||
_ = lambda x:x
|
||||
internationalizeDocstring = lambda x:x
|
||||
|
||||
if not hasattr(world, 'features'):
|
||||
world.features = {}
|
||||
world.features.update({'package-installer': '0.2'})
|
||||
|
||||
BIGGER = 1
|
||||
EQUAL = 0
|
||||
LOWER = -1
|
||||
|
||||
def compareVersions(v1, v2):
|
||||
"""Returns -1, 0, or 1, depending on the newest version."""
|
||||
def split(version):
|
||||
splitted = version.split('+')
|
||||
patches = splitted[1:]
|
||||
numbers = splitted[0].split('.')
|
||||
return numbers.extend(patches)
|
||||
for index in range(0, min(len(v1), len(v2))):
|
||||
if v1[index] < v2[index]:
|
||||
return LOWER
|
||||
elif v1[index] > v2[index]:
|
||||
return BIGGER
|
||||
if len(v1) < len(v2):
|
||||
return LOWER
|
||||
if len(v1) > len(v2):
|
||||
return BIGGER
|
||||
return EQUAL
|
||||
|
||||
def getDirectory(file_):
|
||||
"""Tries to find the directory where plugin files are. Returns None
|
||||
if it is not found or if any file is missing."""
|
||||
directory = None
|
||||
names = []
|
||||
for name in file_.getnames():
|
||||
assert not name.startswith('/')
|
||||
assert not name.startswith('../')
|
||||
assert ':' not in name # Prevents Windows drives and bad formed names
|
||||
if directory is not None and not name.startswith(directory + '/'):
|
||||
# No more than one directory at root
|
||||
return False
|
||||
elif directory is None:
|
||||
directory = name.split('/')[0]
|
||||
if '/' in name:
|
||||
assert name.startswith(directory + '/')
|
||||
else:
|
||||
assert name == directory
|
||||
names.append(name[len(directory)+1:])
|
||||
if directory is None:
|
||||
return None
|
||||
if not all([x in names for x in ('__init__.py', 'config.py',
|
||||
'plugin.py', 'packaging.py',
|
||||
'test.py')]):
|
||||
# I know, test.py is not necessary. But people who don't write
|
||||
# test case suck. More over, supybot-plugin-create automatically
|
||||
# creates this file for a long time, so it should be there.
|
||||
return None
|
||||
return directory
|
||||
|
||||
def getWritableDirectoryFromList(directories):
|
||||
for directory in directories:
|
||||
if os.access(directory, os.W_OK):
|
||||
return directory
|
||||
return None
|
||||
|
||||
|
||||
@internationalizeDocstring
|
||||
class Packages(callbacks.Plugin):
|
||||
"""Add the help for "@plugin help Packages" here
|
||||
This should describe *how* to use this plugin."""
|
||||
threaded = True
|
||||
|
||||
@internationalizeDocstring
|
||||
def install(self, irc, msg, args, filename, optlist):
|
||||
"""<filename> [--force]
|
||||
|
||||
Installs the package. If the package has been downloaded with Packages,
|
||||
just give the package name; otherwise, give the full path (including
|
||||
the extension).
|
||||
If given, --force disables sanity checks (usage is deprecated)."""
|
||||
filename = os.path.expanduser(filename)
|
||||
if os.path.sep not in filename:
|
||||
filename = os.path.join(conf.supybot.directories.data(), filename)
|
||||
filename += '.tar'
|
||||
try:
|
||||
file_ = tarfile.open(name=filename, mode='r:*')
|
||||
except:
|
||||
irc.error(_('Cannot open the package. Are you sure it is '
|
||||
'readable, it is a tarball and it is not '
|
||||
'corrupted?'))
|
||||
return
|
||||
directory = getDirectory(file_)
|
||||
if not directory:
|
||||
irc.error(_('The file is not a valid package.'))
|
||||
return
|
||||
class packaging:
|
||||
"""Namespace for runned code"""
|
||||
exec(file_.extractfile('%s/packaging.py' % directory).read())
|
||||
if not ('force', True) in optlist:
|
||||
failures = []
|
||||
for feature, version in packaging.requires.items():
|
||||
if feature not in world.features:
|
||||
failures.append(_('%s (missing)') % feature)
|
||||
elif compareVersions(world.features[feature], version) == LOWER:
|
||||
failures.append(_('%s (>=%s needed, but %s available)') %
|
||||
(feature, version, world.features[feature]))
|
||||
if failures != []:
|
||||
irc.error(_('Missing dependency(ies): ') +
|
||||
', '.join(failures))
|
||||
return
|
||||
directories = conf.supybot.directories.plugins()
|
||||
directory = getWritableDirectoryFromList(directories)
|
||||
if directory is None:
|
||||
irc.error(_('No writable plugin directory found.'))
|
||||
return
|
||||
file_.extractall(directory)
|
||||
irc.replySuccess()
|
||||
if hasattr(packaging, 'additionalReply'):
|
||||
irc.reply('The plugin provides this additional information: %s' %
|
||||
packaging.additionalReply)
|
||||
install = wrap(install, ['owner', 'filename', getopts({'force': ''})])
|
||||
|
||||
@internationalizeDocstring
|
||||
def download(self, irc, msg, args, name, optlist):
|
||||
"""<package> [--version <version>] [--repo <repository url>]
|
||||
|
||||
Downloads the <package> at the <repository url>.
|
||||
<version> defaults to the latest version available.
|
||||
<repository url> defaults to http://packages.supybot.fr.cr/"""
|
||||
# Parse and check parameters
|
||||
version = None
|
||||
repo = 'http://packages.supybot.fr.cr/'
|
||||
for key, value in optlist:
|
||||
if key == 'version': version = value
|
||||
elif key == 'repo': repo = value
|
||||
if __builtins__['any']([x in repo for x in ('?', '&')]):
|
||||
# Supybot rewrites any() in commands.py
|
||||
irc.error(_('Bad formed url.'))
|
||||
return
|
||||
selectedPackage = None
|
||||
|
||||
# Get server's index
|
||||
try:
|
||||
index = json.load(utils.web.getUrlFd(repo))
|
||||
except ValueError:
|
||||
irc.error(_('Server\'s JSON is bad formed.'))
|
||||
return
|
||||
|
||||
# Crawl the available packages list
|
||||
for package in index['packages']:
|
||||
if not package['name'] == name:
|
||||
continue
|
||||
if version is None and (
|
||||
selectedPackage == None or
|
||||
compareVersions(selectedPackage['version'],
|
||||
package['version']) == LOWER):
|
||||
# If not version given, and [no selected package
|
||||
# or selected package is older than this one]
|
||||
selectedPackage = package
|
||||
elif package['version'] == version:
|
||||
selectedPackage = package
|
||||
if selectedPackage is None:
|
||||
irc.error(_('No packages matches your query.'))
|
||||
return
|
||||
|
||||
# Determines the package's real URL
|
||||
# TODO: handle relative URL starting with /
|
||||
# FIXME: URL ending with /foobar.txt
|
||||
packageUrl = selectedPackage['download-url']
|
||||
if packageUrl.startswith('./'):
|
||||
packageUrl = repo
|
||||
if not packageUrl.endswith('/'):
|
||||
packageUrl += '/'
|
||||
packageUrl += selectedPackage['download-url']
|
||||
|
||||
# Write the package to the disk
|
||||
directory = conf.supybot.directories.data()
|
||||
assert os.access(directory, os.W_OK)
|
||||
path = os.path.join(directory, '%s.tar' % name)
|
||||
try:
|
||||
os.unlink(path)
|
||||
except OSError:
|
||||
# Does not exist
|
||||
pass
|
||||
with open(path, 'ab') as file_:
|
||||
try:
|
||||
file_.write(utils.web.getUrlFd(packageUrl).read())
|
||||
except utils.web.Error as e:
|
||||
irc.reply(e.args[0])
|
||||
return
|
||||
irc.replySuccess()
|
||||
download = wrap(download, ['owner', 'something',
|
||||
getopts({'version': 'something',
|
||||
'repo': 'httpUrl'})])
|
||||
|
||||
@internationalizeDocstring
|
||||
def checkupdates(self, irc, msg, args, repo):
|
||||
"""[<repository url>]
|
||||
|
||||
Checks for updates for loaded plugins at the <repository url>.
|
||||
<repository url> defaults to http://packages.supybot.fr.cr/"""
|
||||
if repo is None:
|
||||
repo = 'http://packages.supybot.fr.cr/'
|
||||
|
||||
# Get server's index
|
||||
try:
|
||||
index = json.load(utils.web.getUrlFd(repo))
|
||||
except ValueError:
|
||||
irc.error(_('Server\'s JSON is bad formed.'))
|
||||
return
|
||||
|
||||
# Crawl the index
|
||||
needUpdate = {}
|
||||
for package in index['packages']:
|
||||
if package['name'] in sys.modules and (
|
||||
not hasattr(sys.modules[package['name']], '__version__') or
|
||||
compareVersions(sys.modules[package['name']].__version__,
|
||||
package['version']) == LOWER):
|
||||
if package['name'] in needUpdate:
|
||||
if compareVersions(needUpdate[package['name']].__version__,
|
||||
package['version']) != LOWER:
|
||||
continue
|
||||
needUpdate.update({package['name']: package})
|
||||
|
||||
# Display results
|
||||
if needUpdate == {}:
|
||||
irc.reply(_('All loaded plugins are up to date :)'))
|
||||
else:
|
||||
irc.reply(', '.join(['%s (%s)' % (y['name'],y['version'])
|
||||
for x,y in needUpdate.items()]))
|
||||
checkupdates = wrap(checkupdates, ['owner', optional('httpUrl')])
|
||||
|
||||
def search(self, irc, msg, args, repo, optlist, description):
|
||||
"""[<repository url>] [--name <name>] [--version <version>]\
|
||||
[--author <author>] [<description>]
|
||||
|
||||
Searches the packages matching the query in the <repository url>.
|
||||
<repository url> defaults to http://packages.supybot.fr.cr"""
|
||||
# Parse the arguments
|
||||
if repo is None:
|
||||
repo = 'http://packages.supybot.fr.cr/'
|
||||
if description is None:
|
||||
description = ''
|
||||
if not __builtins__['any'](x in description for x in '*?'):
|
||||
description = '*%s*' % description
|
||||
optlist.append(('description', description))
|
||||
def glob2matcher(glob):
|
||||
glob = utils.python.glob2re(glob)
|
||||
return re.compile(glob).match
|
||||
matchers = {}
|
||||
for key, value in optlist:
|
||||
if value != None:
|
||||
matchers.update({key: glob2matcher(value)})
|
||||
|
||||
# Get server's index
|
||||
try:
|
||||
index = json.load(utils.web.getUrlFd(repo))
|
||||
except ValueError:
|
||||
irc.error(_('Server\'s JSON is bad formed.'))
|
||||
return
|
||||
|
||||
# Crawl packages index
|
||||
results = []
|
||||
for package in index['packages']:
|
||||
ok = True
|
||||
for key, matcher in matchers.items():
|
||||
if key in package and not matcher(str(package[key])):
|
||||
# If the packages index doesn't have this key, we consider
|
||||
# the key matched.
|
||||
ok = False
|
||||
break
|
||||
if ok:
|
||||
results.append(package)
|
||||
|
||||
# Display results
|
||||
reply = ['%s (%s)' % (x['name'],x['version']) for x in results]
|
||||
reply.sort()
|
||||
irc.reply(', '.join(reply))
|
||||
options = ['name', 'version', 'author']
|
||||
search = wrap(search, [optional('httpUrl'),
|
||||
getopts(dict([(x,'anything') for x in options])),
|
||||
optional('text')])
|
||||
|
||||
def info(self, irc, msg, args, repo, name, version, optlist):
|
||||
"""[<repository url>] <package> [<version>] [--author-full]
|
||||
|
||||
Displays informations about the <package>, at the given <version>.
|
||||
<repository url> defaults to http://packages.supybot.fr.cr/ and
|
||||
<version> defaults to the latest available."""
|
||||
# Parse the arguments
|
||||
if repo is None:
|
||||
repo = 'http://packages.supybot.fr.cr/'
|
||||
if version == '--author-full': # Bug in wrap()
|
||||
version = None
|
||||
optlist.append(('--author-full', True))
|
||||
|
||||
# Get server's index
|
||||
try:
|
||||
index = json.load(utils.web.getUrlFd(repo))
|
||||
except ValueError:
|
||||
irc.error(_('Server\'s JSON is bad formed.'))
|
||||
return
|
||||
|
||||
# Crawl the index
|
||||
selectedPackage = None
|
||||
for package in index['packages']:
|
||||
if package['name'] == name:
|
||||
if version is not None and package['version'] != version:
|
||||
continue
|
||||
if version is None and selectedPackage is not None and \
|
||||
compareVersions(selectedPackage['version'],
|
||||
package['version']) != LOWER:
|
||||
continue
|
||||
selectedPackage = package
|
||||
|
||||
# Display result
|
||||
if selectedPackage is None:
|
||||
irc.error('No such package/version.')
|
||||
return
|
||||
selectedPackage['author-name'] = selectedPackage['author'][0]
|
||||
selectedPackage['author-nick'] = selectedPackage['author'][1]
|
||||
selectedPackage['author-email'] = selectedPackage['author'][2]
|
||||
if ('author-full', True) in optlist:
|
||||
selectedPackage['author-string'] = '%s "%s" <%s>' % \
|
||||
tuple(selectedPackage['author'])
|
||||
else:
|
||||
selectedPackage['author-string'] = selectedPackage['author-name']
|
||||
for key in ('requires', 'suggests', 'provides'):
|
||||
selectedPackage[key] = ', '.join('%s (%s)' % x for x in
|
||||
selectedPackage[key].items())
|
||||
irc.reply(('%(name)s (version %(version)s) has been written by '
|
||||
'%(author-string)s and requires the fellowing flags: '
|
||||
'%(requires)s') % selectedPackage)
|
||||
info = wrap(info, [optional('httpUrl'), 'something',
|
||||
optional('something'), getopts({'author-full': ''})])
|
||||
|
||||
|
||||
|
||||
|
||||
Class = Packages
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|
|
@ -1,37 +0,0 @@
|
|||
###
|
||||
# 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 PackagesTestCase(PluginTestCase):
|
||||
plugins = ('Packages',)
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
Loading…
Reference in New Issue