Skip to content

Commit

Permalink
Extract and propagate databinding information from imported aars.
Browse files Browse the repository at this point in the history
#2694

RELNOTES: None
PiperOrigin-RevId: 309327526
  • Loading branch information
ahumesky authored and copybara-github committed May 1, 2020
1 parent e7ed050 commit 850a864
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.rules.android.databinding.DataBinding;
import com.google.devtools.build.lib.rules.android.databinding.DataBindingV2Provider;
import com.google.devtools.build.lib.rules.java.ImportDepsCheckActionBuilder;
import com.google.devtools.build.lib.rules.java.JavaCommon;
import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider;
Expand All @@ -46,6 +47,7 @@
import com.google.devtools.build.lib.rules.java.JavaSourceJarsProvider;
import com.google.devtools.build.lib.rules.java.JavaStarlarkApiProvider;
import com.google.devtools.build.lib.rules.java.JavaToolchainProvider;
import com.google.devtools.build.lib.skylarkbuildapi.android.DataBindingV2ProviderApi;
import com.google.devtools.build.lib.vfs.PathFragment;
import javax.annotation.Nullable;

Expand Down Expand Up @@ -92,8 +94,12 @@ public ConfiguredTarget create(RuleContext ruleContext)

SpecialArtifact resources = createAarTreeArtifact(ruleContext, "resources");
SpecialArtifact assets = createAarTreeArtifact(ruleContext, "assets");
SpecialArtifact databindingBrFiles = createAarTreeArtifact(ruleContext, "data-binding-br");
SpecialArtifact databindingSetterStoreFiles =
createAarTreeArtifact(ruleContext, "data-binding-setter_store");
ruleContext.registerAction(
createAarResourcesExtractorActions(ruleContext, aar, resources, assets));
createAarResourcesExtractorActions(
ruleContext, aar, resources, assets, databindingBrFiles, databindingSetterStoreFiles));

AndroidDataContext dataContext = androidSemantics.makeContextForNative(ruleContext);
StampedAndroidManifest manifest = AndroidManifest.forAarImport(androidManifestArtifact);
Expand Down Expand Up @@ -226,6 +232,9 @@ public ConfiguredTarget create(RuleContext ruleContext)
common.addTransitiveInfoProviders(
ruleBuilder, javaInfoBuilder, filesToBuild, /*classJar=*/ null);

DataBindingV2Provider dataBindingV2Provider =
createDatabindingProvider(ruleContext, databindingBrFiles, databindingSetterStoreFiles);

