From 0fabbc9039c555bc79f6d535e058d6c66a57dbe8 Mon Sep 17 00:00:00 2001 From: sponge Date: Tue, 13 Mar 2012 09:49:15 +0000 Subject: [PATCH] Plugins: bugfix and defer update. --- .../src/net/i2p/router/web/PluginStarter.java | 24 ++++++++++++++++++- .../i2p/router/web/PluginUpdateHandler.java | 22 +++++++++-------- history.txt | 6 +++++ 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java b/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java index 5e6acb5d0f..d6f8be9a11 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java @@ -2,7 +2,6 @@ package net.i2p.router.web; import java.io.File; import java.io.IOException; -import java.lang.ClassLoader; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; @@ -198,7 +197,30 @@ public class PluginStarter implements Runnable { return false; } + // Do we need to extract an update? + File pluginUpdate = new File(ctx.getConfigDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName + "/app.xpi2p.zip" ); + if(pluginUpdate.exists()) { + // Compare the start time of the router with the plugin. + List contexts = RouterContext.listContexts(); + if ( (contexts == null) || (contexts.isEmpty()) ) + throw new IllegalStateException("No contexts. This is usually because the router is either starting up or shutting down."); + if(contexts.get(0).router().getWhenStarted() > pluginUpdate.lastModified()) { + if (!FileUtil.extractZip(pluginUpdate, pluginDir)) { + pluginUpdate.delete(); + String foo = "Plugin '" + appName + "' failed to update! File '" + pluginUpdate +"' deleted. You may need to remove and install the plugin again."; + log.error(foo); + disablePlugin(appName); + throw new Exception(foo); + } else { + pluginUpdate.delete(); + // Need to always log this, and log.logAlways() did not work for me. + System.err.println("INFO: Plugin updated: " + appName); + } + } // silently fail to update, because we have not restarted. + } + Properties props = pluginProperties(ctx, appName); + String minVersion = ConfigClientsHelper.stripHTML(props, "min-i2p-version"); if (minVersion != null && (new VersionComparator()).compare(CoreVersion.VERSION, minVersion) < 0) { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java index cd7bb8f1a7..5d69c4bfc2 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java @@ -14,6 +14,7 @@ import net.i2p.util.FileUtil; import net.i2p.util.I2PAppThread; import net.i2p.util.OrderedProperties; import net.i2p.util.SecureDirectory; +import net.i2p.util.SecureFile; import net.i2p.util.SimpleScheduler; import net.i2p.util.SimpleTimer; import net.i2p.util.VersionComparator; @@ -333,7 +334,7 @@ public class PluginUpdateHandler extends UpdateHandler { } String oldPubkey = oldProps.getProperty("key"); String oldKeyName = oldProps.getProperty("signer"); - String oldAppName = props.getProperty("name"); + String oldAppName = oldProps.getProperty("name"); if ((!pubkey.equals(oldPubkey)) || (!signer.equals(oldKeyName)) || (!appName.equals(oldAppName))) { to.delete(); statusDone("" + _("Signature of downloaded plugin does not match installed plugin") + ""); @@ -375,24 +376,25 @@ public class PluginUpdateHandler extends UpdateHandler { statusDone("" + _("Plugin requires Jetty version {0} or lower", maxVersion) + ""); return; } - /* - // not ready yet... // do we defer extraction and installation? - if (Boolean.valueOf(props.getProperty("router-restart-required")).booleanValue() && !Boolean.valueOf(props.getProperty("dont-start-at-install")).booleanValue()) { + if (Boolean.valueOf(props.getProperty("router-restart-required")).booleanValue()) { // Yup! - if (!destDir.mkdir()) { + try { + if(!FileUtil.copy(to, (new SecureFile( new SecureFile(appDir.getCanonicalPath() +"/" + appName +"/"+ ZIP).getCanonicalPath())) , true, true)) { + to.delete(); + statusDone("" + _("Cannot copy plugin to directory {0}", destDir.getAbsolutePath()) + ""); + return; + } + } catch (Throwable t) { to.delete(); - statusDone("" + _("Cannot create plugin directory {0}", destDir.getAbsolutePath()) + ""); + _log.error("Error copying plugin {0}", t); return; } - if(!FileUtil.copy(to, destDir, true, true)) { - statusDone("" + _("Cannot copy plugin to directory {0}", destDir.getAbsolutePath()) + ""); - } // we don't need the original file anymore. to.delete(); statusDone("" + _("Plugin will be installed on next restart.") + ""); + return; } - */ if (PluginStarter.isPluginRunning(appName, _context)) { wasRunning = true; try { diff --git a/history.txt b/history.txt index 68e89dcdc1..2f837e6527 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,9 @@ +2012-03-13 sponge + * Plugins: + - Fix a bug in the updater. It was not comparing the correct name. + - Plugin updates can now be deferred if router-restart-required is set. + The update happens at the next router restart. + 2012-03-13 sponge * Plugins: - Handle 'file://' URLs for installation and updates.