Skip to content

Commit 4b00ab1

Browse files
ahumeskyCopybara-Service
authored and
Copybara-Service
committed
Update Android rules for Databinding V2.
RELNOTES[NEW]: Android Databinding v2 can be enabled with --experimental_android_databinding_v2. PiperOrigin-RevId: 221710069
1 parent e636d30 commit 4b00ab1

23 files changed

+1503
-183
lines changed

src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,11 @@ public Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, String
731731
return getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative, getBinOrGenfilesDirectory());
732732
}
733733

734+
@Override
735+
public Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, PathFragment relative) {
736+
return getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative, getBinOrGenfilesDirectory());
737+
}
738+
734739
/**
735740
* Creates an artifact in a directory that is unique to the rule, thus guaranteeing that it never
736741
* clashes with artifacts created by other rules.

src/main/java/com/google/devtools/build/lib/analysis/actions/ActionConstructionContext.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,30 @@ public interface ActionConstructionContext {
8080
*/
8181
Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, String relative);
8282

83+
/**
84+
* Creates an artifact in a directory that is unique to the rule, thus guaranteeing that it never
85+
* clashes with artifacts created by other rules.
86+
*
87+
* @param uniqueDirectorySuffix suffix of the directory - it will be prepended
88+
*/
89+
Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, PathFragment relative);
90+
91+
/**
92+
* Returns a path fragment qualified by the rule name and unique fragment to
93+
* disambiguate artifacts produced from the source file appearing in
94+
* multiple rules.
95+
*
96+
* <p>For example "pkg/dir/name" -> "pkg/&lt;fragment>/rule/dir/name.
97+
*/
98+
public PathFragment getUniqueDirectory(PathFragment fragment);
99+
100+
/**
101+
* Returns the root of either the "bin" or "genfiles" tree, based on this target and the current
102+
* configuration. The choice of which tree to use is based on the rule with which this target
103+
* (which must be an OutputFile or a Rule) is associated.
104+
*/
105+
public ArtifactRoot getBinOrGenfilesDirectory();
106+
83107
/**
84108
* Returns the root-relative path fragment under which output artifacts of this rule should go.
85109
*

src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -878,10 +878,17 @@ static JavaCommon createJavaCommonWithAndroidDataBinding(
878878
JavaSemantics semantics,
879879
DataBindingContext dataBindingContext,
880880
boolean isLibrary) {
881-
ImmutableList<Artifact> srcs =
882-
dataBindingContext.addAnnotationFileToSrcs(
883-
ruleContext.getPrerequisiteArtifacts("srcs", RuleConfiguredTarget.Mode.TARGET).list(),
884-
ruleContext);
881+
882+
ImmutableList<Artifact> ruleSources =
883+
ruleContext.getPrerequisiteArtifacts("srcs", RuleConfiguredTarget.Mode.TARGET).list();
884+
885+
ImmutableList<Artifact> dataBindingSources =
886+
dataBindingContext.getAnnotationSourceFiles(ruleContext);
887+
888+
ImmutableList<Artifact> srcs = ImmutableList.<Artifact>builder()
889+
.addAll(ruleSources)
890+
.addAll(dataBindingSources)
891+
.build();
885892

886893
ImmutableList<TransitiveInfoCollection> compileDeps;
887894
ImmutableList<TransitiveInfoCollection> runtimeDeps;
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright 2018 The Bazel Authors. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package com.google.devtools.build.lib.rules.android;
15+
16+
import com.google.common.collect.ImmutableList;
17+
import com.google.devtools.build.lib.actions.Artifact;
18+
import com.google.devtools.build.lib.actions.ArtifactRoot;
19+
import com.google.devtools.build.lib.vfs.PathFragment;
20+
21+
/** Builder for creating databinding processing action. */
22+
public class AndroidDataBindingProcessorBuilder {
23+
24+
/**
25+
* Creates and registers an action to strip databinding from layout xml and generate the layout
26+
* info file.
27+
*
28+
* @param dataContext The android data context.
29+
* @param androidResources The resources to process.
30+
* @param appId The app id (the app's java package).
31+
* @param dataBindingLayoutInfoOut The output layout info file to write.
32+
* @return The new AndroidResources that has been processed by databinding.
33+
*/
34+
public static AndroidResources create(
35+
AndroidDataContext dataContext,
36+
AndroidResources androidResources,
37+
String appId,
38+
Artifact dataBindingLayoutInfoOut) {
39+
40+
ImmutableList.Builder<Artifact> databindingProcessedResourcesBuilder = ImmutableList.builder();
41+
for (Artifact resource : androidResources.getResources()) {
42+
43+
// Create resources that will be processed by databinding under paths that look like:
44+
//
45+
// <bazel-pkg>/databinding-processed-resources/<rule-name>/<bazal-pkg>/<resource-dir>
46+
47+
Artifact databindingProcessedResource =
48+
dataContext.getUniqueDirectoryArtifact("databinding-processed-resources",
49+
resource.getRootRelativePath());
50+
51+
databindingProcessedResourcesBuilder.add(databindingProcessedResource);
52+
}
53+
ImmutableList<Artifact> databindingProcessedResources =
54+
databindingProcessedResourcesBuilder.build();
55+
56+
BusyBoxActionBuilder builder = BusyBoxActionBuilder.create(dataContext, "PROCESS_DATABINDING");
57+
58+
// Create output resource roots that correspond to the paths of the resources created above:
59+
//
60+
// <bazel-pkg>/databinding-processed-resources/<rule-name>/<resource-root>
61+
//
62+
// AndroidDataBindingProcessingAction will append each value of --resource_root to its
63+
// corresponding --output_resource_root, so the only part that needs to be constructed here is
64+
//
65+
// <bazel-pkg>/databinding-processed-resources/<rule-name>
66+
ArtifactRoot binOrGenfiles = dataContext.getBinOrGenfilesDirectory();
67+
PathFragment uniqueDir =
68+
dataContext.getUniqueDirectory(PathFragment.create("databinding-processed-resources"));
69+
PathFragment outputResourceRoot = binOrGenfiles.getExecPath().getRelative(uniqueDir);
70+
71+
ImmutableList.Builder<PathFragment> outputResourceRootsBuilder = ImmutableList.builder();
72+
for (PathFragment resourceRoot : androidResources.getResourceRoots()) {
73+
74+
outputResourceRootsBuilder.add(outputResourceRoot);
75+
76+
// The order of these matter, the input root and the output root have to be matched up
77+
// because the resource processor will iterate over them in pairs.
78+
builder.addFlag("--resource_root", resourceRoot.toString());
79+
builder.addFlag("--output_resource_root", outputResourceRoot.toString());
80+
}
81+
82+
// Even though the databinding processor really only cares about layout files, we send
83+
// all the resources so that the new resource root that is created for databinding processing
84+
// can be used for later processing (e.g. aapt). It would be nice to send only the layout
85+
// files, but then we'd have to mix roots and rely on sandboxing to "hide" the
86+
// old unprocessed files, which might not work if, for example, the actions run locally.
87+
builder.addInputs(androidResources.getResources());
88+
89+
builder.addOutputs(databindingProcessedResources);
90+
91+
builder.addOutput("--dataBindingInfoOut", dataBindingLayoutInfoOut);
92+
builder.addFlag("--appId", appId);
93+
94+
builder.buildAndRegister("Processing data binding", "ProcessDatabinding");
95+
96+
return new AndroidResources(databindingProcessedResources, outputResourceRootsBuilder.build());
97+
}
98+
}

