From bcfc71fcdb4cd9047d57c4761c67db2cb3aa90b6 Mon Sep 17 00:00:00 2001 From: "arun.sampathkumar" Date: Mon, 8 Aug 2022 04:18:44 +0800 Subject: [PATCH] Implement worker support for `GenerateDataBindingBaseClasses` --- WORKSPACE | 12 +- .../databinding/DataBindingV2Context.java | 56 +++---- .../GenerateDatabindingBaseClassesAction.java | 138 ++++++++++++++++++ .../android/ResourceProcessorBusyBox.java | 6 + 4 files changed, 174 insertions(+), 38 deletions(-) create mode 100644 src/tools/android/java/com/google/devtools/build/android/GenerateDatabindingBaseClassesAction.java diff --git a/WORKSPACE b/WORKSPACE index c7ff55cbc5340b..ba1440035b692a 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -75,8 +75,16 @@ list_source_repository(name = "local_bazel_source_list") # 2. Set the $ANDROID_HOME and $ANDROID_NDK_HOME environment variables # 3. Uncomment the two lines below # -# android_sdk_repository(name = "androidsdk") -# android_ndk_repository(name = "androidndk") +android_sdk_repository( + name = "androidsdk", + api_level = 32, + build_tools_version = "32.0.0", +) + +android_ndk_repository( + name = "androidndk", + api_level = 30, +) # In order to run //src/test/shell/bazel:maven_skylark_test, follow the # instructions above for the Android integration tests and uncomment the diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingV2Context.java b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingV2Context.java index 3f464ce5bfeef2..aa71b094032d40 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingV2Context.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/databinding/DataBindingV2Context.java @@ -22,13 +22,9 @@ import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.analysis.FilesToRunProvider; import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.VectorArg; -import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.packages.BuildType; @@ -37,6 +33,7 @@ import com.google.devtools.build.lib.rules.android.AndroidDataBindingProcessorBuilder; import com.google.devtools.build.lib.rules.android.AndroidDataContext; import com.google.devtools.build.lib.rules.android.AndroidResources; +import com.google.devtools.build.lib.rules.android.BusyBoxActionBuilder; import com.google.devtools.build.lib.rules.java.JavaPluginInfo; import com.google.devtools.build.lib.starlarkbuildapi.android.DataBindingV2ProviderApi; import com.google.devtools.build.lib.starlarkbuildapi.android.DataBindingV2ProviderApi.LabelJavaPackagePair; @@ -289,44 +286,31 @@ public ImmutableList getAnnotationSourceFiles(RuleContext ruleContext) } private ImmutableList createBaseClasses(RuleContext ruleContext) { - if (!AndroidResources.definesAndroidResources(ruleContext.attributes())) { return ImmutableList.of(); // no resource, no base classes or class info } - Artifact layoutInfo = getLayoutInfoFile(); - Artifact classInfoFile = getClassInfoFile(ruleContext); - Artifact srcOutFile = + final Artifact layoutInfo = getLayoutInfoFile(); + final Artifact classInfoFile = getClassInfoFile(ruleContext); + final Artifact srcOutFile = DataBinding.getDataBindingArtifact( ruleContext, "baseClassSrc.srcjar", /* isDirectory= */ false); - - FilesToRunProvider exec = - ruleContext.getExecutablePrerequisite(DataBinding.DATABINDING_EXEC_PROCESSOR_ATTR); - - CustomCommandLine.Builder commandLineBuilder = - CustomCommandLine.builder() - .add("GEN_BASE_CLASSES") - .addExecPath("-layoutInfoFiles", layoutInfo) - .add("-package", AndroidCommon.getJavaPackage(ruleContext)) - .addExecPath("-classInfoOut", classInfoFile) - .addExecPath("-sourceOut", srcOutFile) - .add("-zipSourceOutput", "true") - .add("-useAndroidX", useAndroidX ? "true" : "false"); - - NestedSet dependencyClassInfo = getDirectClassInfo(ruleContext); - commandLineBuilder.addExecPaths( - VectorArg.addBefore("-dependencyClassInfoList").each(dependencyClassInfo)); - - ruleContext.registerAction( - new SpawnAction.Builder() - .setExecutable(exec) - .setMnemonic("GenerateDataBindingBaseClasses") - .addInput(layoutInfo) - .addTransitiveInputs(dependencyClassInfo) - .addOutput(classInfoFile) - .addOutput(srcOutFile) - .addCommandLine(commandLineBuilder.build()) - .build(ruleContext)); + final NestedSet dependencyClassInfo = getDirectClassInfo(ruleContext); + + final BusyBoxActionBuilder builder = + BusyBoxActionBuilder.create(AndroidDataContext.forNative(ruleContext), "GEN_BASE_CLASSES") + .addInput("--layoutInfoFiles", layoutInfo) + .addFlag("--package", AndroidCommon.getJavaPackage(ruleContext)) + .addOutput("--classInfoOut", classInfoFile) + .addOutput("--sourceOut", srcOutFile) + .addFlag("--useDataBindingAndroidX", useAndroidX ? "true" : "false"); + + dependencyClassInfo + .toList() + .forEach(classInfo -> builder.addInput("--dependencyClassInfoList", classInfo)); + + builder.buildAndRegister( + "Generating databinding base classes", "GenerateDataBindingBaseClasses"); return ImmutableList.of(srcOutFile); } 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 new file mode 100644 index 00000000000000..146c4fcadd9743 --- /dev/null +++ b/src/tools/android/java/com/google/devtools/build/android/GenerateDatabindingBaseClassesAction.java @@ -0,0 +1,138 @@ +package com.google.devtools.build.android; + +import android.databinding.AndroidDataBinding; + +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 java.nio.file.Path; +import java.util.Collections; +import java.util.List; +import java.util.logging.Logger; + +public class 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") + public Path layoutInfoFile; + + @Option( + name = "package", + defaultValue = "null", + documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, + effectTags = {OptionEffectTag.UNKNOWN}, + help = "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") + 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") + 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; + } + + 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); + + if (options.layoutInfoFile == null) { + throw new IllegalArgumentException("--layoutInfoFiles is required"); + } + + if (options.packageName == null) { + throw new IllegalArgumentException("--packageName is required"); + } + + if (options.classInfoOut == null) { + throw new IllegalArgumentException("--classInfoOut is required"); + } + + if (options.sourceOut == null) { + throw new IllegalArgumentException("--sourceOut is required"); + } + + final List dependencyClassInfoList = + options.dependencyClassInfoList == null + ? Collections.emptyList() + : options.dependencyClassInfoList; + + final ImmutableList.Builder dbArgsBuilder = + ImmutableList.builder() + .add("GEN_BASE_CLASSES") + .add("-layoutInfoFiles") + .add(options.layoutInfoFile.toString()) + .add("-package", options.packageName) + .add("-classInfoOut") + .add(options.classInfoOut.toString()) + .add("-sourceOut") + .add(options.sourceOut.toString()) + .add("-zipSourceOutput") + .add("true") + .add("-useAndroidX") + .add(Boolean.toString(aaptConfigOptions.useDataBindingAndroidX)); + + dependencyClassInfoList.forEach( + classInfo -> dbArgsBuilder.add("-dependencyClassInfoList").add(classInfo.toString())); + + try { + AndroidDataBinding.main( + Streams.mapWithIndex( + dbArgsBuilder.build().stream(), (arg, index) -> index == 0 ? arg : arg + " ") + .toArray(String[]::new)); + } catch (Exception e) { + logger.log(java.util.logging.Level.SEVERE, "Unexpected", e); + throw e; + } + } +} diff --git a/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorBusyBox.java b/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorBusyBox.java index 58e3b48b3df996..b3f5c42d114b19 100644 --- a/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorBusyBox.java +++ b/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorBusyBox.java @@ -138,6 +138,12 @@ void call(String[] args) throws Exception { void call(String[] args) throws Exception { AndroidDataBindingProcessingAction.main(args); } + }, + GEN_BASE_CLASSES { + @Override + void call(String[] args) throws Exception { + GenerateDatabindingBaseClassesAction.main(args); + } }; abstract void call(String[] args) throws Exception;