diff --git a/src/test/java/com/google/devtools/build/android/AarGeneratorActionTest.java b/src/test/java/com/google/devtools/build/android/AarGeneratorActionTest.java index 99887cb3a0226a..48b5c467b3a8b1 100644 --- a/src/test/java/com/google/devtools/build/android/AarGeneratorActionTest.java +++ b/src/test/java/com/google/devtools/build/android/AarGeneratorActionTest.java @@ -19,12 +19,12 @@ import static org.junit.Assert.assertNotNull; import com.android.builder.core.VariantTypeImpl; +import com.beust.jcommander.JCommander; +import com.beust.jcommander.ParameterException; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.devtools.build.android.AarGeneratorAction.AarGeneratorOptions; import com.google.devtools.build.zip.ZipReader; -import com.google.devtools.common.options.OptionsParser; -import com.google.devtools.common.options.OptionsParsingException; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; @@ -309,7 +309,20 @@ private Set getZipEntryTimestamps(Path zip) throws IOException { } - @Test public void testCheckFlags() throws IOException, OptionsParsingException { + private AarGeneratorOptions parseFlags(String[] args) + throws CompatOptionsParsingException, ParameterException { + AarGeneratorOptions options = new AarGeneratorOptions(); + JCommander jc = new JCommander(options); + String[] preprocessedArgs = AndroidOptionsUtils.runArgFilePreprocessor(jc, args); + String[] normalizedArgs = + AndroidOptionsUtils.normalizeBooleanOptions(options, preprocessedArgs); + jc.parse(normalizedArgs); + return options; + } + + @Test + public void testCheckFlags() + throws CompatOptionsParsingException, IOException, ParameterException { Path manifest = tempDir.resolve("AndroidManifest.xml"); Files.createFile(manifest); Path rtxt = tempDir.resolve("R.txt"); @@ -319,38 +332,33 @@ private Set getZipEntryTimestamps(Path zip) throws IOException { String[] args = new String[] {"--manifest", manifest.toString(), "--rtxt", rtxt.toString(), "--classes", classes.toString()}; - OptionsParser optionsParser = - OptionsParser.builder().optionsClasses(AarGeneratorOptions.class).build(); - optionsParser.parse(args); - AarGeneratorOptions options = optionsParser.getOptions(AarGeneratorOptions.class); + AarGeneratorOptions options = parseFlags(args); AarGeneratorAction.checkFlags(options); } - @Test public void testCheckFlags_MissingClasses() throws IOException, OptionsParsingException { + @Test + public void testCheckFlags_MissingClasses() + throws CompatOptionsParsingException, IOException, ParameterException { Path manifest = tempDir.resolve("AndroidManifest.xml"); Files.createFile(manifest); Path rtxt = tempDir.resolve("R.txt"); Files.createFile(rtxt); String[] args = new String[] {"--manifest", manifest.toString(), "--rtxt", rtxt.toString()}; - OptionsParser optionsParser = - OptionsParser.builder().optionsClasses(AarGeneratorOptions.class).build(); - optionsParser.parse(args); - AarGeneratorOptions options = optionsParser.getOptions(AarGeneratorOptions.class); + AarGeneratorOptions options = parseFlags(args); thrown.expect(IllegalArgumentException.class); thrown.expectMessage("classes must be specified. Building an .aar without" + " classes is unsupported."); AarGeneratorAction.checkFlags(options); } - @Test public void testCheckFlags_MissingMultiple() throws IOException, OptionsParsingException { + @Test + public void testCheckFlags_MissingMultiple() + throws CompatOptionsParsingException, IOException, ParameterException { Path manifest = tempDir.resolve("AndroidManifest.xml"); Files.createFile(manifest); String[] args = new String[] {"--manifest", manifest.toString()}; - OptionsParser optionsParser = - OptionsParser.builder().optionsClasses(AarGeneratorOptions.class).build(); - optionsParser.parse(args); - AarGeneratorOptions options = optionsParser.getOptions(AarGeneratorOptions.class); + AarGeneratorOptions options = parseFlags(args); thrown.expect(IllegalArgumentException.class); thrown.expectMessage("rtxt, classes must be specified. Building an .aar without" + " rtxt, classes is unsupported."); diff --git a/src/test/java/com/google/devtools/build/android/BUILD b/src/test/java/com/google/devtools/build/android/BUILD index f34de2aeecfd18..199c5ef1e9bf74 100644 --- a/src/test/java/com/google/devtools/build/android/BUILD +++ b/src/test/java/com/google/devtools/build/android/BUILD @@ -29,6 +29,7 @@ java_test( "//third_party:guava", "//third_party:junit4", "//third_party:truth", + "//third_party/java/jcommander", ], ) diff --git a/src/tools/android/java/com/google/devtools/build/android/Aapt2OptimizeAction.java b/src/tools/android/java/com/google/devtools/build/android/Aapt2OptimizeAction.java index 1f00a0affe5362..ccc3d65738c971 100644 --- a/src/tools/android/java/com/google/devtools/build/android/Aapt2OptimizeAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/Aapt2OptimizeAction.java @@ -13,12 +13,11 @@ // limitations under the License. package com.google.devtools.build.android; - +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameters; +import com.beust.jcommander.ParametersDelegate; import com.google.common.collect.ImmutableList; import com.google.devtools.build.android.aapt2.Aapt2ConfigOptions; -import com.google.devtools.common.options.OptionsParser; -import com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor; -import java.nio.file.FileSystems; import java.util.List; import java.util.logging.Logger; @@ -33,19 +32,38 @@ public static void main(String... args) throws Exception { logger.fine(CommandHelper.execute("Optimizing resources", buildCommand(args))); } - private static List buildCommand(String... args) { - OptionsParser optionsParser = - OptionsParser.builder() - .optionsClasses(Aapt2ConfigOptions.class, ResourceProcessorCommonOptions.class) - .argsPreProcessor(new ShellQuotedParamsFilePreProcessor(FileSystems.getDefault())) - .allowResidue(true) - .build(); - optionsParser.parseAndExitUponError(args); + @Parameters(separators = "= ") + static class Options extends OptionsBaseWithResidue { + // NOTE: This options class needs the ParametersDelegate feature from JCommander for several + // reasons: + // * There are no Aapt2OptimizeAction-specific options, just fake "inheritance" from + // Aapt2ConfigOptions and ResourceProcessorCommonOptions. + // * The action itself reads the residue from the command line + // In JCommander, residue collection is done at a per-option-class basis, not per OptionsParser, + // as was the case with the Bazel OptionsParser. Simultaneously, only _one_ object in a list of + // Objects passed to JCommander can have residue collection. + // Therefore, the most straightforward option here is to "inherit" the sub-option classes into a + // super Options class, with residue collection enabled for Options. + + @ParametersDelegate public Aapt2ConfigOptions aapt2ConfigOptions = new Aapt2ConfigOptions(); + + @ParametersDelegate + public ResourceProcessorCommonOptions resourceProcessorCommonOptions = + new ResourceProcessorCommonOptions(); + } + + private static List buildCommand(String... args) throws CompatOptionsParsingException { + Options options = new Options(); + JCommander jc = new JCommander(options); + String[] preprocessedArgs = AndroidOptionsUtils.runArgFilePreprocessor(jc, args); + String[] normalizedArgs = + AndroidOptionsUtils.normalizeBooleanOptions(options, preprocessedArgs); + jc.parse(normalizedArgs); return ImmutableList.builder() - .add(optionsParser.getOptions(Aapt2ConfigOptions.class).aapt2.toString()) + .add(options.aapt2ConfigOptions.aapt2.toString()) .add("optimize") - .addAll(optionsParser.getResidue()) + .addAll(options.getResidue()) .build(); } diff --git a/src/tools/android/java/com/google/devtools/build/android/Aapt2ResourcePackagingAction.java b/src/tools/android/java/com/google/devtools/build/android/Aapt2ResourcePackagingAction.java index 99fc285b95cfb2..2883a6f91c30be 100644 --- a/src/tools/android/java/com/google/devtools/build/android/Aapt2ResourcePackagingAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/Aapt2ResourcePackagingAction.java @@ -38,11 +38,8 @@ import com.google.devtools.build.android.aapt2.ResourceCompiler; import com.google.devtools.build.android.aapt2.ResourceLinker; import com.google.devtools.build.android.aapt2.StaticLibrary; -import com.google.devtools.common.options.OptionsParser; -import com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor; import com.google.devtools.common.options.TriState; import java.io.IOException; -import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; @@ -73,7 +70,7 @@ public class Aapt2ResourcePackagingAction { /** Flag specifications for this action. */ @Parameters(separators = "= ") - public static final class Options extends OptionsBaseWithResidue { + public static final class Options { @Parameter( names = "--primaryData", converter = CompatUnvalidatedAndroidDataConverter.class, @@ -229,18 +226,23 @@ public static final class Options extends OptionsBaseWithResidue { @Parameter( names = "--throwOnResourceConflict", + arity = 1, description = "If passed, resource merge conflicts will be treated as errors instead of warnings") public boolean throwOnResourceConflict; - @Parameter(names = "--packageUnderTest", description = "Unused/deprecated option.") + @Parameter(names = "--packageUnderTest", arity = 1, description = "Unused/deprecated option.") public String packageUnderTest; - @Parameter(names = "--isTestWithResources", description = "Unused/deprecated option.") + @Parameter( + names = "--isTestWithResources", + arity = 1, + description = "Unused/deprecated option.") public boolean isTestWithResources; @Parameter( names = "--includeProguardLocationReferences", + arity = 1, description = "When generating proguard configurations, include location references.") public boolean includeProguardLocationReferences; @@ -255,18 +257,15 @@ public static final class Options extends OptionsBaseWithResidue { public static void main(String[] args) throws Exception { Profiler profiler = InMemoryProfiler.createAndStart("setup"); Options options = new Options(); - String[] normalizedArgs = AndroidOptionsUtils.normalizeBooleanOptions(options, args); - JCommander jc = new JCommander(options); + Aapt2ConfigOptions aaptConfigOptions = new Aapt2ConfigOptions(); + ResourceProcessorCommonOptions resourceProcessorCommonOptions = + new ResourceProcessorCommonOptions(); + Object[] allOptions = new Object[] {options, aaptConfigOptions, resourceProcessorCommonOptions}; + JCommander jc = new JCommander(allOptions); + String[] preprocessedArgs = AndroidOptionsUtils.runArgFilePreprocessor(jc, args); + String[] normalizedArgs = + AndroidOptionsUtils.normalizeBooleanOptions(allOptions, preprocessedArgs); jc.parse(normalizedArgs); - List residue = options.getResidue(); - OptionsParser optionsParser = - OptionsParser.builder() - .optionsClasses(Aapt2ConfigOptions.class, ResourceProcessorCommonOptions.class) - .argsPreProcessor(new ShellQuotedParamsFilePreProcessor(FileSystems.getDefault())) - .build(); - optionsParser.parseAndExitUponError(residue.toArray(new String[0])); - - Aapt2ConfigOptions aaptConfigOptions = optionsParser.getOptions(Aapt2ConfigOptions.class); Preconditions.checkArgument( options.packageId == -1 || (options.packageId >= 2 && options.packageId <= 255), @@ -312,8 +311,7 @@ public static void main(String[] args) throws Exception { options.versionName, manifest, processedManifest, - optionsParser.getOptions(ResourceProcessorCommonOptions.class) - .logWarnings)) + resourceProcessorCommonOptions.logWarnings)) .processManifest( manifest -> new DensitySpecificManifestProcessor(options.densities, densityManifest) diff --git a/src/tools/android/java/com/google/devtools/build/android/Aapt2ResourceShrinkingAction.java b/src/tools/android/java/com/google/devtools/build/android/Aapt2ResourceShrinkingAction.java index d3625b434d72ca..71b234806b13eb 100644 --- a/src/tools/android/java/com/google/devtools/build/android/Aapt2ResourceShrinkingAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/Aapt2ResourceShrinkingAction.java @@ -20,12 +20,8 @@ import com.google.devtools.build.android.aapt2.Aapt2ConfigOptions; import com.google.devtools.build.android.aapt2.ResourceLinker; import com.google.devtools.build.android.aapt2.StaticLibrary; -import com.google.devtools.common.options.OptionsParser; -import com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor; -import java.nio.file.FileSystems; import java.nio.file.Files; import java.util.LinkedHashSet; -import java.util.List; import java.util.Set; /** @@ -49,17 +45,15 @@ public static void main(String[] args) throws Exception { final Profiler profiler = LoggingProfiler.createAndStart("shrink").startTask("flags"); // Parse arguments. Options options = new Options(); - JCommander jc = new JCommander(options); - jc.parse(args); - List residue = options.getResidue(); + Aapt2ConfigOptions aapt2ConfigOptions = new Aapt2ConfigOptions(); + Object[] allOptions = + new Object[] {options, aapt2ConfigOptions, new ResourceProcessorCommonOptions()}; + JCommander jc = new JCommander(allOptions); + String[] preprocessedArgs = AndroidOptionsUtils.runArgFilePreprocessor(jc, args); + String[] normalizedArgs = + AndroidOptionsUtils.normalizeBooleanOptions(allOptions, preprocessedArgs); + jc.parse(normalizedArgs); - OptionsParser optionsParser = - OptionsParser.builder() - .optionsClasses(Aapt2ConfigOptions.class, ResourceProcessorCommonOptions.class) - .argsPreProcessor(new ShellQuotedParamsFilePreProcessor(FileSystems.getDefault())) - .build(); - optionsParser.parseAndExitUponError(residue.toArray(new String[0])); - Aapt2ConfigOptions aapt2ConfigOptions = optionsParser.getOptions(Aapt2ConfigOptions.class); profiler.recordEndOf("flags").startTask("setup"); try (ScopedTemporaryDirectory scopedTmp = diff --git a/src/tools/android/java/com/google/devtools/build/android/AarGeneratorAction.java b/src/tools/android/java/com/google/devtools/build/android/AarGeneratorAction.java index 35f0a0cc4a1e55..90da43a90ae2db 100644 --- a/src/tools/android/java/com/google/devtools/build/android/AarGeneratorAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/AarGeneratorAction.java @@ -16,6 +16,9 @@ import static java.nio.charset.StandardCharsets.UTF_8; import com.android.builder.core.VariantTypeImpl; +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.base.Stopwatch; @@ -23,19 +26,12 @@ import com.google.common.collect.Ordering; import com.google.devtools.build.android.AndroidDataMerger.MergeConflictException; import com.google.devtools.build.android.AndroidResourceMerger.MergingException; -import com.google.devtools.build.android.Converters.ExistingPathConverter; -import com.google.devtools.build.android.Converters.PathConverter; -import com.google.devtools.build.android.Converters.UnvalidatedAndroidDataConverter; -import com.google.devtools.common.options.Option; -import com.google.devtools.common.options.OptionDocumentationCategory; -import com.google.devtools.common.options.OptionEffectTag; -import com.google.devtools.common.options.OptionsBase; -import com.google.devtools.common.options.OptionsParser; -import com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor; +import com.google.devtools.build.android.Converters.CompatExistingPathConverter; +import com.google.devtools.build.android.Converters.CompatPathConverter; +import com.google.devtools.build.android.Converters.CompatUnvalidatedAndroidDataConverter; import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; -import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; @@ -77,96 +73,65 @@ public class AarGeneratorAction { private static final Logger logger = Logger.getLogger(AarGeneratorAction.class.getName()); /** Flag specifications for this action. */ - public static final class AarGeneratorOptions extends OptionsBase { - @Option( - name = "mainData", - defaultValue = "null", - converter = UnvalidatedAndroidDataConverter.class, - category = "input", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = - "The directory containing the primary resource directory." - + "The contents will override the contents of any other resource directories during " - + "merging. The expected format is resources[#resources]:assets[#assets]:manifest" - ) + @Parameters(separators = "= ") + public static final class AarGeneratorOptions { + @Parameter( + names = "--mainData", + converter = CompatUnvalidatedAndroidDataConverter.class, + description = + "The directory containing the primary resource directory.The contents will override the" + + " contents of any other resource directories during merging. The expected format" + + " is resources[#resources]:assets[#assets]:manifest") public UnvalidatedAndroidData mainData; - @Option( - name = "manifest", - defaultValue = "null", - converter = ExistingPathConverter.class, - category = "input", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Path to AndroidManifest.xml." - ) + @Parameter( + names = "--manifest", + converter = CompatExistingPathConverter.class, + description = "Path to AndroidManifest.xml.") public Path manifest; - @Option( - name = "rtxt", - defaultValue = "null", - converter = ExistingPathConverter.class, - category = "input", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Path to R.txt." - ) + @Parameter( + names = "--rtxt", + converter = CompatExistingPathConverter.class, + description = "Path to R.txt.") public Path rtxt; - @Option( - name = "classes", - defaultValue = "null", - converter = ExistingPathConverter.class, - category = "input", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Path to classes.jar." - ) + @Parameter( + names = "--classes", + converter = CompatExistingPathConverter.class, + description = "Path to classes.jar.") public Path classes; - @Option( - name = "proguardSpec", - defaultValue = "null", - converter = ExistingPathConverter.class, - allowMultiple = true, - category = "input", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Path to proguard spec file.") - public List proguardSpecs; + @Parameter( + names = "--proguardSpec", + converter = CompatExistingPathConverter.class, + description = "Path to proguard spec file.") + public List proguardSpecs = ImmutableList.of(); - @Option( - name = "aarOutput", - defaultValue = "null", - converter = PathConverter.class, - category = "output", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Path to write the archive." - ) + @Parameter( + names = "--aarOutput", + converter = CompatPathConverter.class, + description = "Path to write the archive.") public Path aarOutput; - @Option( - name = "throwOnResourceConflict", - defaultValue = "false", - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "If passed, resource merge conflicts will be treated as errors instead of warnings" - ) + @Parameter( + names = "--throwOnResourceConflict", + arity = 1, + description = + "If passed, resource merge conflicts will be treated as errors instead of warnings") public boolean throwOnResourceConflict; } - public static void main(String[] args) throws IOException { + public static void main(String[] args) throws CompatOptionsParsingException, IOException { Stopwatch timer = Stopwatch.createStarted(); - OptionsParser optionsParser = - OptionsParser.builder() - .optionsClasses(AarGeneratorOptions.class, ResourceProcessorCommonOptions.class) - .argsPreProcessor(new ShellQuotedParamsFilePreProcessor(FileSystems.getDefault())) - .build(); - optionsParser.parseAndExitUponError(args); - AarGeneratorOptions options = optionsParser.getOptions(AarGeneratorOptions.class); + AarGeneratorOptions options = new AarGeneratorOptions(); + Object[] allOptions = new Object[] {options, new ResourceProcessorCommonOptions()}; + JCommander jc = new JCommander(allOptions); + String[] preprocessedArgs = AndroidOptionsUtils.runArgFilePreprocessor(jc, args); + + String[] normalizedArgs = + AndroidOptionsUtils.normalizeBooleanOptions(allOptions, preprocessedArgs); + jc.parse(normalizedArgs); checkFlags(options); diff --git a/src/tools/android/java/com/google/devtools/build/android/AbstractBusyBoxAction.java b/src/tools/android/java/com/google/devtools/build/android/AbstractBusyBoxAction.java index dc05273d12032d..ae4df91f839142 100644 --- a/src/tools/android/java/com/google/devtools/build/android/AbstractBusyBoxAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/AbstractBusyBoxAction.java @@ -13,10 +13,10 @@ // limitations under the License. package com.google.devtools.build.android; +import com.beust.jcommander.JCommander; +import com.beust.jcommander.ParameterException; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Stopwatch; -import com.google.devtools.common.options.OptionsBase; -import com.google.devtools.common.options.OptionsParser; import com.google.devtools.common.options.OptionsParsingException; import java.nio.file.Path; import java.util.logging.Level; @@ -24,19 +24,19 @@ /** Abstract base class containing helper methods and error handling for BusyBox actions. */ public abstract class AbstractBusyBoxAction { - private final OptionsParser optionsParser; + private final JCommander jc; private final String description; private final Stopwatch timer = Stopwatch.createUnstarted(); - AbstractBusyBoxAction(OptionsParser optionsParser, String description) { - this.optionsParser = optionsParser; + AbstractBusyBoxAction(JCommander jc, String description) { + this.jc = jc; this.description = description; } public void invoke(String[] args) throws Exception { try { invokeWithoutExit(args); - } catch (UserException | OptionsParsingException e) { + } catch (UserException | OptionsParsingException | ParameterException e) { getLogger().severe(e.getMessage()); // In Bazel, users tend to assume that a stack trace indicates a bug in underlying Bazel code // and ignore the content of the exception. If we know that the exception was actually their @@ -52,7 +52,10 @@ public void invoke(String[] args) throws Exception { @VisibleForTesting void invokeWithoutExit(String[] args) throws Exception { timer.start(); - optionsParser.parse(args); + String[] preprocessedArgs = AndroidOptionsUtils.runArgFilePreprocessor(this.jc, args); + String[] normalizedArgs = + AndroidOptionsUtils.normalizeBooleanOptions(jc.getObjects(), preprocessedArgs); + this.jc.parse(normalizedArgs); try (ScopedTemporaryDirectory scopedTmp = new ScopedTemporaryDirectory(description + "_tmp"); ExecutorServiceCloser executorService = ExecutorServiceCloser.createWithFixedPoolOf(15)) { @@ -66,8 +69,14 @@ void invokeWithoutExit(String[] args) throws Exception { abstract Logger getLogger(); - T getOptions(Class clazz) { - return optionsParser.getOptions(clazz); + T getOptions(Class clazz) { + for (Object o : jc.getObjects()) { + if (o.getClass().equals(clazz)) { + return clazz.cast(o); + } + } + + return null; } /** diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidAssetMergingAction.java b/src/tools/android/java/com/google/devtools/build/android/AndroidAssetMergingAction.java index 0704f57a97df21..4c14c2a1e4f007 100644 --- a/src/tools/android/java/com/google/devtools/build/android/AndroidAssetMergingAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/AndroidAssetMergingAction.java @@ -13,19 +13,16 @@ // limitations under the License. package com.google.devtools.build.android; +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; import com.google.devtools.build.android.AndroidDataMerger.ContentComparingChecker; -import com.google.devtools.build.android.Converters.PathConverter; -import com.google.devtools.build.android.Converters.SerializedAndroidDataConverter; -import com.google.devtools.build.android.Converters.SerializedAndroidDataListConverter; -import com.google.devtools.common.options.Option; -import com.google.devtools.common.options.OptionDocumentationCategory; -import com.google.devtools.common.options.OptionEffectTag; -import com.google.devtools.common.options.OptionsBase; -import com.google.devtools.common.options.OptionsParser; -import com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor; -import java.nio.file.FileSystems; +import com.google.devtools.build.android.Converters.AmpersandSplitter; +import com.google.devtools.build.android.Converters.CompatPathConverter; +import com.google.devtools.build.android.Converters.CompatSerializedAndroidDataConverter; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; @@ -45,84 +42,61 @@ static void testingMain(String... args) throws Exception { } private static AndroidAssetMergingAction create() { - OptionsParser optionsParser = - OptionsParser.builder() - .optionsClasses(Options.class, ResourceProcessorCommonOptions.class) - .argsPreProcessor(new ShellQuotedParamsFilePreProcessor(FileSystems.getDefault())) - .build(); - return new AndroidAssetMergingAction(optionsParser); + Options options = new Options(); + JCommander jc = new JCommander(options); + return new AndroidAssetMergingAction(jc); } - private AndroidAssetMergingAction(OptionsParser optionsParser) { - super(optionsParser, "Merge assets"); + private AndroidAssetMergingAction(JCommander jc) { + super(jc, "Merge assets"); } /** Flag specifications for this action. */ - public static final class Options extends OptionsBase { - - @Option( - name = "primaryData", - defaultValue = "null", - converter = SerializedAndroidDataConverter.class, - category = "input", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = - "The assets of the current target. The expected format is " - + SerializedAndroidData.EXPECTED_FORMAT - ) + @Parameters(separators = "= ") + public static final class Options { + + @Parameter( + names = "--primaryData", + converter = CompatSerializedAndroidDataConverter.class, + description = + "The assets of the current target. The expected format is " + + SerializedAndroidData.EXPECTED_FORMAT) public SerializedAndroidData primary; - @Option( - name = "directData", - defaultValue = "", - converter = SerializedAndroidDataListConverter.class, - category = "input", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = - "Direct asset dependencies. These values will be used if not defined in the " - + "primary assets. The expected format is " - + SerializedAndroidData.EXPECTED_FORMAT - + "[&...]" - ) - public List directData; - - @Option( - name = "data", - defaultValue = "", - converter = SerializedAndroidDataListConverter.class, - category = "input", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = - "Transitive Data dependencies. These values will be used if not defined in the " - + "primary assets. The expected format is " - + SerializedAndroidData.EXPECTED_FORMAT - + "[&...]" - ) - public List transitiveData; - - @Option( - name = "assetsOutput", - defaultValue = "null", - converter = PathConverter.class, - category = "output", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Path to the write merged asset archive." - ) + @Parameter( + names = "--directData", + converter = CompatSerializedAndroidDataConverter.class, + splitter = AmpersandSplitter.class, + description = + "Direct asset dependencies. These values will be used if not defined in the " + + "primary assets. The expected format is " + + SerializedAndroidData.EXPECTED_FORMAT + + "[&...]") + public List directData = ImmutableList.of(); + + @Parameter( + names = "--data", + converter = CompatSerializedAndroidDataConverter.class, + splitter = AmpersandSplitter.class, + description = + "Transitive Data dependencies. These values will be used if not defined in the " + + "primary assets. The expected format is " + + SerializedAndroidData.EXPECTED_FORMAT + + "[&...]") + public List transitiveData = ImmutableList.of(); + + @Parameter( + names = "--assetsOutput", + converter = CompatPathConverter.class, + description = "Path to the write merged asset archive.") public Path assetsOutput; - @Option( - name = "throwOnAssetConflict", - defaultValue = "true", - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "If passed, asset merge conflicts will be treated as errors instead of warnings" - ) - public boolean throwOnAssetConflict; + @Parameter( + names = "--throwOnAssetConflict", + arity = 1, + description = + "If passed, asset merge conflicts will be treated as errors instead of warnings") + public boolean throwOnAssetConflict = true; } @Override diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidCompiledResourceMergingAction.java b/src/tools/android/java/com/google/devtools/build/android/AndroidCompiledResourceMergingAction.java index 3df2642b4eec22..da6c4359b13dcd 100644 --- a/src/tools/android/java/com/google/devtools/build/android/AndroidCompiledResourceMergingAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/AndroidCompiledResourceMergingAction.java @@ -15,23 +15,20 @@ import com.android.builder.core.DefaultManifestParser; import com.android.utils.StdLogger; +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; import com.google.common.base.Preconditions; import com.google.common.base.Stopwatch; import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; import com.google.devtools.build.android.AndroidDataMerger.MergeConflictException; import com.google.devtools.build.android.AndroidResourceMerger.MergingException; import com.google.devtools.build.android.AndroidResourceProcessor.AaptConfigOptions; -import com.google.devtools.build.android.Converters.ExistingPathConverter; -import com.google.devtools.build.android.Converters.PathConverter; -import com.google.devtools.build.android.Converters.SerializedAndroidDataConverter; -import com.google.devtools.build.android.Converters.SerializedAndroidDataListConverter; -import com.google.devtools.common.options.Option; -import com.google.devtools.common.options.OptionDocumentationCategory; -import com.google.devtools.common.options.OptionEffectTag; -import com.google.devtools.common.options.OptionsBase; -import com.google.devtools.common.options.OptionsParser; -import com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor; -import java.nio.file.FileSystems; +import com.google.devtools.build.android.Converters.AmpersandSplitter; +import com.google.devtools.build.android.Converters.CompatExistingPathConverter; +import com.google.devtools.build.android.Converters.CompatPathConverter; +import com.google.devtools.build.android.Converters.CompatSerializedAndroidDataConverter; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; @@ -54,148 +51,108 @@ public class AndroidCompiledResourceMergingAction { Logger.getLogger(AndroidCompiledResourceMergingAction.class.getName()); /** Flag specifications for this action. */ - public static class Options extends OptionsBase { - @Option( - name = "primaryData", - defaultValue = "null", - converter = SerializedAndroidDataConverter.class, - category = "input", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = + @Parameters(separators = "= ") + public static class Options { + @Parameter( + names = "--primaryData", + converter = CompatSerializedAndroidDataConverter.class, + description = "The directory containing the primary resource directory. The contents will override" + " the contents of any other resource directories during merging." + " The expected format is " + SerializedAndroidData.EXPECTED_FORMAT) public SerializedAndroidData primaryData; - @Option( - name = "primaryManifest", - defaultValue = "null", - converter = ExistingPathConverter.class, - category = "input", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Path to primary resource's manifest file.") + @Parameter( + names = "--primaryManifest", + converter = CompatExistingPathConverter.class, + description = "Path to primary resource's manifest file.") public Path primaryManifest; - @Option( - name = "data", - defaultValue = "", - converter = SerializedAndroidDataListConverter.class, - category = "input", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = + @Parameter( + names = "--data", + converter = CompatSerializedAndroidDataConverter.class, + splitter = AmpersandSplitter.class, + description = "Transitive Data dependencies. These values will be used if not defined in the " + "primary resources. The expected format is " + SerializedAndroidData.EXPECTED_FORMAT + "[&...]") - public List transitiveData; + public List transitiveData = ImmutableList.of(); - @Option( - name = "directData", - defaultValue = "", - converter = SerializedAndroidDataListConverter.class, - category = "input", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = + @Parameter( + names = "--directData", + converter = CompatSerializedAndroidDataConverter.class, + splitter = AmpersandSplitter.class, + description = "Direct Data dependencies. These values will be used if not defined in the " + "primary resources. The expected format is " + SerializedAndroidData.EXPECTED_FORMAT + "[&...]") - public List directData; + public List directData = ImmutableList.of(); - @Option( - name = "classJarOutput", - defaultValue = "null", - converter = PathConverter.class, - category = "output", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Path for the generated java class jar.") + @Parameter( + names = "--classJarOutput", + converter = CompatPathConverter.class, + description = "Path for the generated java class jar.") public Path classJarOutput; - @Option( - name = "manifestOutput", - defaultValue = "null", - converter = PathConverter.class, - category = "output", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Path for the output processed AndroidManifest.xml.") + @Parameter( + names = "--manifestOutput", + converter = CompatPathConverter.class, + description = "Path for the output processed AndroidManifest.xml.") public Path manifestOutput; - @Option( - name = "packageForR", - defaultValue = "null", - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Custom java package to generate the R symbols files.") + @Parameter( + names = "--packageForR", + description = "Custom java package to generate the R symbols files.") public String packageForR; - @Option( - name = "throwOnResourceConflict", - defaultValue = "false", - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "If passed, resource merge conflicts will be treated as errors instead of warnings") + @Parameter( + names = "--throwOnResourceConflict", + arity = 1, + description = + "If passed, resource merge conflicts will be treated as errors instead of warnings") public boolean throwOnResourceConflict; - @Option( - name = "targetLabel", - defaultValue = "null", - category = "input", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "A label to add to the output jar's manifest as 'Target-Label'") + @Parameter( + names = "--targetLabel", + description = "A label to add to the output jar's manifest as 'Target-Label'") public String targetLabel; - @Option( - name = "injectingRuleKind", - defaultValue = "null", - category = "input", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "A string to add to the output jar's manifest as 'Injecting-Rule-Kind'") + @Parameter( + names = "--injectingRuleKind", + description = "A string to add to the output jar's manifest as 'Injecting-Rule-Kind'") public String injectingRuleKind; - @Option( - name = "annotate_r_fields_from_transitive_deps", - defaultValue = "false", - documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = + @Parameter( + names = "--annotate_r_fields_from_transitive_deps", + arity = 1, + description = "If enabled, annotates R with 'targetLabel' and transitive fields with their" + " respective labels.") public boolean annotateTransitiveFields; - @Option( - name = "rTxtOut", - defaultValue = "null", - converter = PathConverter.class, - category = "output", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = + @Parameter( + names = "--rTxtOut", + converter = CompatPathConverter.class, + description = "Path to where an R.txt file declaring potentially-used resources should be written.") public Path rTxtOut; } public static void main(String[] args) throws Exception { final Stopwatch timer = Stopwatch.createStarted(); - OptionsParser optionsParser = - OptionsParser.builder() - .optionsClasses( - Options.class, AaptConfigOptions.class, ResourceProcessorCommonOptions.class) - .argsPreProcessor(new ShellQuotedParamsFilePreProcessor(FileSystems.getDefault())) - .build(); - optionsParser.parseAndExitUponError(args); - AaptConfigOptions aaptConfigOptions = optionsParser.getOptions(AaptConfigOptions.class); - Options options = optionsParser.getOptions(Options.class); + Options options = new Options(); + AaptConfigOptions aaptConfigOptions = new AaptConfigOptions(); + ResourceProcessorCommonOptions resourceProcessorCommonOptions = + new ResourceProcessorCommonOptions(); + Object[] allOptions = new Object[] {options, aaptConfigOptions, resourceProcessorCommonOptions}; + JCommander jc = new JCommander(allOptions); + String[] preprocessedArgs = AndroidOptionsUtils.runArgFilePreprocessor(jc, args); + String[] normalizedArgs = + AndroidOptionsUtils.normalizeBooleanOptions(allOptions, preprocessedArgs); + jc.parse(normalizedArgs); Preconditions.checkNotNull(options.primaryData); Preconditions.checkNotNull(options.primaryManifest); @@ -257,7 +214,7 @@ public static void main(String[] args) throws Exception { options.packageForR, options.primaryManifest, processedManifest, - optionsParser.getOptions(ResourceProcessorCommonOptions.class).logWarnings); + resourceProcessorCommonOptions.logWarnings); Files.createDirectories(options.manifestOutput.getParent()); Files.copy(processedManifest, options.manifestOutput); diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidDataBindingProcessingAction.java b/src/tools/android/java/com/google/devtools/build/android/AndroidDataBindingProcessingAction.java index d4b5e817134bac..7ba78c91a0b4d8 100644 --- a/src/tools/android/java/com/google/devtools/build/android/AndroidDataBindingProcessingAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/AndroidDataBindingProcessingAction.java @@ -14,17 +14,14 @@ package com.google.devtools.build.android; import com.android.builder.core.VariantTypeImpl; +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; +import com.google.common.collect.ImmutableList; import com.google.devtools.build.android.AndroidResourceProcessor.AaptConfigOptions; -import com.google.devtools.build.android.Converters.PathConverter; -import com.google.devtools.build.android.Converters.VariantTypeConverter; -import com.google.devtools.common.options.Option; -import com.google.devtools.common.options.OptionDocumentationCategory; -import com.google.devtools.common.options.OptionEffectTag; -import com.google.devtools.common.options.OptionsBase; -import com.google.devtools.common.options.OptionsParser; -import com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor; +import com.google.devtools.build.android.Converters.CompatPathConverter; +import com.google.devtools.build.android.Converters.CompatVariantTypeConverter; import java.io.IOException; -import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.Collections; @@ -40,76 +37,55 @@ public class AndroidDataBindingProcessingAction { /** Flag specifications for this action. */ - public static final class Options extends OptionsBase { - - @Option( - name = "resource_root", - defaultValue = "null", - converter = PathConverter.class, - allowMultiple = true, - category = "input", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Input resource root. A corresponding output resource root must be passed to " - + "--output_resource_root. Multiple roots will be paired in the order they're passed.") - public List resourceRoots; - - @Option( - name = "output_resource_directory", - defaultValue = "null", - converter = PathConverter.class, - category = "input", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = + @Parameters(separators = "= ") + public static final class Options extends OptionsBaseWithResidue { + + @Parameter( + names = "--resource_root", + converter = CompatPathConverter.class, + description = + "Input resource root. A corresponding output resource root must be passed to" + + " --output_resource_root. Multiple roots will be paired in the order they're" + + " passed.") + public List resourceRoots = ImmutableList.of(); + + @Parameter( + names = "--output_resource_directory", + converter = CompatPathConverter.class, + description = "The output resource directory. Input source roots will be appended to this to " + "create the output resource roots.") public Path outputResourceDirectory; - @Option( - name = "packageType", - defaultValue = "BASE_APK", - converter = VariantTypeConverter.class, - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = + @Parameter( + names = "--packageType", + converter = CompatVariantTypeConverter.class, + description = "Variant configuration type for packaging the resources." + " Acceptable values BASE_APK, LIBRARY, ANDROID_TEST, UNIT_TEST") - public VariantTypeImpl packageType; - - @Option( - name = "dataBindingInfoOut", - defaultValue = "null", - converter = PathConverter.class, - category = "output", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Path to where data binding's layout info output should be written.") + public VariantTypeImpl packageType = VariantTypeImpl.BASE_APK; + + @Parameter( + names = "--dataBindingInfoOut", + converter = CompatPathConverter.class, + description = "Path to where data binding's layout info output should be written.") public Path dataBindingInfoOut; - @Option( - name = "appId", - defaultValue = "null", - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "The java package for the app.") + @Parameter(names = "--appId", description = "The java package for the app.") public String appId; } - public static void main(String[] args) throws IOException { - - OptionsParser optionsParser = - OptionsParser.builder() - .allowResidue(true) - .optionsClasses( - Options.class, AaptConfigOptions.class, ResourceProcessorCommonOptions.class) - .argsPreProcessor(new ShellQuotedParamsFilePreProcessor(FileSystems.getDefault())) - .build(); - optionsParser.parseAndExitUponError(args); - Options options = optionsParser.getOptions(Options.class); - AaptConfigOptions aaptConfigOptions = optionsParser.getOptions(AaptConfigOptions.class); + public static void main(String[] args) throws CompatOptionsParsingException, IOException { + Options options = new Options(); + AaptConfigOptions aaptConfigOptions = new AaptConfigOptions(); + ResourceProcessorCommonOptions resourceProcessorCommonOptions = + new ResourceProcessorCommonOptions(); + Object[] allOptions = new Object[] {options, aaptConfigOptions, resourceProcessorCommonOptions}; + JCommander jc = new JCommander(allOptions); + String[] preprocessedArgs = AndroidOptionsUtils.runArgFilePreprocessor(jc, args); + String[] normalizedArgs = + AndroidOptionsUtils.normalizeBooleanOptions(allOptions, preprocessedArgs); + jc.parse(normalizedArgs); if (options.dataBindingInfoOut == null) { throw new IllegalArgumentException("--dataBindingInfoOut is required"); diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidOptionsUtils.java b/src/tools/android/java/com/google/devtools/build/android/AndroidOptionsUtils.java index 3feba7f949507d..252279dda361c8 100644 --- a/src/tools/android/java/com/google/devtools/build/android/AndroidOptionsUtils.java +++ b/src/tools/android/java/com/google/devtools/build/android/AndroidOptionsUtils.java @@ -13,10 +13,15 @@ // limitations under the License. package com.google.devtools.build.android; +import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; import java.lang.annotation.Annotation; import java.lang.reflect.Field; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @@ -25,6 +30,34 @@ public class AndroidOptionsUtils { private AndroidOptionsUtils() {} + /** Run the CompatShellQuotedParamsFilePreProcessor on a list of args. */ + public static String[] runArgFilePreprocessor(JCommander jc, String[] argsAsArray) + throws CompatOptionsParsingException { + List args = ImmutableList.copyOf(argsAsArray); + jc.setExpandAtSign(false); + if (args.size() == 1 && args.get(0).startsWith("@")) { + // Use CompatShellQuotedParamsFilePreProcessor to handle the arg file. + FileSystem fs = FileSystems.getDefault(); + Path argFile = fs.getPath(args.get(0).substring(1)); + CompatShellQuotedParamsFilePreProcessor paramsFilePreProcessor = + new CompatShellQuotedParamsFilePreProcessor(fs); + args = paramsFilePreProcessor.preProcess(ImmutableList.of("@" + argFile)); + } + return args.toArray(new String[0]); + } + + /** + * Same as AndroidOptionsUtils#normalizeBooleanOptions, but accepts an array of option classes + * instead. + */ + public static String[] normalizeBooleanOptions(Object[] options, String[] args) { + String[] normalizedArgs = args; + for (Object optionsObject : options) { + normalizedArgs = normalizeBooleanOptions(optionsObject, normalizedArgs); + } + return normalizedArgs; + } + /** * Normalize boolean options to use --=true or --=false syntax. * diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceParsingAction.java b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceParsingAction.java index c0459c4a5696f4..02d8af82f8b331 100644 --- a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceParsingAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceParsingAction.java @@ -13,18 +13,14 @@ // limitations under the License. package com.google.devtools.build.android; +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; import com.google.common.base.Preconditions; import com.google.common.base.Stopwatch; import com.google.common.collect.ImmutableList; -import com.google.devtools.build.android.Converters.PathConverter; -import com.google.devtools.build.android.Converters.UnvalidatedAndroidDirectoriesConverter; -import com.google.devtools.common.options.Option; -import com.google.devtools.common.options.OptionDocumentationCategory; -import com.google.devtools.common.options.OptionEffectTag; -import com.google.devtools.common.options.OptionsBase; -import com.google.devtools.common.options.OptionsParser; -import com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor; -import java.nio.file.FileSystems; +import com.google.devtools.build.android.Converters.CompatPathConverter; +import com.google.devtools.build.android.Converters.CompatUnvalidatedAndroidDirectoriesConverter; import java.nio.file.Path; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; @@ -40,43 +36,35 @@ public class AndroidResourceParsingAction { Logger.getLogger(AndroidResourceParsingAction.class.getName()); /** Flag specifications for this action. */ - public static final class Options extends OptionsBase { + @Parameters(separators = "= ") + public static final class Options { - @Option( - name = "primaryData", - defaultValue = "null", - converter = UnvalidatedAndroidDirectoriesConverter.class, - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - category = "input", - help = - "The resource and asset directories to parse and summarize in a symbols file." - + " The expected format is " - + UnvalidatedAndroidDirectories.EXPECTED_FORMAT - ) + @Parameter( + names = "--primaryData", + converter = CompatUnvalidatedAndroidDirectoriesConverter.class, + description = + "The resource and asset directories to parse and summarize in a symbols file." + + " The expected format is " + + UnvalidatedAndroidDirectories.EXPECTED_FORMAT) public UnvalidatedAndroidDirectories primaryData; - @Option( - name = "output", - defaultValue = "null", - converter = PathConverter.class, - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - category = "output", - help = "Path to write the output protobuf." - ) + @Parameter( + names = "--output", + converter = CompatPathConverter.class, + description = "Path to write the output protobuf.") public Path output; - } public static void main(String[] args) throws Exception { - OptionsParser optionsParser = - OptionsParser.builder() - .optionsClasses(Options.class, ResourceProcessorCommonOptions.class) - .argsPreProcessor(new ShellQuotedParamsFilePreProcessor(FileSystems.getDefault())) - .build(); - optionsParser.parseAndExitUponError(args); - Options options = optionsParser.getOptions(Options.class); + Options options = new Options(); + ResourceProcessorCommonOptions resourceProcessorCommonOptions = + new ResourceProcessorCommonOptions(); + Object[] allOptions = new Object[] {options, resourceProcessorCommonOptions}; + JCommander jc = new JCommander(allOptions); + String[] preprocessedArgs = AndroidOptionsUtils.runArgFilePreprocessor(jc, args); + String[] normalizedArgs = + AndroidOptionsUtils.normalizeBooleanOptions(options, preprocessedArgs); + jc.parse(normalizedArgs); Preconditions.checkNotNull(options.primaryData); Preconditions.checkNotNull(options.output); diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java index f51537f88f89fa..d3e0da06c15ec8 100644 --- a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java +++ b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java @@ -23,23 +23,21 @@ import com.android.repository.Revision; import com.android.utils.ILogger; import com.android.utils.StdLogger; +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; import com.google.common.base.Joiner; import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Multimap; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; -import com.google.devtools.build.android.Converters.ExistingPathConverter; -import com.google.devtools.build.android.Converters.RevisionConverter; +import com.google.devtools.build.android.Converters.CompatExistingPathConverter; +import com.google.devtools.build.android.Converters.CompatRevisionConverter; import com.google.devtools.build.android.junctions.JunctionCreator; import com.google.devtools.build.android.junctions.NoopJunctionCreator; import com.google.devtools.build.android.junctions.WindowsJunctionCreator; import com.google.devtools.build.android.resources.ResourceSymbols; -import com.google.devtools.common.options.Converters.CommaSeparatedOptionListConverter; -import com.google.devtools.common.options.Option; -import com.google.devtools.common.options.OptionDocumentationCategory; -import com.google.devtools.common.options.OptionEffectTag; -import com.google.devtools.common.options.OptionsBase; import com.google.devtools.common.options.TriState; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.io.Closeable; @@ -60,87 +58,53 @@ public class AndroidResourceProcessor { static final Logger logger = Logger.getLogger(AndroidResourceProcessor.class.getName()); /** Options class containing flags for Aapt setup. */ - public static final class AaptConfigOptions extends OptionsBase { - @Option( - name = "buildToolsVersion", - defaultValue = "null", - converter = RevisionConverter.class, - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Version of the build tools (e.g. aapt) being used, e.g. 23.0.2") + @Parameters(separators = "= ") + public static final class AaptConfigOptions { + @Parameter( + names = "--buildToolsVersion", + converter = CompatRevisionConverter.class, + description = "Version of the build tools (e.g. aapt) being used, e.g. 23.0.2") public Revision buildToolsVersion; - @Option( - name = "aapt", - defaultValue = "null", - converter = ExistingPathConverter.class, - category = "tool", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Aapt tool location for resource packaging.") + @Parameter( + names = "--aapt", + converter = CompatExistingPathConverter.class, + description = "Aapt tool location for resource packaging.") public Path aapt; - @Option( - name = "androidJar", - defaultValue = "null", - converter = ExistingPathConverter.class, - category = "tool", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Path to the android jar for resource packaging and building apks.") + @Parameter( + names = "--androidJar", + converter = CompatExistingPathConverter.class, + description = "Path to the android jar for resource packaging and building apks.") public Path androidJar; - @Option( - name = "useAaptCruncher", - defaultValue = "auto", - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = + @Parameter( + names = "--useAaptCruncher", + description = "Use the legacy aapt cruncher, defaults to true for non-LIBRARY packageTypes. LIBRARY" + " packages do not benefit from the additional processing as the resources will" + " need to be reprocessed during the generation of the final apk. See" + " https://code.google.com/p/android/issues/detail?id=67525 for a discussion of" + " the different png crunching methods.") - public TriState useAaptCruncher; - - @Option( - name = "uncompressedExtensions", - defaultValue = "", - converter = CommaSeparatedOptionListConverter.class, - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "A list of file extensions not to compress.") - public List uncompressedExtensions; - - @Option( - name = "debug", - defaultValue = "false", - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Indicates if it is a debug build.") + public TriState useAaptCruncher = TriState.AUTO; + + @Parameter( + names = "--uncompressedExtensions", + description = "A list of file extensions not to compress.") + public List uncompressedExtensions = ImmutableList.of(); + + @Parameter(names = "--debug", arity = 1, description = "Indicates if it is a debug build.") public boolean debug; - @Option( - name = "resourceConfigs", - defaultValue = "", - converter = CommaSeparatedOptionListConverter.class, - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "A list of resource config filters to pass to aapt.") - public List resourceConfigs; - - @Option( - name = "useDataBindingAndroidX", - defaultValue = "false", - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Indicates whether databinding generated files should depend on AndroidX.") + @Parameter( + names = "--resourceConfigs", + description = "A list of resource config filters to pass to aapt.") + public List resourceConfigs = ImmutableList.of(); + + @Parameter( + names = "--useDataBindingAndroidX", + arity = 1, + description = "Indicates whether databinding generated files should depend on AndroidX.") public boolean useDataBindingAndroidX; } diff --git a/src/tools/android/java/com/google/devtools/build/android/CompileLibraryResourcesAction.java b/src/tools/android/java/com/google/devtools/build/android/CompileLibraryResourcesAction.java index ca7d31748f5de7..d2a94e6d6e871e 100644 --- a/src/tools/android/java/com/google/devtools/build/android/CompileLibraryResourcesAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/CompileLibraryResourcesAction.java @@ -23,13 +23,9 @@ import com.google.devtools.build.android.Converters.CompatUnvalidatedAndroidDirectoriesConverter; import com.google.devtools.build.android.aapt2.Aapt2ConfigOptions; import com.google.devtools.build.android.aapt2.ResourceCompiler; -import com.google.devtools.common.options.OptionsParser; -import com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor; import java.io.IOException; -import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; -import java.util.List; import java.util.concurrent.ExecutionException; import java.util.logging.Logger; @@ -37,7 +33,7 @@ @Parameters(separators = "= ") public class CompileLibraryResourcesAction { /** Flag specifications for this action. */ - public static final class Options extends OptionsBaseWithResidue { + public static final class Options { @Parameter( names = "--resources", @@ -79,17 +75,13 @@ public static final class Options extends OptionsBaseWithResidue { public static void main(String[] args) throws Exception { Options options = new Options(); - JCommander jc = new JCommander(options); - jc.parse(args); - List residue = options.getResidue(); - OptionsParser optionsParser = - OptionsParser.builder() - .optionsClasses(Aapt2ConfigOptions.class, ResourceProcessorCommonOptions.class) - .argsPreProcessor(new ShellQuotedParamsFilePreProcessor(FileSystems.getDefault())) - .build(); - optionsParser.parseAndExitUponError(residue.toArray(new String[0])); - - Aapt2ConfigOptions aapt2Options = optionsParser.getOptions(Aapt2ConfigOptions.class); + Aapt2ConfigOptions aapt2Options = new Aapt2ConfigOptions(); + Object[] allOptions = {options, aapt2Options, new ResourceProcessorCommonOptions()}; + JCommander jc = new JCommander(allOptions); + String[] preprocessedArgs = AndroidOptionsUtils.runArgFilePreprocessor(jc, args); + String[] normalizedArgs = + AndroidOptionsUtils.normalizeBooleanOptions(allOptions, preprocessedArgs); + jc.parse(normalizedArgs); Preconditions.checkNotNull(options.resources); Preconditions.checkNotNull(options.output); diff --git a/src/tools/android/java/com/google/devtools/build/android/ConvertResourceZipToApkAction.java b/src/tools/android/java/com/google/devtools/build/android/ConvertResourceZipToApkAction.java index c31cb57db74eb0..2b68e5ce89bd08 100644 --- a/src/tools/android/java/com/google/devtools/build/android/ConvertResourceZipToApkAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/ConvertResourceZipToApkAction.java @@ -24,13 +24,9 @@ import com.google.devtools.build.android.aapt2.ProtoApk; import com.google.devtools.build.android.aapt2.ResourceLinker; import com.google.devtools.build.android.aapt2.StaticLibrary; -import com.google.devtools.common.options.OptionsParser; -import com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor; -import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import java.util.List; /** * An action that will take a ResourcesZip and convert it into a proto APK. @@ -50,16 +46,15 @@ public static void main(String[] args) throws Exception { LoggingProfiler.createAndStart("convert_proto_apk").startTask("flags"); // Parse arguments. Options options = new Options(); - JCommander jc = new JCommander(options); - jc.parse(args); - List residue = options.getResidue(); - OptionsParser optionsParser = - OptionsParser.builder() - .optionsClasses(Aapt2ConfigOptions.class, ResourceProcessorCommonOptions.class) - .argsPreProcessor(new ShellQuotedParamsFilePreProcessor(FileSystems.getDefault())) - .build(); - optionsParser.parseAndExitUponError(residue.toArray(new String[0])); - Aapt2ConfigOptions aapt2ConfigOptions = optionsParser.getOptions(Aapt2ConfigOptions.class); + Aapt2ConfigOptions aapt2ConfigOptions = new Aapt2ConfigOptions(); + Object[] allOptions = + new Object[] {options, aapt2ConfigOptions, new ResourceProcessorCommonOptions()}; + JCommander jc = new JCommander(allOptions); + String[] preprocessedArgs = AndroidOptionsUtils.runArgFilePreprocessor(jc, args); + String[] normalizedArgs = + AndroidOptionsUtils.normalizeBooleanOptions(allOptions, preprocessedArgs); + jc.parse(normalizedArgs); + Preconditions.checkArgument(options.resourcesZip != null, "Missing input resource zip."); profiler.recordEndOf("flags").startTask("setup"); try (ScopedTemporaryDirectory scopedTmp = @@ -88,7 +83,7 @@ public static void main(String[] args) throws Exception { /** Extra options specific to {@link ConvertResourceZipToApkAction}. */ @Parameters(separators = "= ") - public static class Options extends OptionsBaseWithResidue { + public static class Options { @Parameter( names = "--resources", converter = CompatExistingPathConverter.class, diff --git a/src/tools/android/java/com/google/devtools/build/android/Converters.java b/src/tools/android/java/com/google/devtools/build/android/Converters.java index cb8469ac57148e..bf26fc28103186 100644 --- a/src/tools/android/java/com/google/devtools/build/android/Converters.java +++ b/src/tools/android/java/com/google/devtools/build/android/Converters.java @@ -251,6 +251,9 @@ public String getTypeDescription() { public static class AmpersandSplitter implements IParameterSplitter { @Override public List split(String value) { + if (value.isEmpty()) { + return ImmutableList.of(); + } return ImmutableList.copyOf(value.split("&")); } } @@ -259,6 +262,9 @@ public List split(String value) { public static class ColonSplitter implements IParameterSplitter { @Override public List split(String value) { + if (value.isEmpty()) { + return ImmutableList.of(); + } return ImmutableList.copyOf(value.split(":")); } } @@ -271,6 +277,9 @@ public List split(String value) { public static class NoOpSplitter implements IParameterSplitter { @Override public List split(String value) { + if (value.isEmpty()) { + return ImmutableList.of(); + } return ImmutableList.of(value); } } @@ -313,6 +322,22 @@ public String getTypeDescription() { } } + /** + * Converter for {@link Revision}. Relies on {@code Revision#parseRevision(String)} to perform + * conversion and validation. Compatible with JCommander. + */ + public static class CompatRevisionConverter implements IStringConverter { + + @Override + public Revision convert(String input) throws ParameterException { + try { + return Revision.parseRevision(input); + } catch (NumberFormatException e) { + throw new ParameterException(e.getMessage()); + } + } + } + /** * Converter for {@link Revision}. Relies on {@code Revision#parseRevision(String)} to perform * conversion and validation. @@ -414,6 +439,18 @@ public ExistingPathConverter() { } } + /** Converter for {@link VariantType}. Compatible with JCommander. */ + public static class CompatVariantTypeConverter implements IStringConverter { + @Override + public VariantTypeImpl convert(String input) throws ParameterException { + try { + return VariantTypeImpl.valueOf(input); + } catch (IllegalArgumentException e) { + throw new ParameterException(String.format("invalid VariantType: %s", e.getMessage()), e); + } + } + } + /** Converter for {@link VariantType}. */ public static class VariantTypeConverter extends EnumConverter { public VariantTypeConverter() { diff --git a/src/tools/android/java/com/google/devtools/build/android/GenerateDatabindingBaseClassesAction.java b/src/tools/android/java/com/google/devtools/build/android/GenerateDatabindingBaseClassesAction.java index 3955a9946b3eab..a6122efb2267fc 100644 --- a/src/tools/android/java/com/google/devtools/build/android/GenerateDatabindingBaseClassesAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/GenerateDatabindingBaseClassesAction.java @@ -15,17 +15,13 @@ package com.google.devtools.build.android; import android.databinding.AndroidDataBinding; +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; import com.google.common.collect.ImmutableList; import com.google.common.collect.Streams; import com.google.devtools.build.android.AndroidResourceProcessor.AaptConfigOptions; -import com.google.devtools.build.android.Converters.PathConverter; -import com.google.devtools.common.options.Option; -import com.google.devtools.common.options.OptionDocumentationCategory; -import com.google.devtools.common.options.OptionEffectTag; -import com.google.devtools.common.options.OptionsBase; -import com.google.devtools.common.options.OptionsParser; -import com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor; -import java.nio.file.FileSystems; +import com.google.devtools.build.android.Converters.CompatPathConverter; import java.nio.file.Path; import java.util.List; import java.util.logging.Level; @@ -35,70 +31,49 @@ public final class GenerateDatabindingBaseClassesAction { /** Options for GenerateDatabindingBaseClassesAction. */ - public static final class Options extends OptionsBase { - @Option( - name = "layoutInfoFiles", - defaultValue = "null", - converter = PathConverter.class, - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Path to layout-info.zip file produced by databinding processor") + @Parameters(separators = "= ") + public static final class Options extends OptionsBaseWithResidue { + @Parameter( + names = "--layoutInfoFiles", + converter = CompatPathConverter.class, + description = "Path to layout-info.zip file produced by databinding processor") public Path layoutInfoFile; - @Option( - name = "package", - defaultValue = "null", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Package name of the android target") + @Parameter(names = "--package", description = "Package name of the android target") public String packageName; - @Option( - name = "classInfoOut", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - defaultValue = "null", - converter = PathConverter.class, - category = "output", - help = "Path to write classInfo.zip file") + @Parameter( + names = "--classInfoOut", + converter = CompatPathConverter.class, + description = "Path to write classInfo.zip file") public Path classInfoOut; - @Option( - name = "sourceOut", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - defaultValue = "null", - converter = PathConverter.class, - category = "output", - help = "Path to write databinding base classes to be used in Java compilation") + @Parameter( + names = "--sourceOut", + converter = CompatPathConverter.class, + description = "Path to write databinding base classes to be used in Java compilation") public Path sourceOut; - @Option( - name = "dependencyClassInfoList", - defaultValue = "null", - converter = PathConverter.class, - allowMultiple = true, - category = "input", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "List of dependency class info zip files") - public List dependencyClassInfoList; + @Parameter( + names = "--dependencyClassInfoList", + converter = CompatPathConverter.class, + description = "List of dependency class info zip files") + public List dependencyClassInfoList = ImmutableList.of(); } static final Logger logger = Logger.getLogger(GenerateDatabindingBaseClassesAction.class.getName()); public static void main(String[] args) throws Exception { - final OptionsParser optionsParser = - OptionsParser.builder() - .allowResidue(true) - .optionsClasses( - Options.class, AaptConfigOptions.class, ResourceProcessorCommonOptions.class) - .argsPreProcessor(new ShellQuotedParamsFilePreProcessor(FileSystems.getDefault())) - .build(); - optionsParser.parseAndExitUponError(args); - final Options options = optionsParser.getOptions(Options.class); - final AaptConfigOptions aaptConfigOptions = optionsParser.getOptions(AaptConfigOptions.class); + Options options = new Options(); + AaptConfigOptions aaptConfigOptions = new AaptConfigOptions(); + Object[] allOptions = + new Object[] {options, aaptConfigOptions, new ResourceProcessorCommonOptions()}; + JCommander jc = new JCommander(allOptions); + String[] preprocessedArgs = AndroidOptionsUtils.runArgFilePreprocessor(jc, args); + String[] normalizedArgs = + AndroidOptionsUtils.normalizeBooleanOptions(allOptions, preprocessedArgs); + jc.parse(normalizedArgs); if (options.layoutInfoFile == null) { throw new IllegalArgumentException("--layoutInfoFiles is required"); diff --git a/src/tools/android/java/com/google/devtools/build/android/ManifestMergerAction.java b/src/tools/android/java/com/google/devtools/build/android/ManifestMergerAction.java index a1d80a74ba8bdc..77a9014966b10d 100644 --- a/src/tools/android/java/com/google/devtools/build/android/ManifestMergerAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/ManifestMergerAction.java @@ -19,19 +19,16 @@ import com.android.utils.StdLogger; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.android.Converters.CompatExistingPathConverter; import com.google.devtools.build.android.Converters.CompatExistingPathStringDictionaryConverter; import com.google.devtools.build.android.Converters.CompatPathConverter; import com.google.devtools.build.android.Converters.CompatStringDictionaryConverter; -import com.google.devtools.common.options.OptionsParser; -import com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor; import java.io.IOException; -import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import java.util.List; import java.util.Map; import java.util.logging.Logger; import javax.xml.parsers.DocumentBuilder; @@ -65,9 +62,8 @@ */ public class ManifestMergerAction { /** Flag specifications for this action. */ - public static final class Options extends OptionsBaseWithResidue { - // TODO(b/351006636): Remove residue after migrating ResourceProcessorCommonOptions to - // JCommander, since residue was not originally used in this action. + @Parameters(separators = "= ") + public static final class Options { @Parameter( names = "--manifest", converter = CompatExistingPathConverter.class, @@ -81,10 +77,10 @@ public static final class Options extends OptionsBaseWithResidue { converter = CompatExistingPathStringDictionaryConverter.class, description = "A dictionary of manifests, and originating target, to be merged into manifest.") - public Map mergeeManifests; + public Map mergeeManifests = ImmutableMap.of(); @Parameter(names = "--mergeType", description = "The type of merging to perform.") - public MergeType mergeType; + public MergeType mergeType = MergeType.APPLICATION; @Parameter( names = "--manifestValues", @@ -99,7 +95,7 @@ public static final class Options extends OptionsBaseWithResidue { + " The expected format of this string is: key:value[,key:value]*. The keys and" + " values may contain colons and commas as long as they are escaped with a" + " backslash.") - public Map manifestValues; + public Map manifestValues = ImmutableMap.of(); @Parameter( names = "--customPackage", @@ -120,19 +116,9 @@ public static final class Options extends OptionsBaseWithResidue { @Parameter( names = "--mergeManifestPermissions", + arity = 1, description = "If enabled, manifest permissions will be merged.") public boolean mergeManifestPermissions; - - public Options() { - this.manifest = null; - this.mergeeManifests = ImmutableMap.of(); - this.mergeType = MergeType.APPLICATION; - this.manifestValues = ImmutableMap.of(); - this.customPackage = null; - this.manifestOutput = null; - this.log = null; - this.mergeManifestPermissions = false; - } } private static final String[] PERMISSION_TAGS = @@ -166,16 +152,14 @@ public static void main(String[] args) throws Exception { // First parse the local Action flags using JCommander, then parse the remaining common flags // using OptionsParser. Options options = new Options(); - JCommander jc = new JCommander(options); - jc.parse(args); - List residue = options.getResidue(); - - OptionsParser optionsParser = - OptionsParser.builder() - .optionsClasses(ResourceProcessorCommonOptions.class) - .argsPreProcessor(new ShellQuotedParamsFilePreProcessor(FileSystems.getDefault())) - .build(); - optionsParser.parseAndExitUponError(residue.toArray(new String[0])); + ResourceProcessorCommonOptions resourceProcessorCommonOptions = + new ResourceProcessorCommonOptions(); + Object[] allOptions = new Object[] {options, resourceProcessorCommonOptions}; + JCommander jc = new JCommander(allOptions); + String[] preprocessedArgs = AndroidOptionsUtils.runArgFilePreprocessor(jc, args); + String[] normalizedArgs = + AndroidOptionsUtils.normalizeBooleanOptions(allOptions, preprocessedArgs); + jc.parse(normalizedArgs); try { Path mergedManifest; @@ -212,7 +196,7 @@ public static void main(String[] args) throws Exception { options.customPackage, options.manifestOutput, options.log, - optionsParser.getOptions(ResourceProcessorCommonOptions.class).logWarnings); + resourceProcessorCommonOptions.logWarnings); // Bazel expects a log file output as a result of manifest merging, even if it is a no-op. if (options.log != null && !options.log.toFile().exists()) { options.log.toFile().createNewFile(); diff --git a/src/tools/android/java/com/google/devtools/build/android/RClassGeneratorAction.java b/src/tools/android/java/com/google/devtools/build/android/RClassGeneratorAction.java index e47338f0a1bbd1..0d0550e58fdd98 100644 --- a/src/tools/android/java/com/google/devtools/build/android/RClassGeneratorAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/RClassGeneratorAction.java @@ -28,9 +28,6 @@ import com.google.devtools.build.android.Converters.NoOpSplitter; import com.google.devtools.build.android.resources.RPackageId; import com.google.devtools.build.android.resources.ResourceSymbols; -import com.google.devtools.common.options.OptionsParser; -import com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor; -import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; @@ -61,7 +58,7 @@ public class RClassGeneratorAction { /** Flag specifications for this action. */ @Parameters(separators = "= ") - public static final class Options extends OptionsBaseWithResidue { + public static final class Options { @Parameter( names = "--primaryRTxt", @@ -125,17 +122,12 @@ public static final class Options extends OptionsBaseWithResidue { public static void main(String[] args) throws Exception { final Stopwatch timer = Stopwatch.createStarted(); Options options = new Options(); - String[] normalizedArgs = AndroidOptionsUtils.normalizeBooleanOptions(options, args); - JCommander jc = new JCommander(options); + JCommander jc = new JCommander(new Object[] {options, new ResourceProcessorCommonOptions()}); + String[] preprocessedArgs = AndroidOptionsUtils.runArgFilePreprocessor(jc, args); + String[] normalizedArgs = + AndroidOptionsUtils.normalizeBooleanOptions(options, preprocessedArgs); jc.parse(normalizedArgs); - List residue = options.getResidue(); - - OptionsParser optionsParser = - OptionsParser.builder() - .optionsClasses(ResourceProcessorCommonOptions.class) - .argsPreProcessor(new ShellQuotedParamsFilePreProcessor(FileSystems.getDefault())) - .build(); - optionsParser.parseAndExitUponError(residue.toArray(new String[0])); + Preconditions.checkNotNull(options.classJarOutput); final AndroidResourceProcessor resourceProcessor = new AndroidResourceProcessor(STD_LOGGER); try (ScopedTemporaryDirectory scopedTmp = diff --git a/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorCommonOptions.java b/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorCommonOptions.java index 84d0d2c412b370..869e223304665a 100644 --- a/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorCommonOptions.java +++ b/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorCommonOptions.java @@ -13,20 +13,13 @@ // limitations under the License. package com.google.devtools.build.android; -import com.google.devtools.common.options.Option; -import com.google.devtools.common.options.OptionDocumentationCategory; -import com.google.devtools.common.options.OptionEffectTag; -import com.google.devtools.common.options.OptionsBase; +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; /** Common options shared between tools of ResourceProcessorBusyBox */ -public class ResourceProcessorCommonOptions extends OptionsBase { +@Parameters(separators = "= ") +public class ResourceProcessorCommonOptions { - @Option( - name = "logWarnings", - defaultValue = "true", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - converter = com.google.devtools.common.options.Converters.BooleanConverter.class, - help = "") - public boolean logWarnings; + @Parameter(names = "--logWarnings", arity = 1, description = "") + public boolean logWarnings = true; } diff --git a/src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction.java b/src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction.java index ebf85c84999a08..73f8faeffb2050 100644 --- a/src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction.java @@ -29,12 +29,9 @@ import com.google.devtools.build.android.AndroidResourceProcessor.AaptConfigOptions; import com.google.devtools.build.android.Converters.CompatExistingPathConverter; import com.google.devtools.build.android.Converters.CompatPathConverter; -import com.google.devtools.common.options.OptionsParser; -import com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -73,7 +70,7 @@ public class ResourceShrinkerAction { /** Flag specifications for this action. */ @Parameters(separators = "= ") - public static final class Options extends OptionsBaseWithResidue { + public static class Options { @Parameter( names = "--shrunkJar", converter = CompatExistingPathConverter.class, @@ -174,18 +171,15 @@ public static void main(String[] args) throws Exception { final Stopwatch timer = Stopwatch.createStarted(); // Parse arguments. Options options = new Options(); - JCommander jc = new JCommander(options); - jc.parse(args); - - List residue = options.getResidue(); - - OptionsParser optionsParser = - OptionsParser.builder() - .optionsClasses(AaptConfigOptions.class) - .argsPreProcessor(new ShellQuotedParamsFilePreProcessor(FileSystems.getDefault())) - .build(); - optionsParser.parseAndExitUponError(residue.toArray(new String[0])); - AaptConfigOptions aaptConfigOptions = optionsParser.getOptions(AaptConfigOptions.class); + AaptConfigOptions aaptConfigOptions = new AaptConfigOptions(); + ResourceProcessorCommonOptions resourceProcessorCommonOptions = + new ResourceProcessorCommonOptions(); + Object[] allOptions = new Object[] {options, resourceProcessorCommonOptions, aaptConfigOptions}; + JCommander jc = new JCommander(allOptions); + String[] preprocessedArgs = AndroidOptionsUtils.runArgFilePreprocessor(jc, args); + String[] normalizedArgs = + AndroidOptionsUtils.normalizeBooleanOptions(allOptions, preprocessedArgs); + jc.parse(normalizedArgs); AndroidResourceProcessor resourceProcessor = new AndroidResourceProcessor(stdLogger); // Setup temporary working directories. diff --git a/src/tools/android/java/com/google/devtools/build/android/ValidateAndLinkResourcesAction.java b/src/tools/android/java/com/google/devtools/build/android/ValidateAndLinkResourcesAction.java index 562b8017d1c39a..feb452513c296f 100644 --- a/src/tools/android/java/com/google/devtools/build/android/ValidateAndLinkResourcesAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/ValidateAndLinkResourcesAction.java @@ -31,9 +31,6 @@ import com.google.devtools.build.android.aapt2.StaticLibrary; import com.google.devtools.build.android.resources.Visibility; import com.google.devtools.build.android.xml.ProtoXmlUtils; -import com.google.devtools.common.options.OptionsParser; -import com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor; -import java.nio.file.FileSystems; import java.nio.file.Path; import java.util.List; import java.util.Map; @@ -44,7 +41,7 @@ public final class ValidateAndLinkResourcesAction { /** Action configuration options. */ - public static class Options extends OptionsBaseWithResidue { + public static class Options { /** * TODO(b/64570523): Still used by blaze. Will be removed as part of the command line cleanup. * @@ -124,16 +121,15 @@ public static class Options extends OptionsBaseWithResidue { public static void main(String[] args) throws Exception { Options options = new Options(); - JCommander jc = new JCommander(options); - jc.parse(args); - OptionsParser optionsParser = - OptionsParser.builder() - .optionsClasses(Aapt2ConfigOptions.class, ResourceProcessorCommonOptions.class) - .argsPreProcessor(new ShellQuotedParamsFilePreProcessor(FileSystems.getDefault())) - .build(); - optionsParser.parse(options.getResidue()); + Aapt2ConfigOptions aapt2Options = new Aapt2ConfigOptions(); + Object[] allOptions = + new Object[] {options, aapt2Options, new ResourceProcessorCommonOptions()}; + JCommander jc = new JCommander(allOptions); + String[] preprocessedArgs = AndroidOptionsUtils.runArgFilePreprocessor(jc, args); + String[] normalizedArgs = + AndroidOptionsUtils.normalizeBooleanOptions(allOptions, preprocessedArgs); + jc.parse(normalizedArgs); - final Aapt2ConfigOptions aapt2Options = optionsParser.getOptions(Aapt2ConfigOptions.class); final Profiler profiler = LoggingProfiler.createAndStart("manifest"); try (ScopedTemporaryDirectory scopedTmp = diff --git a/src/tools/android/java/com/google/devtools/build/android/aapt2/Aapt2ConfigOptions.java b/src/tools/android/java/com/google/devtools/build/android/aapt2/Aapt2ConfigOptions.java index e82a522f3e0bae..e20b0b3a21164a 100644 --- a/src/tools/android/java/com/google/devtools/build/android/aapt2/Aapt2ConfigOptions.java +++ b/src/tools/android/java/com/google/devtools/build/android/aapt2/Aapt2ConfigOptions.java @@ -1,4 +1,3 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,113 +15,71 @@ package com.google.devtools.build.android.aapt2; import com.android.repository.Revision; -import com.google.devtools.build.android.Converters.ExistingPathConverter; -import com.google.devtools.build.android.Converters.RevisionConverter; -import com.google.devtools.common.options.Converters.CommaSeparatedOptionListConverter; -import com.google.devtools.common.options.Option; -import com.google.devtools.common.options.OptionDocumentationCategory; -import com.google.devtools.common.options.OptionEffectTag; -import com.google.devtools.common.options.OptionsBase; +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; +import com.google.common.collect.ImmutableList; +import com.google.devtools.build.android.Converters.CompatExistingPathConverter; +import com.google.devtools.build.android.Converters.CompatRevisionConverter; import com.google.devtools.common.options.TriState; import java.nio.file.Path; import java.util.List; /** Aapt2 specific configuration options. */ -public class Aapt2ConfigOptions extends OptionsBase { - @Option( - name = "aapt2", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - defaultValue = "null", - converter = ExistingPathConverter.class, - category = "tool", - help = "Aapt2 tool location for resource compilation.") +@Parameters(separators = "= ") +public class Aapt2ConfigOptions { + @Parameter( + names = "--aapt2", + converter = CompatExistingPathConverter.class, + description = "Aapt2 tool location for resource compilation.") public Path aapt2; - @Option( - name = "buildToolsVersion", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - defaultValue = "null", - converter = RevisionConverter.class, - category = "config", - help = "Version of the build tools (e.g. aapt) being used, e.g. 23.0.2") + @Parameter( + names = "--buildToolsVersion", + converter = CompatRevisionConverter.class, + description = "Version of the build tools (e.g. aapt) being used, e.g. 23.0.2") public Revision buildToolsVersion; - @Option( - name = "androidJar", - defaultValue = "null", - converter = ExistingPathConverter.class, - category = "tool", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Path to the android jar for resource packaging and building apks.") + @Parameter( + names = "--androidJar", + converter = CompatExistingPathConverter.class, + description = "Path to the android jar for resource packaging and building apks.") public Path androidJar; - @Option( - name = "useAaptCruncher", - defaultValue = "auto", - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = + @Parameter( + names = "--useAaptCruncher", + description = "Use the legacy aapt cruncher, defaults to true for non-LIBRARY packageTypes. " + " LIBRARY packages do not benefit from the additional processing as the resources" + " will need to be reprocessed during the generation of the final apk. See" + " https://code.google.com/p/android/issues/detail?id=67525 for a discussion of the" + " different png crunching methods.") - public TriState useAaptCruncher; - - @Option( - name = "conditionalKeepRules", - defaultValue = "auto", - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Have AAPT2 produce conditional keep rules.") - public TriState conditionalKeepRules; - - @Option( - name = "uncompressedExtensions", - defaultValue = "", - converter = CommaSeparatedOptionListConverter.class, - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "A list of file extensions not to compress.") - public List uncompressedExtensions; - - @Option( - name = "debug", - defaultValue = "false", - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Indicates if it is a debug build.") + public TriState useAaptCruncher = TriState.AUTO; + + @Parameter( + names = "--conditionalKeepRules", + description = "Have AAPT2 produce conditional keep rules.") + public TriState conditionalKeepRules = TriState.AUTO; + + @Parameter( + names = "--uncompressedExtensions", + description = "A list of file extensions not to compress.") + public List uncompressedExtensions = ImmutableList.of(); + + @Parameter(names = "--debug", description = "Indicates if it is a debug build.", arity = 1) public boolean debug; - @Option( - name = "resourceConfigs", - defaultValue = "", - converter = CommaSeparatedOptionListConverter.class, - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "A list of resource config filters to pass to aapt.") - public List resourceConfigs; + @Parameter( + names = "--resourceConfigs", + description = "A list of resource config filters to pass to aapt.") + public List resourceConfigs = ImmutableList.of(); private static final String ANDROID_SPLIT_DOCUMENTATION_URL = "https://developer.android.com/guide/topics/resources/providing-resources.html" + "#QualifierRules"; - @Option( - name = "split", - defaultValue = "null", - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - allowMultiple = true, - help = + @Parameter( + names = "--split", + description = "An individual split configuration to pass to aapt." + " Each split is a list of configuration filters separated by commas." + " Configuration filters are lists of configuration qualifiers separated by dashes," @@ -134,43 +91,30 @@ public class Aapt2ConfigOptions extends OptionsBase { + " Each split flag will produce an additional output file, named by replacing the" + " commas in the split specification with underscores, and appending the result to" + " the output package name following an underscore.") - public List splits; + public List splits = ImmutableList.of(); // TODO(b/136572475, b/112848607): remove this option - @Option( - name = "useCompiledResourcesForMerge", - defaultValue = "true", - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Use compiled resources for merging rather than parsed symbols binary.", - deprecationWarning = "cannot be disabled") - public boolean useCompiledResourcesForMerge; - - @Option( - name = "resourceTableAsProto", - defaultValue = "false", - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Generate the resource table as a protocol buffer.") + @Parameter( + names = "--useCompiledResourcesForMerge", + arity = 1, + description = "Use compiled resources for merging rather than parsed symbols binary.") + public boolean useCompiledResourcesForMerge = true; + + @Parameter( + names = "--resourceTableAsProto", + arity = 1, + description = "Generate the resource table as a protocol buffer.") public boolean resourceTableAsProto; - @Option( - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - name = "generatePseudoLocale", - defaultValue = "true", - category = "config", - help = "Whether to generate pseudo locales during compilation.") - public boolean generatePseudoLocale; - - @Option( - name = "useDataBindingAndroidX", - defaultValue = "false", - category = "config", - documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, - effectTags = {OptionEffectTag.UNKNOWN}, - help = "Indicates whether databinding generated files should depend on AndroidX.") + @Parameter( + names = "--generatePseudoLocale", + arity = 1, + description = "Whether to generate pseudo locales during compilation.") + public boolean generatePseudoLocale = true; + + @Parameter( + names = "--useDataBindingAndroidX", + arity = 1, + description = "Indicates whether databinding generated files should depend on AndroidX.") public boolean useDataBindingAndroidX; }