forked from I2P_Developers/i2p.i2p
* Update: Support notification of updates that cannot be downloaded
due to "constraints". Add constraint checks for java version, router version, configuration, and base permissions. (ticket #1024)
This commit is contained in:
@ -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<URI> 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
|
||||
*/
|
||||
@ -1006,6 +1056,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;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return success
|
||||
@ -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<UpdateMethod, List<URI>> 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 + '"') : "");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 = "<i2p.release ";
|
||||
// all keys mapped to lower case by parseArgs()
|
||||
private static final String VERSION_KEY = "version";
|
||||
// you have to be at least this version to update to the new version
|
||||
private static final String MIN_VERSION_KEY = "minversion";
|
||||
private static final String MIN_JAVA_VERSION_KEY = "minjavaversion";
|
||||
private static final String SUD_KEY = "sudtorrent";
|
||||
private static final String SU2_KEY = "su2torrent";
|
||||
// following are unused
|
||||
private static final String CLEARNET_SUD_KEY = "sudclearnet";
|
||||
private static final String CLEARNET_SU2_KEY = "su2clearnet";
|
||||
private static final String I2P_SUD_KEY = "sudi2p";
|
||||
@ -125,11 +125,6 @@ class NewsFetcher extends UpdateRunner {
|
||||
* TODO: Check minVersion, use backup URLs specified
|
||||
*/
|
||||
void checkForUpdates() {
|
||||
// For now, don't even tell the manager about new versions if we can't install.
|
||||
// If we do want the manager to know, we must hide the buttons in
|
||||
// SummaryHelper.getUpdateStatus().
|
||||
if (dontInstall())
|
||||
return;
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream(_newsFile);
|
||||
@ -143,6 +138,37 @@ class NewsFetcher extends UpdateRunner {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Found version: [" + ver + "]");
|
||||
if (TrustedUpdate.needsUpdate(RouterVersion.VERSION, ver)) {
|
||||
if (NewsHelper.isUpdateDisabled(_context)) {
|
||||
String msg = _mgr._("In-network updates disabled. Check package manager.");
|
||||
_log.logAlways(Log.WARN, "Cannot update to version " + ver + ": " + msg);
|
||||
_mgr.notifyVersionConstraint(this, _currentURI, ROUTER_SIGNED, "", ver, msg);
|
||||
return;
|
||||
}
|
||||
if (NewsHelper.isBaseReadonly(_context)) {
|
||||
String msg = _mgr._("No write permission for I2P install directory.");
|
||||
_log.logAlways(Log.WARN, "Cannot update to version " + ver + ": " + msg);
|
||||
_mgr.notifyVersionConstraint(this, _currentURI, ROUTER_SIGNED, "", ver, msg);
|
||||
return;
|
||||
}
|
||||
String minRouter = args.get(MIN_VERSION_KEY);
|
||||
if (minRouter != null) {
|
||||
if (VersionComparator.comp(RouterVersion.VERSION, minRouter) < 0) {
|
||||
String msg = _mgr._("You must first update to version {0}", minRouter);
|
||||
_log.logAlways(Log.WARN, "Cannot update to version " + ver + ": " + msg);
|
||||
_mgr.notifyVersionConstraint(this, _currentURI, ROUTER_SIGNED, "", ver, msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
String minJava = args.get(MIN_JAVA_VERSION_KEY);
|
||||
if (minJava != null) {
|
||||
String ourJava = System.getProperty("java.version");
|
||||
if (VersionComparator.comp(ourJava, minJava) < 0) {
|
||||
String msg = _mgr._("Requires Java version {0} but installed Java version is {1}", minJava, ourJava);
|
||||
_log.logAlways(Log.WARN, "Cannot update to version " + ver + ": " + msg);
|
||||
_mgr.notifyVersionConstraint(this, _currentURI, ROUTER_SIGNED, "", ver, msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Our version is out of date, update!");
|
||||
// TODO if minversion > our version, continue
|
||||
|
@ -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;
|
||||
|
@ -678,7 +678,22 @@ public class SummaryHelper extends HelperBase {
|
||||
buf.append(' ').append(_("Version {0}", dver));
|
||||
buf.append("</b></h4>");
|
||||
}
|
||||
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("<hr>");
|
||||
else
|
||||
needSpace = true;
|
||||
buf.append("<h4><b>").append(_("Update available")).append(":<br>");
|
||||
buf.append(_("Version {0}", getUpdateVersion())).append("<br>");
|
||||
buf.append(constraint).append("</h4>");
|
||||
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("<form action=\"").append(uri).append("\" method=\"POST\">\n");
|
||||
buf.append("<input type=\"hidden\" name=\"updateNonce\" value=\"").append(nonce).append("\" >\n");
|
||||
if (updateAvailable()) {
|
||||
if (avail) {
|
||||
buf.append("<button type=\"submit\" class=\"download\" name=\"updateAction\" value=\"signed\" >")
|
||||
// Note to translators: parameter is a version, e.g. "0.8.4"
|
||||
.append(_("Download {0} Update", getUpdateVersion()))
|
||||
.append("</button><br>\n");
|
||||
}
|
||||
if (unsignedUpdateAvailable()) {
|
||||
if (unsignedAvail) {
|
||||
buf.append("<button type=\"submit\" class=\"download\" name=\"updateAction\" value=\"Unsigned\" >")
|
||||
// Note to translators: parameter is a date and time, e.g. "02-Mar 20:34 UTC"
|
||||
// <br> is optional, to help the browser make the lines even in the button
|
||||
|
@ -67,6 +67,22 @@ public interface UpdateManager {
|
||||
Map<UpdateMethod, List<URI>> sourceMap,
|
||||
String newVersion, String minVersion);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Called by the Checker after check() was called and all notifyVersionAvailable() callbacks are finished
|
||||
* @param newer notifyVersionAvailable was called
|
||||
|
Reference in New Issue
Block a user