src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataContext.java

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
1717
import com.google.devtools.build.lib.actions.Artifact;
18+
import com.google.devtools.build.lib.actions.ArtifactRoot;
1819
import com.google.devtools.build.lib.analysis.FilesToRunProvider;
1920
import com.google.devtools.build.lib.analysis.RuleContext;
2021
import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
@@ -24,6 +25,7 @@
2425
import com.google.devtools.build.lib.cmdline.Label;
2526
import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SafeImplicitOutputsFunction;
2627
import com.google.devtools.build.lib.skylarkbuildapi.android.AndroidDataContextApi;
28+
import com.google.devtools.build.lib.vfs.PathFragment;
2729

2830
/**
2931
* Wraps common tools and settings used for working with Android assets, resources, and manifests.
@@ -37,39 +39,45 @@
3739
* are used in BusyBox actions.
3840
*/
3941
public class AndroidDataContext implements AndroidDataContextApi {
42+
4043
private final Label label;
4144
private final ActionConstructionContext actionConstructionContext;
4245
private final FilesToRunProvider busybox;
4346
private final AndroidSdkProvider sdk;
4447
private final boolean persistentBusyboxToolsEnabled;
48+
private final boolean useDataBindingV2;
4549

4650
public static AndroidDataContext forNative(RuleContext ruleContext) {
4751
return makeContext(ruleContext);
4852
}
4953

5054
public static AndroidDataContext makeContext(RuleContext ruleContext) {
55+
AndroidConfiguration androidConfig = ruleContext
56+
.getConfiguration()
57+
.getFragment(AndroidConfiguration.class);
58+
5159
return new AndroidDataContext(
5260
ruleContext.getLabel(),
5361
ruleContext,
5462
ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST),
55-
ruleContext
56-
.getConfiguration()
57-
.getFragment(AndroidConfiguration.class)
58-
.persistentBusyboxTools(),
59-
AndroidSdkProvider.fromRuleContext(ruleContext));
63+
androidConfig.persistentBusyboxTools(),
64+
AndroidSdkProvider.fromRuleContext(ruleContext),
65+
androidConfig.useDataBindingV2());
6066
}
6167