resourceApk.addToConfiguredTargetBuilder(
ruleBuilder,
ruleContext.getLabel(),
Expand All @@ -237,6 +246,7 @@ public ConfiguredTarget create(RuleContext ruleContext)
.addSkylarkTransitiveInfo(
JavaStarlarkApiProvider.NAME, JavaStarlarkApiProvider.fromRuleContext())
.addProvider(RunfilesProvider.class, RunfilesProvider.EMPTY)
.addNativeDeclaredProvider(dataBindingV2Provider)
.addNativeDeclaredProvider(
new AndroidNativeLibsInfo(
AndroidCommon.collectTransitiveNativeLibs(ruleContext).add(nativeLibs).build()))
Expand Down Expand Up @@ -307,7 +317,13 @@ private static Action[] createSingleFileExtractorActions(
}

private static Action[] createAarResourcesExtractorActions(
RuleContext ruleContext, Artifact aar, Artifact resourcesDir, Artifact assetsDir) {
RuleContext ruleContext,
Artifact aar,
Artifact resourcesDir,
Artifact assetsDir,
Artifact databindingBrFiles,
Artifact databindingSetterStoreFiles) {

return new SpawnAction.Builder()
.useDefaultShellEnvironment()
.setExecutable(
Expand All @@ -317,11 +333,15 @@ private static Action[] createAarResourcesExtractorActions(
.addInput(aar)
.addOutput(resourcesDir)
.addOutput(assetsDir)
.addOutput(databindingBrFiles)
.addOutput(databindingSetterStoreFiles)
.addCommandLine(
CustomCommandLine.builder()
.addExecPath("--input_aar", aar)
.addExecPath("--output_res_dir", resourcesDir)
.addExecPath("--output_assets_dir", assetsDir)
.addExecPath("--output_databinding_br_dir", databindingBrFiles)
.addExecPath("--output_databinding_setter_store_dir", databindingSetterStoreFiles)
.build())
.build(ruleContext);
}
Expand Down Expand Up @@ -389,6 +409,36 @@ private static Action[] createAarNativeLibsFilterActions(
return actionBuilder.build(ruleContext);
}

private static DataBindingV2Provider createDatabindingProvider(
RuleContext ruleContext,
SpecialArtifact databindingBrFiles,
SpecialArtifact databindingSetterStoreFiles) {

Iterable<? extends DataBindingV2ProviderApi<Artifact>> databindingProvidersFromDeps =
ruleContext.getPrerequisites("deps", TransitionMode.TARGET, DataBindingV2Provider.PROVIDER);

Iterable<? extends DataBindingV2ProviderApi<Artifact>> databindingProvidersFromExports =
ruleContext.getPrerequisites(
"exports", TransitionMode.TARGET, DataBindingV2Provider.PROVIDER);

DataBindingV2Provider dataBindingV2Provider =
DataBindingV2Provider.createProvider(
databindingSetterStoreFiles,
/* classInfoFile= */ null,
databindingBrFiles,
ruleContext.getRule().getLabel().toString(),
// TODO: The aar's Java package isn't available during analysis (it's in the manifest
// inside the aar, or can maybe be inferred elsewhere). This is mostly used for
// constructing a nice error message if multiple android_library rules try to generate
// databinding conflicting classes into the same Java package, so it's not as important
// for aars.
/* javaPackage= */ null,
databindingProvidersFromDeps,
databindingProvidersFromExports);

return dataBindingV2Provider;
}

private static Artifact createAarArtifact(RuleContext ruleContext, String name) {
return ruleContext.getUniqueDirectoryArtifact(
"_aar", name, ruleContext.getBinOrGenfilesDirectory());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ public ImmutableList<Artifact> processDeps(RuleContext ruleContext, boolean isBi

for (Entry<String, Collection<String>> entry : javaPackagesToLabel.asMap().entrySet()) {
if (entry.getValue().size() > 1) {
String javaPackage = entry.getKey().isEmpty() ? "<default package>" : entry.getKey();
ruleContext.attributeError(
"deps",
String.format(
Expand All @@ -159,7 +160,7 @@ public ImmutableList<Artifact> processDeps(RuleContext ruleContext, boolean isBi
+ "android_library targets are:\n"
+ " Java package %s:\n"
+ " %s",
entry.getKey(), Joiner.on("\n ").join(entry.getValue())));
javaPackage, Joiner.on("\n ").join(entry.getValue())));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package com.google.devtools.build.lib.rules.android;

import static com.google.common.truth.Truth.assertThat;
import static java.util.stream.Collectors.toList;

import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableMap;
Expand All @@ -30,6 +31,7 @@
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.rules.android.databinding.DataBindingV2Provider;
import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider;
import com.google.devtools.build.lib.rules.java.JavaCompilationInfoProvider;
import com.google.devtools.build.lib.rules.java.JavaConfiguration.ImportDepsCheckingLevel;
Expand Down Expand Up @@ -189,6 +191,29 @@ public void testResourcesProvided() throws Exception {
assertThat(assetsTreeArtifact.getExecPathString()).endsWith("_aar/unzipped/assets/foo");
}

@Test
public void testDatabindingInfoProvided() throws Exception {
ConfiguredTarget aarImportTarget = getConfiguredTarget("//a:last");

DataBindingV2Provider provider = aarImportTarget.get(DataBindingV2Provider.PROVIDER);

Artifact setterStore = Iterables.getOnlyElement(provider.getSetterStores());
assertThat(setterStore.isTreeArtifact()).isTrue();
assertThat(setterStore.getExecPathString())
.endsWith("_aar/unzipped/data-binding-setter_store/last");

assertThat(
provider.getTransitiveBRFiles().toList().stream()
.map(Artifact::getRootRelativePathString)
.collect(toList()))
.containsExactly(
"a/_aar/unzipped/data-binding-br/baz",
"a/_aar/unzipped/data-binding-br/foo",
"a/_aar/unzipped/data-binding-br/bar",
"a/_aar/unzipped/data-binding-br/intermediate",
"a/_aar/unzipped/data-binding-br/last");
}

@Test
public void testSourceJarsProvided() throws Exception {
ConfiguredTarget aarImportTarget = getConfiguredTarget("//a:foo");
Expand Down Expand Up @@ -249,6 +274,12 @@ public void testResourcesExtractor() throws Exception {
.get(0);
Artifact assetsTreeArtifact = assets.getAssets().get(0);

DataBindingV2Provider dataBindingV2Provider =
getConfiguredTarget("//a:foo").get(DataBindingV2Provider.PROVIDER);
Artifact databindingBrTreeArtifact =
dataBindingV2Provider.getTransitiveBRFiles().toList().get(0);
Artifact databindingSetterStoreTreeArtifact = dataBindingV2Provider.getSetterStores().get(0);

assertThat(getGeneratingSpawnAction(resourceTreeArtifact).getArguments())
.containsExactly(
aarResourcesExtractor.getExecPathString(),
Expand All @@ -257,7 +288,11 @@ public void testResourcesExtractor() throws Exception {
"--output_res_dir",
resourceTreeArtifact.getExecPathString(),
"--output_assets_dir",
assetsTreeArtifact.getExecPathString());
assetsTreeArtifact.getExecPathString(),
"--output_databinding_br_dir",
databindingBrTreeArtifact.getExecPathString(),
"--output_databinding_setter_store_dir",
databindingSetterStoreTreeArtifact.getExecPathString());
}

@Test
Expand Down
18 changes: 18 additions & 0 deletions tools/android/aar_resources_extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
flags.DEFINE_string("output_res_dir", None, "Output resources directory")
flags.mark_flag_as_required("output_res_dir")
flags.DEFINE_string("output_assets_dir", None, "Output assets directory")
flags.DEFINE_string("output_databinding_br_dir", None,
"Output directory for databinding br files")
flags.DEFINE_string("output_databinding_setter_store_dir", None,
"Output directory for databinding setter_store.json files")


def ExtractResources(aar, output_res_dir):
Expand Down Expand Up @@ -79,6 +83,14 @@ def ExtractAssets(aar, output_assets_dir):
WriteFileWithJunctions(empty_asset_filename, b"")


def ExtractDatabinding(aar, file_suffix, output_databinding_dir):
"""Extracts databinding metadata files from an `aar`."""
output_databinding_dir_abs = os.path.abspath(output_databinding_dir)
for name in aar.namelist():
if name.startswith("data-binding/") and name.endswith(file_suffix):
ExtractOneFile(aar, name, output_databinding_dir_abs)


def WriteFileWithJunctions(filename, content):
"""Writes file including creating any junctions or directories necessary."""
def _WriteFile(filename):
Expand Down Expand Up @@ -132,6 +144,12 @@ def main(unused_argv):
ExtractResources(aar, FLAGS.output_res_dir)
if FLAGS.output_assets_dir is not None:
ExtractAssets(aar, FLAGS.output_assets_dir)
if FLAGS.output_databinding_br_dir is not None:
ExtractDatabinding(aar, "br.bin", FLAGS.output_databinding_br_dir)
if FLAGS.output_databinding_setter_store_dir is not None:
ExtractDatabinding(aar, "setter_store.json",
FLAGS.output_databinding_setter_store_dir)


if __name__ == "__main__":
FLAGS(sys.argv)
Expand Down
25 changes: 25 additions & 0 deletions tools/android/aar_resources_extractor_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,31 @@ def testContainsAssets(self):
with open("out_dir/assets/b", "r") as layout_xml:
self.assertEqual("some other asset", layout_xml.read())

def testDatabinding(self):
aar = zipfile.ZipFile(io.BytesIO(), "w")

br_filepath = (
"data-binding/com.android.databinding.library.baseAdapters--br.bin")
setter_store_filepath = (
"data-binding/" +
"com.android.databinding.library.baseAdapters--setter_store.json")

aar.writestr(br_filepath, "br data")
aar.writestr(setter_store_filepath, "setter store data")

os.makedirs("out_dir/br")
os.makedirs("out_dir/setter_store")

aar_resources_extractor.ExtractDatabinding(aar, "br.bin", "out_dir/br")
aar_resources_extractor.ExtractDatabinding(aar, "setter_store.json",
"out_dir/setter_store")

with open("out_dir/br/" + br_filepath, "r") as f:
self.assertEqual("br data", f.read())

with open("out_dir/setter_store/" + setter_store_filepath, "r") as f:
self.assertEqual("setter store data", f.read())


if __name__ == "__main__":
unittest.main()

0 comments on commit 850a864

Please sign in to comment.