Packages: Remove plugin.

master
Valentin Lorentz 2013-03-25 17:20:52 +01:00
parent 0096931e15
commit 5f4817d40f
10 changed files with 0 additions and 1119 deletions

View File

@ -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"
}
}
]
}

View File

@ -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:

View File

@ -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:

View File

@ -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)

View File

@ -1 +0,0 @@
# Stub so local is a module, used for third-party modules

View File

@ -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."

View File

@ -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)

View File

@ -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 ""

View File

@ -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:

View File

@ -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: