diff --git a/apps/routerconsole/java/src/net/i2p/router/update/ConsoleUpdateManager.java b/apps/routerconsole/java/src/net/i2p/router/update/ConsoleUpdateManager.java index 1d97872e0..537d37041 100644 --- a/apps/routerconsole/java/src/net/i2p/router/update/ConsoleUpdateManager.java +++ b/apps/routerconsole/java/src/net/i2p/router/update/ConsoleUpdateManager.java @@ -172,6 +172,7 @@ public class ConsoleUpdateManager implements UpdateManager { /** * Is an update available? * Blocking. + * An available update may still have a constraint or lack sources. * @param maxWait max time to block * @return new version or null if nothing newer is available */ @@ -244,7 +245,8 @@ public class ConsoleUpdateManager implements UpdateManager { /** * Is an update available? - * Non-blocking, returns result of last check or notification from an Updater + * Non-blocking, returns result of last check or notification from an Updater. + * An available update may still have a constraint or lack sources. * @return new version or null if nothing newer is available */ public String getUpdateAvailable(UpdateType type) { @@ -253,7 +255,8 @@ public class ConsoleUpdateManager implements UpdateManager { /** * Is an update available? - * Non-blocking, returns result of last check or notification from an Updater + * Non-blocking, returns result of last check or notification from an Updater. + * An available update may still have a constraint or lack sources. * @return new version or null if nothing newer is available */ public String getUpdateAvailable(UpdateType type, String id) { @@ -497,7 +500,6 @@ public class ConsoleUpdateManager implements UpdateManager { _log.warn("Update already in progress for: " + type + ' ' + id); return false; } - List updateSources = null; UpdateItem ui = new UpdateItem(type, id); VersionAvailable va = _available.get(ui); if (va == null) { @@ -748,6 +750,54 @@ public class ConsoleUpdateManager implements UpdateManager { return true; } + /** + * A new version is available but cannot be downloaded or installed due to some constraint. + * The manager should notify the user. + * Called by the Checker, either after check() was called, or it found out on its own. + * + * @param newsSource who told us + * @param id plugin name for plugins, ignored otherwise + * @param sourceMap Mapping of methods to sources + * @param newVersion The new version available + * @param message A translated message to be displayed to the user, non-null + * @since 0.9.9 + */ + public void notifyVersionConstraint(UpdateTask task, URI newsSource, + UpdateType type, String id, + String newVersion, String message) { + UpdateItem ui = new UpdateItem(type, id); + Version old = _installed.get(ui); + VersionAvailable newVA = new VersionAvailable(newVersion, message); + if (_log.shouldLog(Log.INFO)) + _log.info("notifyVersionConstraint " + ui + ' ' + newVA + " old: " + old); + if (old != null && old.compareTo(newVA) >= 0) { + if (_log.shouldLog(Log.WARN)) + _log.warn(ui.toString() + ' ' + old + " already installed"); + return; + } + old = _downloaded.get(ui); + if (old != null && old.compareTo(newVA) >= 0) { + if (_log.shouldLog(Log.WARN)) + _log.warn(ui.toString() + ' ' + old + " already downloaded"); + return; + } + VersionAvailable oldVA = _available.get(ui); + if (oldVA != null) { + if (_log.shouldLog(Log.WARN)) + _log.warn(ui.toString() + ' ' + oldVA + " already available"); + if (oldVA.compareTo(newVA) >= 0) + return; + // don't replace an unconstrained version with a constrained one + if (oldVA.constraint == null) + return; + // replace constrained one + } + // Use the new VersionAvailable + if (_log.shouldLog(Log.INFO)) + _log.info(ui.toString() + ' ' + newVA + " now available"); + _available.put(ui, newVA); + } + /** * Called by the Updater after check() was called and all notifyVersionAvailable() callbacks are finished */ @@ -1005,6 +1055,18 @@ public class ConsoleUpdateManager implements UpdateManager { } return Collections.EMPTY_LIST; } + + /** + * Is there a reason we can't download the update? + * @return translated contraint or null + * @since 0.9.9 + */ + public String getUpdateConstraint(UpdateType type, String id) { + VersionAvailable va = _available.get(new UpdateItem(type, id)); + if (va != null) + return va.constraint; + return null; + } /** * @@ -1118,6 +1180,14 @@ public class ConsoleUpdateManager implements UpdateManager { return Messages.getString(s, o, _context); } + /** + * translate a string with parameters + * @since 0.9.9 + */ + public String _(String s, Object o, Object o2) { + return Messages.getString(s, o, o2, _context); + } + private void updateStatus(String s) { _status = s; } @@ -1301,6 +1371,7 @@ public class ConsoleUpdateManager implements UpdateManager { private static class VersionAvailable extends Version { public final String minVersion; public final ConcurrentHashMap> sourceMap; + public volatile String constraint; /** * Puts the method and sources in the map. The map may be added to later. @@ -1312,9 +1383,21 @@ public class ConsoleUpdateManager implements UpdateManager { sourceMap.put(method, updateSources); } + /** + * Available but can't be downloaded due to constraint. + * + */ + public VersionAvailable(String version, String constraint) { + super(version); + minVersion = ""; + sourceMap = new ConcurrentHashMap(4); + this.constraint = constraint; + } + @Override public String toString() { - return "VersionAvailable \"" + version + "\" " + sourceMap; + return "VersionAvailable \"" + version + "\" " + sourceMap + + (constraint != null ? (" \"" + constraint + '"') : ""); } } diff --git a/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java b/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java index 61ae0354c..ba309d3de 100644 --- a/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java +++ b/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java @@ -31,6 +31,7 @@ import net.i2p.util.EepGet; import net.i2p.util.EepHead; import net.i2p.util.FileUtil; import net.i2p.util.Log; +import net.i2p.util.VersionComparator; /** * Task to fetch updates to the news.xml, and to keep @@ -60,10 +61,6 @@ class NewsFetcher extends UpdateRunner { @Override public UpdateType getType() { return NEWS; } - private boolean dontInstall() { - return NewsHelper.dontInstall(_context); - } - @Override public void run() { _isRunning = true; @@ -111,9 +108,12 @@ class NewsFetcher extends UpdateRunner { private static final String VERSION_PREFIX = " our version, continue diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NewsHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/NewsHelper.java index c1fbf2b05..f04f1847b 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NewsHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NewsHelper.java @@ -74,6 +74,17 @@ public class NewsHelper extends ContentHelper { return mgr.getUpdateAvailable(ROUTER_SIGNED); } + /** + * Translated message about new version available but constrained + * @return null if none + * @since 0.9.9 + */ + public static String updateConstraint() { + ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance(); + if (mgr == null) return null; + return mgr.getUpdateConstraint(ROUTER_SIGNED, ""); + } + /** * Already downloaded but not installed version * @return null if none @@ -259,9 +270,20 @@ public class NewsHelper extends ContentHelper { * @since 0.9.4 moved from NewsFetcher */ public static boolean dontInstall(RouterContext ctx) { - boolean disabled = ctx.getBooleanProperty(ConfigUpdateHandler.PROP_UPDATE_DISABLED); - if (disabled) - return true; + return isUpdateDisabled(ctx) || isBaseReadonly(ctx); + } + + /** + * @since 0.9.9 + */ + public static boolean isUpdateDisabled(RouterContext ctx) { + return ctx.getBooleanProperty(ConfigUpdateHandler.PROP_UPDATE_DISABLED); + } + + /** + * @since 0.9.9 + */ + public static boolean isBaseReadonly(RouterContext ctx) { File test = new File(ctx.getBaseDir(), "history.txt"); boolean readonly = ((test.exists() && !test.canWrite()) || (!ctx.getBaseDir().canWrite())); return readonly; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java index 7d75790ae..9ad087a6d 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java @@ -678,7 +678,22 @@ public class SummaryHelper extends HelperBase { buf.append(' ').append(_("Version {0}", dver)); buf.append(""); } - if ((updateAvailable() || unsignedUpdateAvailable()) && + boolean avail = updateAvailable(); + boolean unsignedAvail = unsignedUpdateAvailable(); + String constraint = avail ? NewsHelper.updateConstraint() : null; + if (avail && constraint != null && + !NewsHelper.isUpdateInProgress() && + !_context.router().gracefulShutdownInProgress()) { + if (needSpace) + buf.append("
"); + else + needSpace = true; + buf.append("

").append(_("Update available")).append(":
"); + buf.append(_("Version {0}", getUpdateVersion())).append("
"); + buf.append(constraint).append("

"); + avail = false; + } + if ((avail || unsignedAvail) && !NewsHelper.isUpdateInProgress() && !_context.router().gracefulShutdownInProgress() && _context.portMapper().getPort(PortMapper.SVC_HTTP_PROXY) > 0 && // assume using proxy for now @@ -694,13 +709,13 @@ public class SummaryHelper extends HelperBase { String uri = getRequestURI(); buf.append("
\n"); buf.append("\n"); - if (updateAvailable()) { + if (avail) { buf.append("
\n"); } - if (unsignedUpdateAvailable()) { + if (unsignedAvail) { buf.append("