From 41ce70349befbab650fc08e65dc45da0f5047827 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Wed, 29 Oct 2003 22:31:55 +0000 Subject: [PATCH] Revamped the way we handle versioned jar files such that each bundle is named according to its version number so that when we patch an old version to create a new version, we don't have to do any renaming, we just create the new version directly and hopefully avoid this bullshit problem on Windows where we're unable to rename a goddamned file. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2846 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../threerings/resource/DownloadManager.java | 7 +- .../threerings/resource/JNLPDownloader.java | 84 +++++++++++++------ .../threerings/resource/ResourceManager.java | 47 ++++++++++- 3 files changed, 106 insertions(+), 32 deletions(-) diff --git a/src/java/com/threerings/resource/DownloadManager.java b/src/java/com/threerings/resource/DownloadManager.java index 666496d9c..1924ee970 100644 --- a/src/java/com/threerings/resource/DownloadManager.java +++ b/src/java/com/threerings/resource/DownloadManager.java @@ -1,5 +1,5 @@ // -// $Id: DownloadManager.java,v 1.13 2003/10/23 20:31:28 ray Exp $ +// $Id: DownloadManager.java,v 1.14 2003/10/29 22:31:55 mdb Exp $ package com.threerings.resource; @@ -27,6 +27,9 @@ import com.samskivert.util.StringUtil; */ public class DownloadManager { + /** Indicates whether or not we're using versioned resources. */ + public static boolean VERSIONING = false; + /** * Provides facilities for notifying an observer of file download * progress. @@ -384,8 +387,6 @@ public class DownloadManager /** The data buffer size for reading file data. */ protected static final int BUFFER_SIZE = 2048; - /** Indicates whether or not we're using versioned resources. */ - protected static boolean VERSIONING = false; static { try { VERSIONING = "true".equalsIgnoreCase( diff --git a/src/java/com/threerings/resource/JNLPDownloader.java b/src/java/com/threerings/resource/JNLPDownloader.java index c028fa698..f39852cca 100644 --- a/src/java/com/threerings/resource/JNLPDownloader.java +++ b/src/java/com/threerings/resource/JNLPDownloader.java @@ -1,5 +1,5 @@ // -// $Id: JNLPDownloader.java,v 1.9 2003/10/29 02:42:56 mdb Exp $ +// $Id: JNLPDownloader.java,v 1.10 2003/10/29 22:31:55 mdb Exp $ package com.threerings.resource; @@ -40,12 +40,52 @@ public class JNLPDownloader extends Downloader { super.init(ddesc); - // determine which version we already have, if any + String dpath = _desc.destFile.getPath(); + + // determine the path of our version file before we version the + // path of the destination file _vfile = new File(FileUtil.resuffix(_desc.destFile, ".jar", ".vers")); - if (_vfile.exists() && _desc.destFile.exists()) { + + // if we're using a version, adjust our destination file path + // based on said version + if (!StringUtil.blank(_desc.version)) { + _desc.destFile = new File( + ResourceManager.versionPath(dpath, _desc.version, ".jar")); + } + + // determine which version we already have, if any + if (_vfile.exists()) { try { BufferedReader vin = new BufferedReader(new FileReader(_vfile)); _cvers = vin.readLine(); + + // make sure the version referenced by that file still + // exists; if not ignore our "current version" + _curFile = new File(ResourceManager.versionPath( + dpath, _cvers, ".jar")); + if (!_curFile.exists()) { + // for backwards compatibility, check to see if we + // have an old non-versioned-path version of our + // existing version + File legacyFile = new File(dpath); + if (legacyFile.exists()) { + if (!legacyFile.renameTo(_curFile)) { + Log.warning("Failed to rename legacy bundle to " + + "versioned name [cur=" + _curFile + + ", leg=" + legacyFile + "]."); + // just cope and we won't be able to blow away + // this version of the resources + _curFile = legacyFile; + } else { + Log.info("Renamed legacy bundle [cur=" + _curFile + + ", leg=" + legacyFile + "]."); + } + + } else { + _cvers = null; + } + } + } catch (IOException ioe) { Log.warning("Error reading version file [path=" + _vfile + ", error=" + ioe + "]."); @@ -106,7 +146,7 @@ public class JNLPDownloader extends Downloader if (ucon.getContentType().equals(JARDIFF_TYPE)) { Log.info("Downloading patch [url=" + rsrcURL + "]."); _patchFile = new File( - FileUtil.resuffix(_desc.destFile, ".jar", ".diff")); + FileUtil.resuffix(_curFile, ".jar", ".diff")); downloadContent(dmgr, obs, pinfo, buffer, ucon, _patchFile); } else { @@ -121,25 +161,9 @@ public class JNLPDownloader extends Downloader throws IOException { if (_patchFile != null) { - // move the old jar out of the way - File oldDest = new File( - FileUtil.resuffix(_desc.destFile, ".jar", ".old")); - if (!_desc.destFile.renameTo(oldDest)) { - Log.warning("Unable to move " + _desc.destFile + " to " + - oldDest + ". Trying another strategy."); - oldDest = new File(_desc.destFile, - RandomUtil.rand.nextLong() + ".jar"); - if (!_desc.destFile.renameTo(oldDest)) { - Log.warning("Unable to move " + _desc.destFile + " to " + - oldDest + ". Giving up and wiping."); - // attempt to blow everything away before choking so that - // next time we'll download afresh - cleanUpAndFail(null); - } - } - // now apply the patch - Log.info("Applying patch [old=" + oldDest + ", path=" + _patchFile + + Log.info("Applying patch [old=" + _curFile + + ", patch=" + _patchFile + ", new=" + _desc.destFile + "]."); Patcher.PatchDelegate delegate = new Patcher.PatchDelegate() { public void patching (int value) { @@ -153,7 +177,7 @@ public class JNLPDownloader extends Downloader try { out = new BufferedOutputStream( new FileOutputStream(_desc.destFile)); - patcher.applyPatch(delegate, oldDest.getPath(), + patcher.applyPatch(delegate, _curFile.getPath(), _patchFile.getPath(), out); out.close(); @@ -161,13 +185,16 @@ public class JNLPDownloader extends Downloader Log.warning("Failure applying patch [rfile=" + _desc.destFile + ", error=" + ioe + "]. Cleaning up and failing."); StreamUtil.close(out); - oldDest.delete(); cleanUpAndFail(ioe); } // clean up the old jar and the patch file - oldDest.delete(); - _patchFile.delete(); + if (!_curFile.delete()) { + Log.warning("Failed to delete old bundle " + _curFile + "."); + } + if (!_patchFile.delete()) { + Log.warning("Failed to delete patch file " + _curFile + "."); + } } PrintWriter pout = new PrintWriter( @@ -210,7 +237,7 @@ public class JNLPDownloader extends Downloader protected void cleanUpAndFail (IOException cause) throws IOException { - if (!_desc.destFile.delete()) { + if (_curFile != null) { Log.warning("Failed to delete " + _desc.destFile + " in cleanUpAndFail()."); } @@ -241,6 +268,9 @@ public class JNLPDownloader extends Downloader /** The current version of the resource if we have one. */ protected String _cvers; + /** The existing version of our bundle file. */ + protected File _curFile; + /** The mime-type of a jardiff patch file. */ protected static final String JARDIFF_TYPE = "application/x-java-archive-diff"; diff --git a/src/java/com/threerings/resource/ResourceManager.java b/src/java/com/threerings/resource/ResourceManager.java index 6890e07cc..3e6b36416 100644 --- a/src/java/com/threerings/resource/ResourceManager.java +++ b/src/java/com/threerings/resource/ResourceManager.java @@ -1,5 +1,5 @@ // -// $Id: ResourceManager.java,v 1.37 2003/10/27 11:43:26 mdb Exp $ +// $Id: ResourceManager.java,v 1.38 2003/10/29 22:31:55 mdb Exp $ package com.threerings.resource; @@ -661,8 +661,17 @@ public class ResourceManager // make sure the cache directory exists for this set createCacheDirectory(setName); + // compute the versioned path for this bundle if we have a + // version configured + String vpath = path; + if (DownloadManager.VERSIONING && !StringUtil.blank(_version)) { + vpath = versionPath( + path, _version, getSuffix(path, ".jar")); + } + // compute the path to the cache file for this bundle File cfile = new File(genCachePath(setName, path)); + File vfile = new File(genCachePath(setName, vpath)); // slap this on the list for retrieval or update by the // download manager @@ -670,7 +679,7 @@ public class ResourceManager // finally, add the file that will be cached to the set as // a resource bundle - set.add(new ResourceBundle(cfile, true, true)); + set.add(new ResourceBundle(vfile, true, true)); } catch (MalformedURLException mue) { Log.warning("Unable to create URL for resource " + @@ -850,6 +859,40 @@ public class ResourceManager return (ResourceBundle[])_sets.get(name); } + /** + * Creates a versioned path using the supplied version string, path + * and file suffix. For example foo/bar/baz.jar becomes + * foo/bar/baz__Vversion.jar. + */ + public static String versionPath ( + String path, String version, String suffix) + { + if (!suffix.startsWith(".")) { + suffix = "." + suffix; + } + int sidx = path.indexOf(suffix); + if (sidx == -1) { + Log.warning("Invalid unversioned path, missing suffix " + + "[path=" + path + ", suffix=" + suffix + "]."); + return path; + } + return path.substring(0, sidx) + "__V" + version + suffix; + } + + /** + * Returns the suffix of the specified path, ie. .jar if + * the path references a file that ends in .jar. + */ + public static String getSuffix (String path, String defsuf) + { + int didx = path.lastIndexOf("."); + if (didx == -1) { + return defsuf; + } else { + return path.substring(didx); + } + } + /** The classloader we use for classpath-based resource loading. */ protected ClassLoader _loader;