Share --output in CliParserUtils and improve descriptions. Change-Id: I9d8fecaf3fa58200bbf98039b77b162c01bb34e9
diff --git a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java index 2875d1f..d340494 100644 --- a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java +++ b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
@@ -131,15 +131,20 @@ private static CliParser<Builder> createParser() { BooleanBox hasDefinedApiLevel = new BooleanBox(false); + BooleanBox hasSetOutputPath = new BooleanBox(false); var parser = new CliParser<Builder>( StringUtils.lines("Usage: BackportedMethodList [options]", " Options are:")); parser - .option1( - "--output", - "<file>", - "Output result in <file>.", - (b, arg) -> b.setOutputPath(Paths.get(arg))) + .apply( + CliParserUtils.addOutputOption( + b -> hasSetOutputPath.get(), + (b, path) -> { + b.setOutputPath(path); + hasSetOutputPath.set(true); + }, + (b, error) -> b.reporter.error(new StringDiagnostic(error)), + CliParserUtils.OutputOptionType.FILE)) .apply( CliParserUtils.addMinApiOption( b -> hasDefinedApiLevel.get(),
diff --git a/src/main/java/com/android/tools/r8/D8CommandParser.java b/src/main/java/com/android/tools/r8/D8CommandParser.java index ce5ffc8..94fc092 100644 --- a/src/main/java/com/android/tools/r8/D8CommandParser.java +++ b/src/main/java/com/android/tools/r8/D8CommandParser.java
@@ -176,20 +176,12 @@ state.compilationMode = CompilationMode.RELEASE; } }) - .option1( - "--output", - "<file>", - "Output result in <file>. <file> must be an existing directory or a zip file.", - (state, arg) -> { - if (state.outputPath != null) { - state.builder.error( - new StringDiagnostic( - "Cannot output both to '" + state.outputPath + "' and '" + arg + "'", - state.origin)); - } else { - state.outputPath = Paths.get(arg); - } - }) + .apply( + CliParserUtils.addOutputOption( + state -> state.outputPath != null, + (state, path) -> state.outputPath = path, + (state, error) -> state.builder.error(new StringDiagnostic(error, state.origin)), + CliParserUtils.OutputOptionType.ZIP_OR_EXISTING_DIR)) .option1( "--globals", "<file>",
diff --git a/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommandParser.java b/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommandParser.java index 92de03b..527c631 100644 --- a/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommandParser.java +++ b/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommandParser.java
@@ -65,20 +65,12 @@ "<file|jdk-home>", "Add <file|jdk-home> as a library resource.", (b, arg) -> b.builder.addLibraryFiles(Paths.get(arg))) - .option1( - "--output", - "<globals-file>", - "Output result in <globals-file>.", - (b, arg) -> { - if (b.outputPath != null) { - StringDiagnostic diagnostic = - new StringDiagnostic( - "Cannot output both to '" + b.outputPath + "' and '" + arg + "'", b.origin); - b.builder.error(diagnostic); - } else { - b.outputPath = Paths.get(arg); - } - }) + .apply( + CliParserUtils.addOutputOption( + b -> b.outputPath != null, + (b, path) -> b.outputPath = path, + (b, error) -> b.builder.error(new StringDiagnostic(error, b.origin)), + CliParserUtils.OutputOptionType.FILE)) .option0( "--classfile", "Generate globals for only classfile to classfile desugaring. (By default globals for"
diff --git a/src/main/java/com/android/tools/r8/L8CommandParser.java b/src/main/java/com/android/tools/r8/L8CommandParser.java index 7ea71a6..e2b989d 100644 --- a/src/main/java/com/android/tools/r8/L8CommandParser.java +++ b/src/main/java/com/android/tools/r8/L8CommandParser.java
@@ -96,21 +96,12 @@ state.compilationMode = CompilationMode.RELEASE; } }) - .option1( - "--output", - "<file>", - "Output result in <file>. <file> must be an existing directory or a zip file.", - (state, arg) -> { - if (state.outputPath != null) { - StringDiagnostic diagnostic = - new StringDiagnostic( - "Cannot output both to '" + state.outputPath + "' and '" + arg + "'", - state.origin); - state.builder.error(diagnostic); - } else { - state.outputPath = Paths.get(arg); - } - }) + .apply( + CliParserUtils.addOutputOption( + state -> state.outputPath != null, + (state, path) -> state.outputPath = path, + (state, error) -> state.builder.error(new StringDiagnostic(error, state.origin)), + CliParserUtils.OutputOptionType.ZIP_OR_EXISTING_DIR)) .option1( "--lib", "<file|jdk-home>",
diff --git a/src/main/java/com/android/tools/r8/R8CommandParser.java b/src/main/java/com/android/tools/r8/R8CommandParser.java index 8a0d042..c491411 100644 --- a/src/main/java/com/android/tools/r8/R8CommandParser.java +++ b/src/main/java/com/android/tools/r8/R8CommandParser.java
@@ -95,20 +95,12 @@ } state.outputMode = OutputMode.ClassFile; }) - .option1( - "--output", - "<file>", - "Output result in <file>. <file> must be an existing directory or a zip file.", - (state, arg) -> { - if (state.outputPath != null) { - StringDiagnostic diagnostic = - new StringDiagnostic( - "Cannot output both to '" + state.outputPath + "' and '" + arg + "'", - state.origin); - state.builder.error(diagnostic); - } - state.outputPath = Paths.get(arg); - }) + .apply( + CliParserUtils.addOutputOption( + state -> state.outputPath != null, + (state, path) -> state.outputPath = path, + (state, error) -> state.builder.error(new StringDiagnostic(error, state.origin)), + CliParserUtils.OutputOptionType.ZIP_OR_EXISTING_DIR)) .option1( "--lib", "<file|jdk-home>",
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/DesugaredMethodsListCommand.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/DesugaredMethodsListCommand.java index 6a00d8d..9744154 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/DesugaredMethodsListCommand.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/DesugaredMethodsListCommand.java
@@ -267,6 +267,7 @@ private static class ParserState { final DesugaredMethodsListCommand.Builder builder; boolean hasDefinedApiLevel = false; + Path outputPath = null; ParserState(DesugaredMethodsListCommand.Builder builder) { this.builder = builder; @@ -277,11 +278,15 @@ var header = "Usage: desugaredmethods [options] where options are:"; var parser = new CliParser<ParserState>(header); return parser - .option1( - "--output", - "<file>", - "Output result in <file>. <file> must be an existing directory or a zip file.", - (state, arg) -> state.builder.setOutputPath(Paths.get(arg))) + .apply( + CliParserUtils.addOutputOption( + state -> state.outputPath != null, + (state, path) -> { + state.outputPath = path; + state.builder.setOutputPath(path); + }, + (state, error) -> state.builder.reporter.error(new StringDiagnostic(error)), + CliParserUtils.OutputOptionType.FILE)) .option1( "--lib", "<file|jdk-home>",
diff --git a/src/main/java/com/android/tools/r8/relocator/RelocatorCommand.java b/src/main/java/com/android/tools/r8/relocator/RelocatorCommand.java index 77d1c31..f00d7d6 100644 --- a/src/main/java/com/android/tools/r8/relocator/RelocatorCommand.java +++ b/src/main/java/com/android/tools/r8/relocator/RelocatorCommand.java
@@ -430,20 +430,12 @@ s.origin)); } }) - .option1( - "--output", - "<file>", - "Output result in <outfile>.", - (s, arg) -> { - if (s.outputPath != null) { - s.builder.error( - new StringDiagnostic( - "Cannot output both to '" + s.outputPath + "' and '" + arg + "'", - s.origin)); - } else { - s.outputPath = Paths.get(arg); - } - }) + .apply( + CliParserUtils.addOutputOption( + s -> s.outputPath != null, + (s, path) -> s.outputPath = path, + (s, error) -> s.builder.error(new StringDiagnostic(error, s.origin)), + CliParserUtils.OutputOptionType.ZIP_OR_EXISTING_DIR)) .option1( "--map", "<from->to>",
diff --git a/src/main/java/com/android/tools/r8/utils/CliParserUtils.java b/src/main/java/com/android/tools/r8/utils/CliParserUtils.java index 869f697..eed8ebf 100644 --- a/src/main/java/com/android/tools/r8/utils/CliParserUtils.java +++ b/src/main/java/com/android/tools/r8/utils/CliParserUtils.java
@@ -22,6 +22,8 @@ import com.android.tools.r8.utils.internal.collections.Pair; import com.android.tools.r8.utils.internal.exceptions.Unreachable; import com.google.common.collect.ImmutableList; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.function.BiConsumer; @@ -329,6 +331,39 @@ }); } + public enum OutputOptionType { + ZIP_OR_EXISTING_DIR( + "<path>", "Output result in <path>. <path> must be a zip file or an existing directory."), + FILE("<file>", "Output result in <file>."); + + private final String paramLabel; + private final String description; + + OutputOptionType(String paramLabel, String description) { + this.paramLabel = paramLabel; + this.description = description; + } + } + + public static <B> Consumer<CliParser<B>> addOutputOption( + Predicate<B> hasSetOutputPathAlready, + BiConsumer<B, Path> action, + BiConsumer<B, String> errorHandler, + OutputOptionType outputOptionType) { + return parser -> + parser.option1( + "--output", + outputOptionType.paramLabel, + outputOptionType.description, + (state, arg) -> { + if (hasSetOutputPathAlready.test(state)) { + errorHandler.accept(state, "Cannot set multiple --output options"); + } else { + action.accept(state, Paths.get(arg)); + } + }); + } + public static <B> Consumer<CliParser<B>> addThreadCountOption( BiConsumer<B, Integer> action, Function<B, ? extends DiagnosticsHandler> getDiagnosticsHandler,
diff --git a/src/test/java/com/android/tools/r8/D8CommandTest.java b/src/test/java/com/android/tools/r8/D8CommandTest.java index f019b19..fdad625 100644 --- a/src/test/java/com/android/tools/r8/D8CommandTest.java +++ b/src/test/java/com/android/tools/r8/D8CommandTest.java
@@ -177,9 +177,9 @@ " and options are:", " --debug # Compile with debugging information (default).", " --release # Compile without debugging information.", - " --output <file> # Output result in <file>. <file> must be an existing" - + " directory or a zip", - " # file.", + " --output <path> # Output result in <path>. <path> must be a zip file or" + + " an existing", + " # directory.", " --globals <file> # Global synthetics <file> from a previous intermediate" + " compilation. The", " # <file> may be either a zip-archive of global"
diff --git a/src/test/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommandParserTest.java b/src/test/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommandParserTest.java index 927ef37..89e087a 100644 --- a/src/test/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommandParserTest.java +++ b/src/test/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommandParserTest.java
@@ -35,7 +35,7 @@ " --min-api <number>[.<number>]", " # Minimum Android API level compatibility (default: 1).", " --lib <file|jdk-home> # Add <file|jdk-home> as a library resource.", - " --output <globals-file> # Output result in <globals-file>.", + " --output <file> # Output result in <file>.", " --classfile # Generate globals for only classfile to classfile" + " desugaring. (By default", " # globals for both classfile and dex desugaring are"
diff --git a/src/test/java/com/android/tools/r8/L8CommandTest.java b/src/test/java/com/android/tools/r8/L8CommandTest.java index a61a4d8..2cd05be 100644 --- a/src/test/java/com/android/tools/r8/L8CommandTest.java +++ b/src/test/java/com/android/tools/r8/L8CommandTest.java
@@ -95,9 +95,9 @@ " and options are:", " --debug # Compile with debugging information (default).", " --release # Compile without debugging information.", - " --output <file> # Output result in <file>. <file> must be an existing" - + " directory or a zip", - " # file.", + " --output <path> # Output result in <path>. <path> must be a zip file or" + + " an existing", + " # directory.", " --lib <file|jdk-home> # Add <file|jdk-home> as a library resource.", " --min-api <number>[.<number>]", " # Minimum Android API level compatibility (default: 1).",
diff --git a/src/test/java/com/android/tools/r8/R8CommandTest.java b/src/test/java/com/android/tools/r8/R8CommandTest.java index 2a6d280..c5648dd 100644 --- a/src/test/java/com/android/tools/r8/R8CommandTest.java +++ b/src/test/java/com/android/tools/r8/R8CommandTest.java
@@ -371,9 +371,9 @@ " --debug # Compile with debugging information.", " --dex # Compile program to DEX file format (default).", " --classfile # Compile program to Java classfile format.", - " --output <file> # Output result in <file>. <file> must be an existing" - + " directory or a zip", - " # file.", + " --output <path> # Output result in <path>. <path> must be a zip file or" + + " an existing", + " # directory.", " --lib <file|jdk-home> # Add <file|jdk-home> as a library resource.", " --classpath <file> # Add <file> as a classpath resource.", " --min-api <number>[.<number>]",
diff --git a/src/test/java/com/android/tools/r8/relocator/RelocatorCommandTest.java b/src/test/java/com/android/tools/r8/relocator/RelocatorCommandTest.java index 56571aa..da2968b 100644 --- a/src/test/java/com/android/tools/r8/relocator/RelocatorCommandTest.java +++ b/src/test/java/com/android/tools/r8/relocator/RelocatorCommandTest.java
@@ -56,7 +56,9 @@ " --input <file> # Input file to remap, class, zip or jar.", " --input-no-res <file> # Input file to remap, zip or jar. Only .class file entries" + " are included.", - " --output <file> # Output result in <outfile>.", + " --output <path> # Output result in <path>. <path> must be a zip file or" + + " an existing", + " # directory.", " --map <from->to> # Registers a mapping.", " --map-diagnostics[:<type>] <from-level> <to-level>", " # Map diagnostics of <type> (default any) reported as" @@ -170,8 +172,7 @@ .build(); }); assertThat( - exception.getCause().getMessage(), - containsString("Cannot output both to 'first_output.zip' and 'another_output.zip'")); + exception.getCause().getMessage(), containsString("Cannot set multiple --output options")); } @Test
diff --git a/src/test/java8/ir/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/DesugaredMethodsListCommandTest.java b/src/test/java8/ir/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/DesugaredMethodsListCommandTest.java index e3ccc98..b250623 100644 --- a/src/test/java8/ir/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/DesugaredMethodsListCommandTest.java +++ b/src/test/java8/ir/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/DesugaredMethodsListCommandTest.java
@@ -40,9 +40,7 @@ assertEquals( StringUtils.lines( "Usage: desugaredmethods [options] where options are:", - " --output <file> # Output result in <file>. <file> must be an existing" - + " directory or a zip", - " # file.", + " --output <file> # Output result in <file>.", " --lib <file|jdk-home> # Add <file|jdk-home> as a library resource.", " --min-api <number>[.<number>]", " # Minimum Android API level compatibility (default: 1).",