diff --git a/.travis.yml b/.travis.yml index 7b43b6822..e526c902f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,19 @@ language: java notifications: email: false before_install: chmod +x gradlew -install: ./gradlew setupCIWorkspace -S -matrix: - include: - - jdk: oraclejdk7 - script: ./gradlew build -S \ No newline at end of file +install: ./gradlew setupCIWorkspace -s +script: ./gradlew build -s +jdk: + - oraclejdk8 + - oraclejdk7 + - openjdk6 +# Caching for Gradle files, prevents hitting Maven too much. +before_cache: + - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock +cache: + directories: + - $HOME/.gradle/caches/ + - $HOME/.gradle/wrapper/ + +# Faster builds without sudo. +sudo: false diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/Closer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/Closer.java index 2e733c6ab..6b5c37efe 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/Closer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/Closer.java @@ -29,6 +29,7 @@ import java.util.ArrayDeque; import java.util.Deque; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.zip.ZipFile; import static com.google.common.base.Preconditions.checkNotNull; @@ -55,6 +56,7 @@ public final class Closer implements Closeable { // only need space for 2 elements in most cases, so try to use the smallest array possible private final Deque stack = new ArrayDeque(4); + private final Deque zipStack = new ArrayDeque(4); private Throwable thrown; @VisibleForTesting Closer(Suppressor suppressor) { @@ -73,6 +75,17 @@ public final class Closer implements Closeable { return closeable; } + /** + * Registers the given {@code zipFile} to be closed when this {@code Closer} is + * {@linkplain #close closed}. + * + * @return the given {@code closeable} + */ + public Z register(Z zipFile) { + zipStack.push(zipFile); + return zipFile; + } + /** * Stores the given throwable and rethrows it. It will be rethrown as is if it is an * {@code IOException}, {@code RuntimeException} or {@code Error}. Otherwise, it will be rethrown @@ -161,6 +174,18 @@ public final class Closer implements Closeable { } } } + while (!zipStack.isEmpty()) { + ZipFile zipFile = zipStack.pop(); + try { + zipFile.close(); + } catch (Throwable e) { + if (throwable == null) { + throwable = e; + } else { + suppressor.suppress(zipFile, throwable, e); + } + } + } if (thrown == null && throwable != null) { Throwables.propagateIfPossible(throwable, IOException.class); @@ -177,7 +202,7 @@ public final class Closer implements Closeable { * the given closeable. {@code thrown} is the exception that is actually being thrown from the * method. Implementations of this method should not throw under any circumstances. */ - void suppress(Closeable closeable, Throwable thrown, Throwable suppressed); + void suppress(Object closeable, Throwable thrown, Throwable suppressed); } /** @@ -188,7 +213,7 @@ public final class Closer implements Closeable { static final LoggingSuppressor INSTANCE = new LoggingSuppressor(); @Override - public void suppress(Closeable closeable, Throwable thrown, Throwable suppressed) { + public void suppress(Object closeable, Throwable thrown, Throwable suppressed) { // log to the same place as Closeables logger.log(Level.WARNING, "Suppressing exception thrown when closing " + closeable, suppressed); } @@ -217,7 +242,7 @@ public final class Closer implements Closeable { } @Override - public void suppress(Closeable closeable, Throwable thrown, Throwable suppressed) { + public void suppress(Object closeable, Throwable thrown, Throwable suppressed) { // ensure no exceptions from addSuppressed if (thrown == suppressed) { return;