diff options
9 files changed, 71 insertions, 24 deletions
diff --git a/src/main/java/com/android/tools/r8/BaseCommand.java b/src/main/java/com/android/tools/r8/BaseCommand.java index 85c430a44..aa0e39659 100644 --- a/src/main/java/com/android/tools/r8/BaseCommand.java +++ b/src/main/java/com/android/tools/r8/BaseCommand.java @@ -22,6 +22,7 @@ abstract class BaseCommand { private final OutputMode outputMode; private final CompilationMode mode; private final int minApiLevel; + private final boolean overwriteOutputs; BaseCommand(boolean printHelp, boolean printVersion) { this.printHelp = printHelp; @@ -32,10 +33,11 @@ abstract class BaseCommand { this.outputMode = OutputMode.Indexed; this.mode = null; this.minApiLevel = 0; + this.overwriteOutputs = true; } BaseCommand(AndroidApp app, Path outputPath, - OutputMode outputMode, CompilationMode mode, int minApiLevel) { + OutputMode outputMode, CompilationMode mode, int minApiLevel, boolean overwriteOutputs) { assert app != null; assert mode != null; assert minApiLevel > 0; @@ -44,6 +46,7 @@ abstract class BaseCommand { this.outputMode = outputMode; this.mode = mode; this.minApiLevel = minApiLevel; + this.overwriteOutputs = overwriteOutputs; // Print options are not set. printHelp = false; printVersion = false; @@ -81,6 +84,10 @@ abstract class BaseCommand { return outputMode; } + public boolean isOverwriteOutputs() { + return overwriteOutputs; + } + abstract static class Builder<C extends BaseCommand, B extends Builder<C, B>> { private boolean printHelp = false; @@ -90,6 +97,7 @@ abstract class BaseCommand { private OutputMode outputMode = OutputMode.Indexed; private CompilationMode mode; private int minApiLevel = Constants.DEFAULT_ANDROID_API; + private boolean overwriteOutputs = true; protected Builder(CompilationMode mode) { this(AndroidApp.builder(), mode); @@ -197,9 +205,9 @@ abstract class BaseCommand { return outputMode; } - /** Set an output path. Must be an existing directory or a non-existent zip file. */ - public B setOutputPath(Path outputPath) throws CompilationException { - this.outputPath = FileUtils.validateOutputFile(outputPath); + /** Set an output path. Must be an existing directory or a zip file. */ + public B setOutputPath(Path outputPath) { + this.outputPath = outputPath; return self(); } @@ -248,5 +256,17 @@ abstract class BaseCommand { this.printVersion = printVersion; return self(); } + + protected boolean isOverwriteOutputs() { + return overwriteOutputs; + } + + protected void setOverwriteOutputs(boolean overwriteOutputs) { + this.overwriteOutputs = overwriteOutputs; + } + + protected void validate() throws CompilationException { + FileUtils.validateOutputFile(outputPath, overwriteOutputs); + } } } diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java index 62cb5a57d..0ef972889 100644 --- a/src/main/java/com/android/tools/r8/D8Command.java +++ b/src/main/java/com/android/tools/r8/D8Command.java @@ -101,8 +101,10 @@ public class D8Command extends BaseCommand { if (isPrintHelp() || isPrintVersion()) { return new D8Command(isPrintHelp(), isPrintVersion()); } + + validate(); return new D8Command(getAppBuilder().build(), - getOutputPath(), getOutputMode(), getMode(), getMinApiLevel()); + getOutputPath(), getOutputMode(), getMode(), getMinApiLevel(), isOverwriteOutputs()); } } @@ -180,8 +182,8 @@ public class D8Command extends BaseCommand { } private D8Command(AndroidApp inputApp, Path outputPath, - OutputMode outputMode, CompilationMode mode, int minApiLevel) { - super(inputApp, outputPath, outputMode, mode, minApiLevel); + OutputMode outputMode, CompilationMode mode, int minApiLevel, boolean overwriteOutputs) { + super(inputApp, outputPath, outputMode, mode, minApiLevel, overwriteOutputs); } private D8Command(boolean printHelp, boolean printVersion) { @@ -194,7 +196,7 @@ public class D8Command extends BaseCommand { assert !internal.debug; internal.debug = getMode() == CompilationMode.DEBUG; internal.minApiLevel = getMinApiLevel(); - internal.overwriteOutputs = true; + internal.overwriteOutputs = isOverwriteOutputs(); // Assert and fixup defaults. assert !internal.skipMinification; internal.skipMinification = true; diff --git a/src/main/java/com/android/tools/r8/DexSegments.java b/src/main/java/com/android/tools/r8/DexSegments.java index 501fecc16..09eb21e50 100644 --- a/src/main/java/com/android/tools/r8/DexSegments.java +++ b/src/main/java/com/android/tools/r8/DexSegments.java @@ -41,12 +41,14 @@ public class DexSegments { if (isPrintHelp()) { return new Command(isPrintHelp()); } + validate(); return new Command( getAppBuilder().build(), getOutputPath(), getOutputMode(), getMode(), - getMinApiLevel()); + getMinApiLevel(), + isOverwriteOutputs()); } } @@ -89,8 +91,9 @@ public class DexSegments { Path outputPath, OutputMode outputMode, CompilationMode mode, - int minApiLevel) { - super(inputApp, outputPath, outputMode, mode, minApiLevel); + int minApiLevel, + boolean isOverwrite) { + super(inputApp, outputPath, outputMode, mode, minApiLevel, isOverwrite); } private Command(boolean printHelp) { diff --git a/src/main/java/com/android/tools/r8/Disassemble.java b/src/main/java/com/android/tools/r8/Disassemble.java index b183ecc17..7d7389533 100644 --- a/src/main/java/com/android/tools/r8/Disassemble.java +++ b/src/main/java/com/android/tools/r8/Disassemble.java @@ -46,13 +46,15 @@ public class Disassemble { return new DisassembleCommand(isPrintHelp(), isPrintVersion()); } + validate(); return new DisassembleCommand( getAppBuilder().build(), getOutputPath(), getOutputMode(), getMode(), getMinApiLevel(), - useSmali); + useSmali, + isOverwriteOutputs()); } } @@ -108,8 +110,9 @@ public class Disassemble { OutputMode outputMode, CompilationMode mode, int minApiLevel, - boolean useSmali) { - super(inputApp, outputPath, outputMode, mode, minApiLevel); + boolean useSmali, + boolean isOverwrite) { + super(inputApp, outputPath, outputMode, mode, minApiLevel, isOverwrite); //assert getOutputMode() == OutputMode.Indexed : "Only regular mode is supported in R8"; this.useSmali = useSmali; } diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java index 7d0146290..7fd1c6f72 100644 --- a/src/main/java/com/android/tools/r8/R8Command.java +++ b/src/main/java/com/android/tools/r8/R8Command.java @@ -136,6 +136,7 @@ public class R8Command extends BaseCommand { return new R8Command(isPrintHelp(), isPrintVersion()); } + validate(); DexItemFactory factory = new DexItemFactory(); ImmutableList<ProguardConfigurationRule> mainDexKeepRules; if (this.mainDexRules.isEmpty()) { @@ -178,7 +179,8 @@ public class R8Command extends BaseCommand { getMinApiLevel(), useTreeShaking, useMinification, - ignoreMissingClasses); + ignoreMissingClasses, + isOverwriteOutputs()); } } @@ -321,8 +323,9 @@ public class R8Command extends BaseCommand { int minApiLevel, boolean useTreeShaking, boolean useMinification, - boolean ignoreMissingClasses) { - super(inputApp, outputPath, outputMode, mode, minApiLevel); + boolean ignoreMissingClasses, + boolean overwriteOutputs) { + super(inputApp, outputPath, outputMode, mode, minApiLevel, overwriteOutputs); assert proguardConfiguration != null; assert mainDexKeepRules != null; assert getOutputMode() == OutputMode.Indexed : "Only regular mode is supported in R8"; diff --git a/src/main/java/com/android/tools/r8/utils/FileUtils.java b/src/main/java/com/android/tools/r8/utils/FileUtils.java index 3f69c2e88..6a708455d 100644 --- a/src/main/java/com/android/tools/r8/utils/FileUtils.java +++ b/src/main/java/com/android/tools/r8/utils/FileUtils.java @@ -73,10 +73,10 @@ public class FileUtils { Files.write(file, Arrays.asList(lines)); } - public static Path validateOutputFile(Path path) throws CompilationException { + public static Path validateOutputFile(Path path, boolean allowOverwrite) throws CompilationException { if (path != null) { if (isZipFile(path)) { - if (Files.exists(path)) { + if ((!allowOverwrite) && Files.exists(path)) { throw new CompilationException("Cannot write to existing output file: " + path); } } else if (!(Files.exists(path) && Files.isDirectory(path))) { diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java index e74eb2c15..e039e9e2f 100644 --- a/src/test/java/com/android/tools/r8/ToolHelper.java +++ b/src/test/java/com/android/tools/r8/ToolHelper.java @@ -725,4 +725,10 @@ public class ToolHelper { public static AndroidApp getApp(BaseCommand command) { return command.getInputApp(); } + + public static <T extends BaseCommand, U extends BaseCommand.Builder<T, U>> + U setOverwrite(U commandBuilder, boolean overwrite) { + commandBuilder.setOverwriteOutputs(overwrite); + return commandBuilder; + } } diff --git a/src/test/java/com/android/tools/r8/utils/D8CommandTest.java b/src/test/java/com/android/tools/r8/utils/D8CommandTest.java index be72756df..b0869106f 100644 --- a/src/test/java/com/android/tools/r8/utils/D8CommandTest.java +++ b/src/test/java/com/android/tools/r8/utils/D8CommandTest.java @@ -58,7 +58,7 @@ public class D8CommandTest { @Test public void defaultOutIsCwd() throws IOException, InterruptedException { Path working = temp.getRoot().toPath(); - Path input = Paths.get(EXAMPLES_BUILD_DIR, "arithmetic.jar").toAbsolutePath(); + Path input = Paths.get(EXAMPLES_BUILD_DIR + "/arithmetic.jar").toAbsolutePath(); Path output = working.resolve("classes.dex"); assertFalse(Files.exists(output)); assertEquals(0, ToolHelper.forkD8(working, input.toString()).exitCode); @@ -91,9 +91,15 @@ public class D8CommandTest { } @Test - public void existingOutputZip() throws Throwable { + public void existingOutputZipNoOverwrite() throws Throwable { thrown.expect(CompilationException.class); Path existingZip = temp.newFile("an-existing-archive.zip").toPath(); + ToolHelper.setOverwrite(D8Command.builder().setOutputPath(existingZip), false).build(); + } + + @Test + public void existingOutputZip() throws Throwable { + Path existingZip = temp.newFile("an-existing-archive.zip").toPath(); D8Command.builder().setOutputPath(existingZip).build(); } @@ -113,7 +119,6 @@ public class D8CommandTest { @Test public void existingOutputZipParse() throws Throwable { - thrown.expect(CompilationException.class); Path existingZip = temp.newFile("an-existing-archive.zip").toPath(); parse("--output", existingZip.toString()); } diff --git a/src/test/java/com/android/tools/r8/utils/R8CommandTest.java b/src/test/java/com/android/tools/r8/utils/R8CommandTest.java index 935275aa5..15df84fe1 100644 --- a/src/test/java/com/android/tools/r8/utils/R8CommandTest.java +++ b/src/test/java/com/android/tools/r8/utils/R8CommandTest.java @@ -98,12 +98,18 @@ public class R8CommandTest { @Test public void existingOutputZip() throws Throwable { - thrown.expect(CompilationException.class); Path existingZip = temp.newFile("an-existing-archive.zip").toPath(); R8Command.builder().setOutputPath(existingZip).build(); } @Test + public void existingOutputZipNoOverwrite() throws Throwable { + thrown.expect(CompilationException.class); + Path existingZip = temp.newFile("an-existing-archive.zip").toPath(); + ToolHelper.setOverwrite(R8Command.builder().setOutputPath(existingZip), false).build(); + } + + @Test public void invalidOutputFileType() throws Throwable { thrown.expect(CompilationException.class); Path invalidType = temp.getRoot().toPath().resolve("an-invalid-output-file-type.foobar"); @@ -119,7 +125,6 @@ public class R8CommandTest { @Test public void existingOutputZipParse() throws Throwable { - thrown.expect(CompilationException.class); Path existingZip = temp.newFile("an-existing-archive.zip").toPath(); parse("--output", existingZip.toString()); } |