6268
protected AndroidDataContext(
6369
Label label,
6470
ActionConstructionContext actionConstructionContext,
6571
FilesToRunProvider busybox,
6672
boolean persistentBusyboxToolsEnabled,
67-
AndroidSdkProvider sdk) {
73+
AndroidSdkProvider sdk,
74+
boolean useDataBindingV2) {
6875
this.label = label;
6976
this.persistentBusyboxToolsEnabled = persistentBusyboxToolsEnabled;
7077
this.actionConstructionContext = actionConstructionContext;
7178
this.busybox = busybox;
7279
this.sdk = sdk;
80+
this.useDataBindingV2 = useDataBindingV2;
7381
}
7482

7583
public Label getLabel() {
@@ -111,6 +119,22 @@ public Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, String
111119
return actionConstructionContext.getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative);
112120
}
113121

122+
public Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, PathFragment relative) {
123+
return actionConstructionContext.getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative);
124+
}
125+
126+
public PathFragment getUniqueDirectory(PathFragment fragment) {
127+
return actionConstructionContext.getUniqueDirectory(fragment);
128+
}
129+
130+
public ArtifactRoot getBinOrGenfilesDirectory() {
131+
return actionConstructionContext.getBinOrGenfilesDirectory();
132+
}
133+
134+
public PathFragment getPackageDirectory() {
135+
return actionConstructionContext.getPackageDirectory();
136+
}
137+
114138
public AndroidConfiguration getAndroidConfig() {
115139
return actionConstructionContext.getConfiguration().getFragment(AndroidConfiguration.class);
116140
}
@@ -124,4 +148,8 @@ public boolean useDebug() {
124148
public boolean isPersistentBusyboxToolsEnabled() {
125149
return persistentBusyboxToolsEnabled;
126150
}
151+
152+
public boolean useDataBindingV2() {
153+
return useDataBindingV2;
154+
}
127155
}

src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -214,23 +214,35 @@ public ProcessedAndroidData build(
214214
StampedAndroidManifest primaryManifest,
215215
DataBindingContext dataBindingContext) {
216216

217-
if (aaptVersion == AndroidAaptVersion.AAPT2) {
218-
createAapt2ApkAction(dataContext, primaryResources, primaryAssets, primaryManifest);
219-
} else {
220-
createAaptAction(dataContext, primaryResources, primaryAssets, primaryManifest);
221-
}
222-
223217
// Wrap the new manifest, if any
224218
ProcessedAndroidManifest processedManifest =
225219
new ProcessedAndroidManifest(
226220
manifestOut == null ? primaryManifest.getManifest() : manifestOut,
227221
primaryManifest.getPackage(),
228222
primaryManifest.isExported());
229223

224+
// In databinding v2, this strips out the databinding and generates the layout info file.
225+
AndroidResources databindingProcessedResources = dataBindingContext.processResources(
226+
dataContext, primaryResources, processedManifest.getPackage());
227+
228+
if (aaptVersion == AndroidAaptVersion.AAPT2) {
229+
createAapt2ApkAction(
230+
dataContext,
231+
databindingProcessedResources,
232+
primaryAssets,
233+
primaryManifest);
234+
} else {
235+
createAaptAction(
236+
dataContext,
237+
databindingProcessedResources,
238+
primaryAssets,
239+
primaryManifest);
240+
}
241+
230242
// Wrap the parsed resources
231243
ParsedAndroidResources parsedResources =
232244
ParsedAndroidResources.of(
233-
primaryResources,
245+
databindingProcessedResources,
234246
symbols,
235247
/* compiledSymbols = */ null,
236248
dataContext.getLabel(),

src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,11 @@ Generated files (from genrules) can be referenced by
442442
attr(DataBinding.DATABINDING_ANNOTATION_PROCESSOR_ATTR, LABEL)
443443
.cfg(HostTransition.INSTANCE)
444444
.value(env.getToolsLabel("//tools/android:databinding_annotation_processor")))
445+
.add(
446+
attr(DataBinding.DATABINDING_EXEC_PROCESSOR_ATTR, LABEL)
447+
.cfg(HostTransition.INSTANCE)
448+
.exec()
449+
.value(env.getToolsLabel("//tools/android:databinding_exec")))
445450
.advertiseSkylarkProvider(
446451
SkylarkProviderIdentifier.forKey(AndroidResourcesInfo.PROVIDER.getKey()))
447452
.advertiseSkylarkProvider(

src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkData.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public AndroidResourcesInfo resourcesFromDeps(
9393
}
9494
return ResourceApk.processFromTransitiveLibraryData(
9595
ctx,
96-
DataBinding.asDisabledDataBindingContext(),
96+
DataBinding.getDisabledDataBindingContext(ctx),
9797
ResourceDependencies.fromProviders(deps, /* neverlink = */ neverlink),
9898
AssetDependencies.empty(),
9999
StampedAndroidManifest.createEmpty(
@@ -374,7 +374,7 @@ public SkylarkDict<Provider, NativeInfo> processAarImportData(
374374
AndroidManifest.forAarImport(androidManifestArtifact),
375375
ResourceDependencies.fromProviders(
376376
getProviders(deps, AndroidResourcesInfo.PROVIDER), /* neverlink = */ false),
377-
DataBinding.asDisabledDataBindingContext(),
377+
DataBinding.getDisabledDataBindingContext(ctx),
378378
aaptVersion);
379379

380380
MergedAndroidAssets mergedAssets =
@@ -420,7 +420,7 @@ public SkylarkDict<Provider, NativeInfo> processLocalTestData(
420420
ctx,
421421
getAndroidSemantics(),
422422
errorReporter,
423-
DataBinding.asDisabledDataBindingContext(),
423+
DataBinding.getDisabledDataBindingContext(ctx),
424424
rawManifest,
425425
AndroidResources.from(errorReporter, getFileProviders(resources), "resource_files"),
426426
AndroidAssets.from(

src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ public BusyBoxActionBuilder addInput(
9898
return this;
9999
}
100100

101+
/** Adds the given input artifacts without any command line options. */
102+
public BusyBoxActionBuilder addInputs(Iterable<Artifact> inputs) {
103+
this.inputs.addAll(inputs);
104+
return this;
105+
}
106+
101107
/** Adds an input artifact if it is non-null */
102108
public BusyBoxActionBuilder maybeAddInput(
103109
@CompileTimeConstant String arg, @Nullable Artifact value) {
@@ -150,6 +156,12 @@ public BusyBoxActionBuilder addOutput(@CompileTimeConstant String arg, Artifact
150156
return this;
151157
}
152158

159+
/** Adds the given output artifacts without adding any command line options. */
160+
public BusyBoxActionBuilder addOutputs(Iterable<Artifact> outputs) {
161+
this.outputs.addAll(outputs);
162+
return this;
163+
}
164+
153165
/** Adds an output artifact if it is non-null */
154166
public BusyBoxActionBuilder maybeAddOutput(
155167
@CompileTimeConstant String arg, @Nullable Artifact value) {

src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidResources.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ public static ParsedAndroidResources parseFrom(
5656
getDummyDataBindingArtifact(dataContext.getActionConstructionContext())));
5757
}
5858

59+
// In databinding v2, this strips out the databinding and generates the layout info file.
60+
AndroidResources databindingProcessedResources =
61+
dataBindingContext.processResources(dataContext, resources, manifest.getPackage());
62+
5963
return builder
6064
.setOutput(dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_MERGED_SYMBOLS))
6165
.setCompiledSymbolsOutput(
@@ -64,7 +68,7 @@ public static ParsedAndroidResources parseFrom(
6468
: null)
6569
.build(
6670
dataContext,
67-
dataBindingContext.processResources(resources),
71+
databindingProcessedResources,
6872
manifest,
6973
dataBindingContext);
7074
}

0 commit comments

Comments
 (0)