From b882b449ecdfbbc5e5b108977c35492d6e46c5df Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Tue, 26 Nov 2013 18:13:56 +0100 Subject: [PATCH] PluginDownloader: If bot is running on Python 3, run 2to3 on installed plugins if they are detected as being designed for Python 2. --- plugins/PluginDownloader/plugin.py | 40 +++++++++++++++++++++++++++--- plugins/PluginDownloader/test.py | 7 ++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/plugins/PluginDownloader/plugin.py b/plugins/PluginDownloader/plugin.py index 0d63ec296..919e3b7e8 100644 --- a/plugins/PluginDownloader/plugin.py +++ b/plugins/PluginDownloader/plugin.py @@ -128,6 +128,7 @@ class GithubRepository(GitRepository): assert archive.getmember(prefix + dirname).isdir(), \ 'This is not a valid plugin (it is a file, not a directory).' + run_2to3 = sys.version_info[0] >= 3 for file in archive.getmembers(): if file.name.startswith(prefix + dirname): extractedFile = archive.extractfile(file) @@ -141,10 +142,44 @@ class GithubRepository(GitRepository): if extractedFile is None: os.mkdir(newFileName) else: - open(newFileName, 'ab').write(extractedFile.read()) + with open(newFileName, 'ab') as fd: + reload_imported = False + for line in extractedFile.readlines(): + if sys.version_info[0] >= 3: + if 'import reload' in line.decode(): + reload_imported = True + elif not reload_imported and \ + 'reload(' in line.decode(): + fd.write('from imp import reload\n' \ + .encode()) + reload_imported = True + fd.write(line) + if newFileName.endswith('__init__.py'): + with open(newFileName) as fd: + lines = list(filter(lambda x:'import plugin' in x, + fd.readlines())) + if lines and lines[0].startswith('from . import'): + # This should be already Python 3-compatible + run_2to3 = False finally: archive.close() del archive + if run_2to3: + try: + import lib2to3 + except ImportError: + return _('Plugin is probably not compatible with your ' + 'Python version (3.x) but could not be converted ' + 'because 2to3 is not installed.') + import subprocess + fixers = [] + subprocess.Popen(['2to3', '-wn', os.path.join(directory, plugin)]) \ + .wait() + return _('Plugin was designed for Python 2, but an attempt to ' + 'convert it to Python 3 has been made. There is no ' + 'garantee it will work, though.') + else: + return _('Plugin successfully installed.') def getInfo(self, plugin): archive = self._download(plugin) @@ -308,8 +343,7 @@ class PluginDownloader(callbacks.Plugin): irc.error(_('This plugin does not exist in this repository.')) else: try: - repositories[repository].install(plugin) - irc.replySuccess() + irc.reply(repositories[repository].install(plugin)) except Exception as e: import traceback traceback.print_exc() diff --git a/plugins/PluginDownloader/test.py b/plugins/PluginDownloader/test.py index 58c3a0d9b..7770e515e 100644 --- a/plugins/PluginDownloader/test.py +++ b/plugins/PluginDownloader/test.py @@ -29,6 +29,7 @@ ### import os +import sys import shutil from supybot.test import * @@ -97,6 +98,12 @@ class PluginDownloaderTestCase(PluginTestCase): 'Advanced Twitter plugin for Supybot, with capabilities ' 'handling, and per-channel user account.') + if sys.version_info[0] >= 3: + def test_2to3(self): + self.assertRegexp('plugindownloader install SpiderDave Pastebin', + 'convert') + self.assertNotError('load Pastebin') + if not network: class PluginDownloaderTestCase(PluginTestCase): pass