diff --git a/core/src/main/java/com/threerings/getdown/classpath/cache/GarbageCollector.java b/core/src/main/java/com/threerings/getdown/cache/GarbageCollector.java similarity index 71% rename from core/src/main/java/com/threerings/getdown/classpath/cache/GarbageCollector.java rename to core/src/main/java/com/threerings/getdown/cache/GarbageCollector.java index c4acd6d..6bd732b 100644 --- a/core/src/main/java/com/threerings/getdown/classpath/cache/GarbageCollector.java +++ b/core/src/main/java/com/threerings/getdown/cache/GarbageCollector.java @@ -1,8 +1,11 @@ -package com.threerings.getdown.classpath.cache; +// +// Getdown - application installer, patcher and launcher +// Copyright (C) 2004-2016 Getdown authors +// https://github.com/threerings/getdown/blob/master/LICENSE + +package com.threerings.getdown.cache; import java.io.File; -import java.io.FileFilter; - import com.threerings.getdown.util.FileUtil; /** @@ -44,38 +47,32 @@ public class GarbageCollector /** * Collect and delete garbage in the native cache. It tries to find a jar file with a matching - * lastmodified file, and deletes the entire directory accordingly. + * last modified file, and deletes the entire directory accordingly. */ - public static void collectNative (File cacheDir, final long retentionPeriodMillis) { - FileUtil.walkDirectChildren(cacheDir, new FileUtil.Visitor() { - @Override - public void visit(File file) { - if (file.isDirectory()) { - // Get all the native jars in the directory (there should only be one though) - File[] nativejars = file.listFiles(new FileFilter() { - @Override - public boolean accept(File pathname) { - return pathname.getAbsolutePath().endsWith(".jar"); - } - }); - for (File nativejar : nativejars) { - if (nativejar==null || !nativejar.exists()) { + public static void collectNative (File cacheDir, final long retentionPeriodMillis) + { + File[] subdirs = cacheDir.listFiles(); + if (subdirs != null) { + for (File dir : subdirs) { + if (dir.isDirectory()) { + // Get all the native jars in the directory (there should only be one) + for (File file : dir.listFiles()) { + if (!file.getName().endsWith(".jar")) { continue; } - - File cachedFile = getCachedFile(nativejar); - File lastAccessedFile = getLastAccessedFile(nativejar); - - if (!cachedFile.exists() || !lastAccessedFile.exists() || shouldDelete(lastAccessedFile, retentionPeriodMillis)) { - FileUtil.deleteDirHarder(file); + File cachedFile = getCachedFile(file); + File lastAccessedFile = getLastAccessedFile(file); + if (!cachedFile.exists() || !lastAccessedFile.exists() || + shouldDelete(lastAccessedFile, retentionPeriodMillis)) { + FileUtil.deleteDirHarder(dir); } } } else { - // @TODO There shouldn't be any loose files in native/ but if there are then what? Delete them? - // file.delete(); + // @TODO There shouldn't be any loose files in native/ but if there are then + // what? Delete them? file.delete(); } } - }); + } } private static boolean shouldDelete (File lastAccessedFile, long retentionMillis) diff --git a/core/src/main/java/com/threerings/getdown/classpath/cache/ResourceCache.java b/core/src/main/java/com/threerings/getdown/cache/ResourceCache.java similarity index 62% rename from core/src/main/java/com/threerings/getdown/classpath/cache/ResourceCache.java rename to core/src/main/java/com/threerings/getdown/cache/ResourceCache.java index d517841..b847e12 100644 --- a/core/src/main/java/com/threerings/getdown/classpath/cache/ResourceCache.java +++ b/core/src/main/java/com/threerings/getdown/cache/ResourceCache.java @@ -1,4 +1,9 @@ -package com.threerings.getdown.classpath.cache; +// +// Getdown - application installer, patcher and launcher +// Copyright (C) 2004-2016 Getdown authors +// https://github.com/threerings/getdown/blob/master/LICENSE + +package com.threerings.getdown.cache; import java.io.File; import java.io.IOException; @@ -14,7 +19,6 @@ public class ResourceCache public ResourceCache (File _cacheDir) throws IOException { this._cacheDir = _cacheDir; - createDirectoryIfNecessary(_cacheDir); } @@ -26,34 +30,16 @@ public class ResourceCache } /** - * Caches the given file under it's {@code digest}. Same as calling {@link #cacheFile(File, String, boolean)} - * with {@code false} - * @return the cached file + * Caches the given file under its {@code digest}. + * @param fileToCache file to cache. + * @param cacheSubdir the subdirectory of the cache directory in which to store the cached + * file. Usually either {@code digest} or a prefix of {@code digest}. + * @param digest a crypto digest of the cached files contents. + * @return the cached file. */ - public File cacheFile (File fileToCache, String digest) throws IOException + public File cacheFile (File fileToCache, String cacheSubdir, String digest) throws IOException { - return cacheFile(fileToCache, digest, false); - } - - /** - * Caches the given file under it's {@code digest}. - * @param fileToCache file to cache - * @param digest used to determine the name of the directory to store file in - * @param useFullHashName if true, the name of the cache directory will not be truncated. - * This is useful if you need to avoid the possibility of two files - * sharing a directory. - * @return the cached file - */ - public File cacheFile (File fileToCache, String digest, boolean useFullHashName) throws IOException - { - File cacheLocation; - - if (useFullHashName) { - cacheLocation = new File(_cacheDir, digest); - } else { - cacheLocation = new File(_cacheDir, digest.substring(0, 2)); - - } + File cacheLocation = new File(_cacheDir, cacheSubdir); createDirectoryIfNecessary(cacheLocation); File cachedFile = new File(cacheLocation, digest + getFileSuffix(fileToCache)); diff --git a/core/src/main/java/com/threerings/getdown/classpath/ClassPaths.java b/core/src/main/java/com/threerings/getdown/classpath/ClassPaths.java deleted file mode 100644 index 05eb487..0000000 --- a/core/src/main/java/com/threerings/getdown/classpath/ClassPaths.java +++ /dev/null @@ -1,72 +0,0 @@ -// -// Getdown - application installer, patcher and launcher -// Copyright (C) 2004-2016 Getdown authors -// https://github.com/threerings/getdown/blob/master/LICENSE - -package com.threerings.getdown.classpath; - -import java.io.File; -import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.concurrent.TimeUnit; - -import com.threerings.getdown.classpath.cache.GarbageCollector; -import com.threerings.getdown.classpath.cache.ResourceCache; -import com.threerings.getdown.data.Application; -import com.threerings.getdown.data.Resource; - -public class ClassPaths -{ - - /** - * Builds either a default or cached classpath based on {@code app}'s configuration. - */ - public static ClassPath buildClassPath (Application app) throws IOException - { - return app.useCodeCache() ? buildCachedClassPath(app) : buildDefaultClassPath(app); - } - - /** - * Builds a {@link ClassPath} instance for {@code app} using the code resources in place in - * the app directory. - */ - public static ClassPath buildDefaultClassPath (Application app) - { - LinkedHashSet classPathEntries = new LinkedHashSet(); - for (Resource resource: app.getActiveCodeResources()) { - classPathEntries.add(resource.getFinalTarget()); - } - return new ClassPath(classPathEntries); - } - - /** - * Builds a {@link ClassPath} instance for {@code app} by first copying the code resources into - * a cache directory and then referencing them from there. This avoids problems with - * overwriting in-use classpath elements when the application is later updated. This also - * "garbage collects" expired caches if necessary. - */ - public static ClassPath buildCachedClassPath (Application app) throws IOException - { - File codeCacheDir = new File(app.getAppDir(), Application.CACHE_DIR + "/code"); - - // a negative value of code_cache_retention_days allows to clean up the cache forcefully - if (app.getCodeCacheRetentionDays() != 0) { - runGarbageCollection(app, codeCacheDir); - } - - ResourceCache cache = new ResourceCache(codeCacheDir); - LinkedHashSet classPathEntries = new LinkedHashSet<>(); - for (Resource resource: app.getActiveCodeResources()) { - File entry = cache.cacheFile(resource.getFinalTarget(), app.getDigest(resource)); - classPathEntries.add(entry); - } - - return new ClassPath(classPathEntries); - } - - private static void runGarbageCollection (Application app, File cacheDir) - { - long retainMillis = TimeUnit.DAYS.toMillis(app.getCodeCacheRetentionDays()); - GarbageCollector.collect(cacheDir, retainMillis); - } -} diff --git a/core/src/main/java/com/threerings/getdown/classpath/NativeLibPath.java b/core/src/main/java/com/threerings/getdown/classpath/NativeLibPath.java deleted file mode 100644 index 9c72468..0000000 --- a/core/src/main/java/com/threerings/getdown/classpath/NativeLibPath.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.threerings.getdown.classpath; - -import com.threerings.getdown.classpath.cache.GarbageCollector; -import com.threerings.getdown.classpath.cache.ResourceCache; -import com.threerings.getdown.data.Application; -import com.threerings.getdown.data.Resource; -import com.threerings.getdown.util.FileUtil; - -import java.io.File; -import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.jar.JarFile; -import static com.threerings.getdown.Log.log; - -/** - * Similar to {@link ClassPath}, except used to represent directories containing native libraries instead. - */ -public class NativeLibPath extends ClassPath { - - public NativeLibPath(LinkedHashSet entries) { - super(entries); - } - - /** - * Builds a {@link NativeLibPath} instance by first caching all native jars (indicated by - * nresource=[native jar]), unpacking them, and referencing the locations of each of the unpacked files. - * Also performs garbage collection similar to {@link ClassPaths#buildCachedClassPath} - * - * @param app used to determine native jars and related information - * @param addCurrentLibraryPath if true, it adds the locations referenced by - * {@code System.getProperty("java.library.path")} as well - */ - public static NativeLibPath buildLibsPath(Application app, boolean addCurrentLibraryPath) throws IOException { - List resources = app.getNativeJars(); - String[] curPaths = System.getProperty("java.library.path").split(File.pathSeparator); - LinkedHashSet nativedirs = new LinkedHashSet<>(); - - File nativeCacheDir = new File(app.getAppDir(), Application.CACHE_DIR + "/native"); - ResourceCache cache = new ResourceCache(nativeCacheDir); - - // negative value forces total garbage collection, 0 avoids garbage collection at all - if (app.getCodeCacheRetentionDays() != 0) { - runGarbageCollection(app, nativeCacheDir); - } - - for (Resource resource : resources) { - // Use untruncated directory names because in the off chance that two native jars share a directory AND - // contain files with the same names, we'll get overwriting issues when unpacking - File cachedFile = cache.cacheFile(resource.getFinalTarget(), app.getDigest(resource), true); - - if (!getUnpackedIndicator(cachedFile).exists()) { - try { - FileUtil.unpackJar(new JarFile(cachedFile), cachedFile.getParentFile(), false); - getUnpackedIndicator(cachedFile).createNewFile(); - } catch (IOException ioe) { - log.warning("Failed to unpack native jar", "File", cachedFile.getAbsolutePath(), ioe); - // Keep going and unpack the other jars... - } - } - - nativedirs.add(cachedFile.getParentFile()); - } - - if (addCurrentLibraryPath) { - for (String path : curPaths) { - nativedirs.add(new File(path)); - } - } - - return new NativeLibPath(nativedirs); - } - - private static void runGarbageCollection(Application app, File nativeCacheDir) { - long retainMillis = TimeUnit.DAYS.toMillis(app.getCodeCacheRetentionDays()); - GarbageCollector.collectNative(nativeCacheDir, retainMillis); - } - - private static File getUnpackedIndicator(File cachedFile) { - return new File(cachedFile.getParent(), cachedFile.getName() + ".unpacked"); - } -} diff --git a/core/src/main/java/com/threerings/getdown/data/Application.java b/core/src/main/java/com/threerings/getdown/data/Application.java index 66bffbe..8198a7c 100644 --- a/core/src/main/java/com/threerings/getdown/data/Application.java +++ b/core/src/main/java/com/threerings/getdown/data/Application.java @@ -23,9 +23,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; -import com.threerings.getdown.classpath.ClassPaths; -import com.threerings.getdown.classpath.ClassPath; -import com.threerings.getdown.classpath.NativeLibPath; import com.threerings.getdown.util.*; // avoid ambiguity with java.util.Base64 which we can't use as it's 1.8+ import com.threerings.getdown.util.Base64; @@ -55,9 +52,6 @@ public class Application /** A special classname that means 'use -jar code.jar' instead of a classname. */ public static final String MANIFEST_CLASS = "manifest"; - /** Name of directory to store cached files in. */ - public static final String CACHE_DIR = ".cache"; - /** Used to communicate information about the UI displayed when updating the application. */ public static final class UpdateInterface { @@ -379,19 +373,17 @@ public class Application } /** - * Returns all jar resources indicated to contain native library files (.dll, .so etc.) + * Returns all resources indicated to contain native library files (.dll, .so, etc.). */ - public List getNativeJars() { - - List nativeJars = new ArrayList<>(); - + public List getNativeResources () + { + List natives = new ArrayList<>(); for (Resource resource: _resources) { - if (resource.isNativeJar()) { - nativeJars.add(resource); + if (resource.isNative()) { + natives.add(resource); } } - - return nativeJars; + return natives; } /** @@ -702,7 +694,10 @@ public class Application parseResources(config, auxgroup + ".ucode", Resource.UNPACK, codes); ArrayList rsrcs = new ArrayList<>(); parseResources(config, auxgroup + ".resource", Resource.NORMAL, rsrcs); + parseResources(config, auxgroup + ".xresource", Resource.EXEC, rsrcs); parseResources(config, auxgroup + ".uresource", Resource.UNPACK, rsrcs); + parseResources(config, auxgroup + ".presource", Resource.PRELOAD, rsrcs); + parseResources(config, auxgroup + ".nresource", Resource.NATIVE, rsrcs); _auxgroups.put(auxgroup, new AuxGroup(auxgroup, codes, rsrcs)); } @@ -934,12 +929,7 @@ public class Application boolean dashJarMode = MANIFEST_CLASS.equals(_class); // add the -classpath arguments if we're not in -jar mode - ClassPath classPath = ClassPaths.buildClassPath(this); - - // get the -Djava.library.path value to pass - // @TODO optional getdown.txt parameter to set addCurrentLibraryPath to true or false? - NativeLibPath nativeLibPaths = NativeLibPath.buildLibsPath(this, true); - + ClassPath classPath = PathBuilder.buildClassPath(this); if (!dashJarMode) { args.add("-classpath"); args.add(classPath.asArgumentString()); @@ -963,8 +953,12 @@ public class Application // add the marker indicating the app is running in getdown args.add("-D" + Properties.GETDOWN + "=true"); - // set the native library path - args.add("-Djava.library.path=" + nativeLibPaths.asArgumentString()); + // set the native library path if we have native resources + // @TODO optional getdown.txt parameter to set addCurrentLibraryPath to true or false? + ClassPath javaLibPath = PathBuilder.buildLibsPath(this, true); + if (javaLibPath != null) { + args.add("-Djava.library.path=" + javaLibPath.asArgumentString()); + } // pass along any pass-through arguments for (Map.Entry entry : System.getProperties().entrySet()) { @@ -1044,7 +1038,7 @@ public class Application */ public void invokeDirect () throws IOException { - ClassPath classPath = ClassPaths.buildClassPath(this); + ClassPath classPath = PathBuilder.buildClassPath(this); URL[] jarUrls = classPath.asUrls(); // create custom class loader diff --git a/core/src/main/java/com/threerings/getdown/classpath/ClassPath.java b/core/src/main/java/com/threerings/getdown/data/ClassPath.java similarity index 80% rename from core/src/main/java/com/threerings/getdown/classpath/ClassPath.java rename to core/src/main/java/com/threerings/getdown/data/ClassPath.java index d96b712..0777b2f 100644 --- a/core/src/main/java/com/threerings/getdown/classpath/ClassPath.java +++ b/core/src/main/java/com/threerings/getdown/data/ClassPath.java @@ -1,4 +1,9 @@ -package com.threerings.getdown.classpath; +// +// Getdown - application installer, patcher and launcher +// Copyright (C) 2004-2016 Getdown authors +// https://github.com/threerings/getdown/blob/master/LICENSE + +package com.threerings.getdown.data; import java.io.File; import java.net.MalformedURLException; @@ -9,9 +14,9 @@ import java.util.LinkedHashSet; import java.util.Set; /** - * Represents the class path and it's elements of the application to be launched. The class path can - * either be represented as an {@link #asArgumentString() argument string} for the java command line - * or as an {@link #asUrls() array of URLs} to be used by a {@link URLClassLoader}. + * Represents the class path and it's elements of the application to be launched. The class path + * can either be represented as an {@link #asArgumentString() argument string} for the java command + * line or as an {@link #asUrls() array of URLs} to be used by a {@link URLClassLoader}. */ public class ClassPath { diff --git a/core/src/main/java/com/threerings/getdown/data/PathBuilder.java b/core/src/main/java/com/threerings/getdown/data/PathBuilder.java new file mode 100644 index 0000000..932fe30 --- /dev/null +++ b/core/src/main/java/com/threerings/getdown/data/PathBuilder.java @@ -0,0 +1,135 @@ +// +// Getdown - application installer, patcher and launcher +// Copyright (C) 2004-2016 Getdown authors +// https://github.com/threerings/getdown/blob/master/LICENSE + +package com.threerings.getdown.data; + +import java.io.File; +import java.io.IOException; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.jar.JarFile; + +import com.threerings.getdown.cache.GarbageCollector; +import com.threerings.getdown.cache.ResourceCache; +import com.threerings.getdown.util.FileUtil; +import static com.threerings.getdown.Log.log; + +public class PathBuilder +{ + /** Name of directory to store cached code files in. */ + public static final String CODE_CACHE_DIR = ".cache"; + + /** Name of directory to store cached native resources in. */ + public static final String NATIVE_CACHE_DIR = ".ncache"; + + /** + * Builds either a default or cached classpath based on {@code app}'s configuration. + */ + public static ClassPath buildClassPath (Application app) throws IOException + { + return app.useCodeCache() ? buildCachedClassPath(app) : buildDefaultClassPath(app); + } + + /** + * Builds a {@link ClassPath} instance for {@code app} using the code resources in place in + * the app directory. + */ + public static ClassPath buildDefaultClassPath (Application app) + { + LinkedHashSet classPathEntries = new LinkedHashSet(); + for (Resource resource: app.getActiveCodeResources()) { + classPathEntries.add(resource.getFinalTarget()); + } + return new ClassPath(classPathEntries); + } + + /** + * Builds a {@link ClassPath} instance for {@code app} by first copying the code resources into + * a cache directory and then referencing them from there. This avoids problems with + * overwriting in-use classpath elements when the application is later updated. This also + * "garbage collects" expired caches if necessary. + */ + public static ClassPath buildCachedClassPath (Application app) throws IOException + { + File codeCacheDir = new File(app.getAppDir(), CODE_CACHE_DIR); + + // a negative value of code_cache_retention_days allows to clean up the cache forcefully + long retainMillis = TimeUnit.DAYS.toMillis(app.getCodeCacheRetentionDays()); + if (retainMillis != 0L) { + GarbageCollector.collect(codeCacheDir, retainMillis); + } + + ResourceCache cache = new ResourceCache(codeCacheDir); + LinkedHashSet classPathEntries = new LinkedHashSet<>(); + for (Resource resource: app.getActiveCodeResources()) { + String digest = app.getDigest(resource); + File entry = cache.cacheFile(resource.getFinalTarget(), digest.substring(0, 2), digest); + classPathEntries.add(entry); + } + + return new ClassPath(classPathEntries); + } + + /** + * Builds a {@link ClassPath} instance by first caching all native jars (indicated by + * nresource=[native jar]), unpacking them, and referencing the locations of each of the + * unpacked files. Also performs garbage collection similar to {@link #buildCachedClassPath} + * + * @param app used to determine native jars and related information. + * @param addCurrentLibraryPath if true, it adds the locations referenced by + * {@code System.getProperty("java.library.path")} as well. + * @return a classpath instance if at least one native resource was found and unpacked, + * {@code null} if no native resources were used by the application. + */ + public static ClassPath buildLibsPath (Application app, + boolean addCurrentLibraryPath) throws IOException { + List resources = app.getNativeResources(); + if (resources.isEmpty()) { + return null; + } + + LinkedHashSet nativedirs = new LinkedHashSet<>(); + File nativeCacheDir = new File(app.getAppDir(), NATIVE_CACHE_DIR); + ResourceCache cache = new ResourceCache(nativeCacheDir); + + // negative value forces total garbage collection, 0 avoids garbage collection at all + long retainMillis = TimeUnit.DAYS.toMillis(app.getCodeCacheRetentionDays()); + if (retainMillis != 0L) { + GarbageCollector.collectNative(nativeCacheDir, retainMillis); + } + + for (Resource resource : resources) { + // Use untruncated cache subdirectory names to avoid overwriting issues when unpacking, + // in the off chance that two native jars share a directory AND contain files with the + // same names + String digest = app.getDigest(resource); + File cachedFile = cache.cacheFile(resource.getFinalTarget(), digest, digest); + File cachedParent = cachedFile.getParentFile(); + File unpackedIndicator = new File(cachedParent, cachedFile.getName() + ".unpacked"); + + if (!unpackedIndicator.exists()) { + try { + FileUtil.unpackJar(new JarFile(cachedFile), cachedParent, false); + unpackedIndicator.createNewFile(); + } catch (IOException ioe) { + log.warning("Failed to unpack native jar", + "file", cachedFile.getAbsolutePath(), ioe); + // Keep going and unpack the other jars... + } + } + + nativedirs.add(cachedFile.getParentFile()); + } + + if (addCurrentLibraryPath) { + for (String path : System.getProperty("java.library.path").split(File.pathSeparator)) { + nativedirs.add(new File(path)); + } + } + + return new ClassPath(nativedirs); + } +} diff --git a/core/src/main/java/com/threerings/getdown/data/Resource.java b/core/src/main/java/com/threerings/getdown/data/Resource.java index 9d6a040..babfecc 100644 --- a/core/src/main/java/com/threerings/getdown/data/Resource.java +++ b/core/src/main/java/com/threerings/getdown/data/Resource.java @@ -46,7 +46,7 @@ public class Resource implements Comparable public static final EnumSet UNPACK = EnumSet.of(Attr.UNPACK); public static final EnumSet EXEC = EnumSet.of(Attr.EXEC); public static final EnumSet PRELOAD = EnumSet.of(Attr.PRELOAD); - public static final EnumSet NATIVE = EnumSet.of(Attr.NATIVE); + public static final EnumSet NATIVE = EnumSet.of(Attr.NATIVE); /** * Computes the MD5 hash of the supplied file. @@ -218,12 +218,11 @@ public class Resource implements Comparable /** * Returns true if this resource is a native lib jar. */ - public boolean isNativeJar () + public boolean isNative () { return _attrs.contains(Attr.NATIVE); } - /** * Computes the MD5 hash of this resource's underlying file. * Note: This is both CPU and I/O intensive. diff --git a/core/src/main/java/com/threerings/getdown/util/FileUtil.java b/core/src/main/java/com/threerings/getdown/util/FileUtil.java index d3325af..20fd992 100644 --- a/core/src/main/java/com/threerings/getdown/util/FileUtil.java +++ b/core/src/main/java/com/threerings/getdown/util/FileUtil.java @@ -79,20 +79,17 @@ public class FileUtil /** * Force deletes {@code file} and all of its children recursively using {@link #deleteHarder}. - * Note that some children may still be deleted even if {@code false} is returned. Also, since {@link #deleteHarder} - * is used, the {@code file} could be deleted once the jvm exits even if {@code false} is returned. + * Note that some children may still be deleted even if {@code false} is returned. Also, since + * {@link #deleteHarder} is used, the {@code file} could be deleted once the jvm exits even if + * {@code false} is returned. * - * @param file file to delete + * @param file file to delete. * @return true iff {@code file} was successfully deleted. */ - public static boolean deleteDirHarder(File file) { + public static boolean deleteDirHarder (File file) { if (file.isDirectory()) { for (File child : file.listFiles()) { - if (child.isDirectory()) { - deleteDirHarder(child); - } else { - deleteHarder(child); - } + deleteDirHarder(child); } } return deleteHarder(file); @@ -211,7 +208,7 @@ public class FileUtil } /** - * Used by {@link #walkTree} and {@link #walkDirectChildren}. + * Used by {@link #walkTree}. */ public interface Visitor { @@ -239,21 +236,4 @@ public class FileUtil } } } - - /** - * Walks all direct sub-files of {@code root}, calling {@code visitor} on each file. - */ - public static void walkDirectChildren (final File root, Visitor visitor) { - File[] children = root.listFiles(); - - if (children == null) return; - Deque stack = new ArrayDeque<>(Arrays.asList(children)); - while (!stack.isEmpty()) { - File currentFile = stack.pop(); - if (currentFile.exists()) { - visitor.visit(currentFile); - } - } - } - } diff --git a/core/src/test/java/com/threerings/getdown/classpath/cache/GarbageCollectorTest.java b/core/src/test/java/com/threerings/getdown/cache/GarbageCollectorTest.java similarity index 89% rename from core/src/test/java/com/threerings/getdown/classpath/cache/GarbageCollectorTest.java rename to core/src/test/java/com/threerings/getdown/cache/GarbageCollectorTest.java index ee86685..6b604cf 100644 --- a/core/src/test/java/com/threerings/getdown/classpath/cache/GarbageCollectorTest.java +++ b/core/src/test/java/com/threerings/getdown/cache/GarbageCollectorTest.java @@ -1,4 +1,9 @@ -package com.threerings.getdown.classpath.cache; +// +// Getdown - application installer, patcher and launcher +// Copyright (C) 2004-2016 Getdown authors +// https://github.com/threerings/getdown/blob/master/LICENSE + +package com.threerings.getdown.cache; import java.io.File; import java.io.IOException; diff --git a/core/src/test/java/com/threerings/getdown/classpath/cache/ResourceCacheTest.java b/core/src/test/java/com/threerings/getdown/cache/ResourceCacheTest.java similarity index 88% rename from core/src/test/java/com/threerings/getdown/classpath/cache/ResourceCacheTest.java rename to core/src/test/java/com/threerings/getdown/cache/ResourceCacheTest.java index 8002f0b..8b699bf 100644 --- a/core/src/test/java/com/threerings/getdown/classpath/cache/ResourceCacheTest.java +++ b/core/src/test/java/com/threerings/getdown/cache/ResourceCacheTest.java @@ -1,4 +1,9 @@ -package com.threerings.getdown.classpath.cache; +// +// Getdown - application installer, patcher and launcher +// Copyright (C) 2004-2016 Getdown authors +// https://github.com/threerings/getdown/blob/master/LICENSE + +package com.threerings.getdown.cache; import java.io.File; import java.io.IOException; @@ -26,7 +31,7 @@ public class ResourceCacheTest private File cacheFile() throws IOException { - return _cache.cacheFile(_fileToCache, "abc123"); + return _cache.cacheFile(_fileToCache, "abc123", "abc123"); } @Test public void shouldTrackFileUsage () throws IOException diff --git a/core/src/test/java/com/threerings/getdown/classpath/ClassPathTest.java b/core/src/test/java/com/threerings/getdown/data/ClassPathTest.java similarity index 87% rename from core/src/test/java/com/threerings/getdown/classpath/ClassPathTest.java rename to core/src/test/java/com/threerings/getdown/data/ClassPathTest.java index fb90a80..1779f64 100644 --- a/core/src/test/java/com/threerings/getdown/classpath/ClassPathTest.java +++ b/core/src/test/java/com/threerings/getdown/data/ClassPathTest.java @@ -1,4 +1,9 @@ -package com.threerings.getdown.classpath; +// +// Getdown - application installer, patcher and launcher +// Copyright (C) 2004-2016 Getdown authors +// https://github.com/threerings/getdown/blob/master/LICENSE + +package com.threerings.getdown.data; import java.io.File; import java.io.IOException; diff --git a/core/src/test/java/com/threerings/getdown/classpath/ClassPathsTest.java b/core/src/test/java/com/threerings/getdown/data/PathBuilderTest.java similarity index 79% rename from core/src/test/java/com/threerings/getdown/classpath/ClassPathsTest.java rename to core/src/test/java/com/threerings/getdown/data/PathBuilderTest.java index 05b47a1..5bdbcad 100644 --- a/core/src/test/java/com/threerings/getdown/classpath/ClassPathsTest.java +++ b/core/src/test/java/com/threerings/getdown/data/PathBuilderTest.java @@ -1,4 +1,9 @@ -package com.threerings.getdown.classpath; +// +// Getdown - application installer, patcher and launcher +// Copyright (C) 2004-2016 Getdown authors +// https://github.com/threerings/getdown/blob/master/LICENSE + +package com.threerings.getdown.data; import java.io.File; import java.io.IOException; @@ -14,11 +19,8 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import static org.mockito.Mockito.when; -import com.threerings.getdown.data.Application; -import com.threerings.getdown.data.Resource; - @RunWith(MockitoJUnitRunner.class) -public class ClassPathsTest +public class PathBuilderTest { @Before public void setupFilesAndResources () throws IOException { @@ -33,7 +35,7 @@ public class ClassPathsTest @Test public void shouldBuildDefaultClassPath () throws IOException { - ClassPath classPath = ClassPaths.buildDefaultClassPath(_application); + ClassPath classPath = PathBuilder.buildDefaultClassPath(_application); String expectedClassPath = _firstJarFile.getAbsolutePath() + File.pathSeparator + _secondJarFile.getAbsolutePath(); assertEquals(expectedClassPath, classPath.asArgumentString()); @@ -46,15 +48,15 @@ public class ClassPathsTest when(_application.getCodeCacheRetentionDays()).thenReturn(1); Path firstCachedJarFile = _appdir.getRoot().toPath(). - resolve(Application.CACHE_DIR + "/code").resolve("fi").resolve("first.jar"); + resolve(PathBuilder.CODE_CACHE_DIR).resolve("fi").resolve("first.jar"); Path secondCachedJarFile = _appdir.getRoot().toPath(). - resolve(Application.CACHE_DIR + "/code").resolve("se").resolve("second.jar"); + resolve(PathBuilder.CODE_CACHE_DIR).resolve("se").resolve("second.jar"); String expectedClassPath = firstCachedJarFile.toAbsolutePath() + File.pathSeparator + secondCachedJarFile.toAbsolutePath(); - ClassPath classPath = ClassPaths.buildCachedClassPath(_application); + ClassPath classPath = PathBuilder.buildCachedClassPath(_application); assertEquals(expectedClassPath, classPath.asArgumentString()); }