Tidy up new resources stuff a bit.

The one major change here is that Getdown.isUpdateAvailable/install()
are no longer static.

GetdownApp has a start() method that you can call if you want to get the
Getdown reference back. You can call isUpdateAvailable() on that. It was
super weird that you would call GetdownApp.main() and then just call
some static methods after that.
This commit is contained in:
Michael Bayne
2016-11-04 17:45:51 -07:00
parent 345f64d62d
commit 7c651fbd73
5 changed files with 189 additions and 166 deletions
@@ -35,7 +35,7 @@ public class Resource
_path = path; _path = path;
_remote = remote; _remote = remote;
_local = local; _local = local;
_local_new = new File(local.toString() + "_new"); _localNew = new File(local.toString() + "_new");
String lpath = _local.getPath(); String lpath = _local.getPath();
_marker = new File(lpath + "v"); _marker = new File(lpath + "v");
@@ -67,9 +67,12 @@ public class Resource
return _local; return _local;
} }
/**
* Returns the location of the to-be-installed new version of this resource.
*/
public File getLocalNew () public File getLocalNew ()
{ {
return _local_new; return _localNew;
} }
/** /**
@@ -109,17 +112,13 @@ public class Resource
* Computes the MD5 hash of this resource's underlying file. * Computes the MD5 hash of this resource's underlying file.
* <em>Note:</em> This is both CPU and I/O intensive. * <em>Note:</em> This is both CPU and I/O intensive.
*/ */
public String computeDigest (MessageDigest md, ProgressObserver obs) public String computeDigest (MessageDigest md, ProgressObserver obs) throws IOException
throws IOException
{ {
File file; File file;
if (_local.toString().toLowerCase().endsWith(Application.CONFIG_FILE)) if (_local.toString().toLowerCase().endsWith(Application.CONFIG_FILE)) {
file = _local;
else {
if (_local_new.exists())
file = _local_new;
else
file = _local; file = _local;
} else {
file = _localNew.exists() ? _localNew : _local;
} }
return computeDigest(file, md, obs); return computeDigest(file, md, obs);
} }
@@ -309,7 +308,7 @@ public class Resource
protected String _path; protected String _path;
protected URL _remote; protected URL _remote;
protected File _local, _local_new, _marker, _unpacked; protected File _local, _localNew, _marker, _unpacked;
protected boolean _unpack, _isJar, _isPacked200Jar; protected boolean _unpack, _isJar, _isPacked200Jar;
/** Used to sort the entries in a jar file. */ /** Used to sort the entries in a jar file. */
@@ -49,8 +49,11 @@ public class SysProps
return System.getProperty("silent") != null; return System.getProperty("silent") != null;
} }
public static boolean install () { /** If true, Getdown does not automatically install updates after downloading them. It waits
return System.getProperty("no_install") == null; * for the application to call {@link Getdown#install}.
* Usage: {@code -Dno_install}. */
public static boolean noInstall () {
return System.getProperty("no_install") != null;
} }
/** If true, Getdown installs the app without ever bringing up a UI and then launches it. /** If true, Getdown installs the app without ever bringing up a UI and then launches it.
@@ -101,11 +101,11 @@ public abstract class Getdown extends Thread
// If the silent property exists, install without bringing up any gui. If it equals // If the silent property exists, install without bringing up any gui. If it equals
// launch, start the application after installing. Otherwise, just install and exit. // launch, start the application after installing. Otherwise, just install and exit.
_silent = SysProps.silent(); _silent = SysProps.silent();
_install = SysProps.install();
if (_silent) { if (_silent) {
_launchInSilent = SysProps.launchInSilent(); _launchInSilent = SysProps.launchInSilent();
} }
_delay = SysProps.startDelay(); _delay = SysProps.startDelay();
_noInstall = SysProps.noInstall();
} catch (SecurityException se) { } catch (SecurityException se) {
// don't freak out, just assume non-silent and no delay; we're probably already // don't freak out, just assume non-silent and no delay; we're probably already
// recovering from a security failure // recovering from a security failure
@@ -128,6 +128,39 @@ public abstract class Getdown extends Thread
_startup = System.currentTimeMillis(); _startup = System.currentTimeMillis();
} }
/**
* Returns true if there are pending new resources, waiting to be installed.
*/
public boolean isUpdateAvailable ()
{
return _readyToInstall && !_toBeInstalledResouces.isEmpty();
}
/**
* Installs the currently pending new resources.
*/
public void install () throws IOException, InterruptedException
{
if (_readyToInstall) {
log.info("Installing downloaded resources:");
for (Resource resource : _toBeInstalledResouces) {
File source = resource.getLocalNew(), dest = resource.getLocal();
log.info("- " + source);
if (!FileUtil.renameTo(source, dest)) {
throw new IOException("Failed to rename " + source + " to " + dest);
}
if (Thread.interrupted()) {
throw new InterruptedException("m.applet_stopped");
}
}
_toBeInstalledResouces.clear();
_readyToInstall = false;
log.info("Install completed.");
} else {
log.info("Nothing to install.");
}
}
/** /**
* This is used by the applet which always needs a user interface and wants to load it as soon * This is used by the applet which always needs a user interface and wants to load it as soon
* as possible. * as possible.
@@ -412,8 +445,8 @@ public abstract class Getdown extends Thread
// we'll keep track of all the resources we unpack // we'll keep track of all the resources we unpack
Set<Resource> unpacked = new HashSet<Resource>(); Set<Resource> unpacked = new HashSet<Resource>();
toBeInstalledResouces = new ArrayList<Resource>(); _toBeInstalledResouces = new ArrayList<Resource>();
readyToInstall = false; _readyToInstall = false;
//setStep(Step.START); //setStep(Step.START);
for (int ii = 0; ii < MAX_LOOPS; ii++) { for (int ii = 0; ii < MAX_LOOPS; ii++) {
@@ -447,7 +480,6 @@ public abstract class Getdown extends Thread
setStep(Step.VERIFY_RESOURCES); setStep(Step.VERIFY_RESOURCES);
setStatusAsync("m.validating", -1, -1L, false); setStatusAsync("m.validating", -1, -1L, false);
List<Resource> failures = _app.verifyResources(_progobs, alreadyValid, unpacked); List<Resource> failures = _app.verifyResources(_progobs, alreadyValid, unpacked);
addToBeInstalledResources(failures);
if (failures == null) { if (failures == null) {
log.info("Resources verified."); log.info("Resources verified.");
@@ -477,9 +509,11 @@ public abstract class Getdown extends Thread
} }
} }
readyToInstall = true; // assuming we're not doing anything funny, install the update
if (_install) _readyToInstall = true;
if (!_noInstall) {
install(); install();
}
// Only launch if we aren't in silent mode. Some mystery program starting out // Only launch if we aren't in silent mode. Some mystery program starting out
// of the blue would be disconcerting. // of the blue would be disconcerting.
@@ -496,6 +530,13 @@ public abstract class Getdown extends Thread
return; return;
} }
// we have failures, those will be redownloaded so we note them as to-be-installed
for (Resource r : failures) {
if (!_toBeInstalledResouces.contains(r)) {
_toBeInstalledResouces.add(r);
}
}
try { try {
// if any of our resources have already been marked valid this is not a first // if any of our resources have already been marked valid this is not a first
// time install and we don't want to enable tracking // time install and we don't want to enable tracking
@@ -509,6 +550,7 @@ public abstract class Getdown extends Thread
download(failures); download(failures);
reportTrackingEvent("app_complete", -1); reportTrackingEvent("app_complete", -1);
} finally { } finally {
_enableTracking = false; _enableTracking = false;
} }
@@ -541,15 +583,6 @@ public abstract class Getdown extends Thread
} }
} }
private void addToBeInstalledResources(List<Resource> resources) {
if (resources == null)
return;
else
for (Resource r : resources)
if (!toBeInstalledResouces.contains(r))
toBeInstalledResouces.add(r);
}
// documentation inherited from interface // documentation inherited from interface
public void updateStatus (String message) public void updateStatus (String message)
{ {
@@ -774,31 +807,6 @@ public abstract class Getdown extends Thread
} }
} }
public static void install ()
throws IOException, InterruptedException
{
if (readyToInstall) {
log.info("Installing downloaded resources:");
for (Resource resource : toBeInstalledResouces) {
log.info(resource);
if (!FileUtil.renameTo(resource.getLocalNew(), resource.getLocal()))
throw new IOException("Failed to rename(" + resource.getLocalNew() + ", " + resource.getLocal() + ")");
if (Thread.interrupted()) {
throw new InterruptedException("m.applet_stopped");
}
}
toBeInstalledResouces.clear();
readyToInstall = false;
log.info("Install completed.");
} else {
log.info("Nothing to install.");
}
}
public static boolean isUpdateAvailable() {
return readyToInstall && !toBeInstalledResouces.isEmpty();
}
/** /**
* Called to launch the application if everything is determined to be ready to go. * Called to launch the application if everything is determined to be ready to go.
*/ */
@@ -1263,10 +1271,13 @@ public abstract class Getdown extends Thread
protected boolean _dead; protected boolean _dead;
protected boolean _silent; protected boolean _silent;
protected boolean _install; protected boolean _noInstall;
protected boolean _launchInSilent; protected boolean _launchInSilent;
protected long _startup; protected long _startup;
protected List<Resource> _toBeInstalledResouces;
protected boolean _readyToInstall;
protected boolean _enableTracking = true; protected boolean _enableTracking = true;
protected int _reportedProgress = 0; protected int _reportedProgress = 0;
@@ -1284,6 +1295,4 @@ public abstract class Getdown extends Thread
protected static final long PLAY_AGAIN_TIME = 3000L; protected static final long PLAY_AGAIN_TIME = 3000L;
protected static final String PROXY_REGISTRY = protected static final String PROXY_REGISTRY =
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"; "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
protected static List<Resource> toBeInstalledResouces;
protected static boolean readyToInstall;
} }
@@ -36,6 +36,20 @@ public class GetdownApp
{ {
public static void main (String[] argv) public static void main (String[] argv)
{ {
try {
start(argv);
} catch (Exception e) {
log.warning("main() failed.", e);
}
}
/**
* Runs Getdown as an application, using the arguments supplie as {@code argv}.
* @return the {@code Getdown} instance that is running. {@link Getdown#start} will have been
* called on it.
* @throws Exception if anything goes wrong starting Getdown.
*/
public static Getdown start (String[] argv) throws Exception {
int aidx = 0; int aidx = 0;
List<String> args = Arrays.asList(argv); List<String> args = Arrays.asList(argv);
@@ -91,7 +105,6 @@ public class GetdownApp
log.info("-- Cur dir: " + System.getProperty("user.dir")); log.info("-- Cur dir: " + System.getProperty("user.dir"));
log.info("---------------------------------------------"); log.info("---------------------------------------------");
try {
Getdown app = new Getdown(appDir, appId, null, null, appArgs) { Getdown app = new Getdown(appDir, appId, null, null, appArgs) {
@Override @Override
protected Container createContainer () { protected Container createContainer () {
@@ -200,9 +213,6 @@ public class GetdownApp
protected JFrame _frame; protected JFrame _frame;
}; };
app.start(); app.start();
return app;
} catch (Exception e) {
log.warning("main() failed.", e);
}
} }
} }
@@ -60,7 +60,9 @@ public class FileUtil extends com.samskivert.util.FileUtil
fin = new FileInputStream(source); fin = new FileInputStream(source);
fout = new FileOutputStream(dest); fout = new FileOutputStream(dest);
StreamUtil.copy(fin, fout); StreamUtil.copy(fin, fout);
fin.close(); // needed otherwise cannot delete source // close the input stream now so we can delete 'source'
fin.close();
fin = null;
if (!source.delete()) { if (!source.delete()) {
log.warning("Failed to delete " + source + log.warning("Failed to delete " + source +
" after brute force copy to " + dest + "."); " after brute force copy to " + dest + ".");