Skip to content

Commit

Permalink
Update Android rules for Databinding V2.
Browse files Browse the repository at this point in the history
RELNOTES[NEW]: Android Databinding v2 can be enabled with --experimental_android_databinding_v2.

PiperOrigin-RevId: 221710069
  • Loading branch information
ahumesky authored and Copybara-Service committed Nov 16, 2018
1 parent e636d30 commit 4b00ab1
Show file tree
Hide file tree
Showing 23 changed files with 1,503 additions and 183 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,11 @@ public Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, String
return getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative, getBinOrGenfilesDirectory());
}

@Override
public Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, PathFragment relative) {
return getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative, getBinOrGenfilesDirectory());
}

/**
* Creates an artifact in a directory that is unique to the rule, thus guaranteeing that it never
* clashes with artifacts created by other rules.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,30 @@ public interface ActionConstructionContext {
*/
Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, String relative);

/**
* Creates an artifact in a directory that is unique to the rule, thus guaranteeing that it never
* clashes with artifacts created by other rules.
*
* @param uniqueDirectorySuffix suffix of the directory - it will be prepended
*/
Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, PathFragment relative);

/**
* Returns a path fragment qualified by the rule name and unique fragment to
* disambiguate artifacts produced from the source file appearing in
* multiple rules.
*
* <p>For example "pkg/dir/name" -> "pkg/&lt;fragment>/rule/dir/name.
*/
public PathFragment getUniqueDirectory(PathFragment fragment);

/**
* Returns the root of either the "bin" or "genfiles" tree, based on this target and the current
* configuration. The choice of which tree to use is based on the rule with which this target
* (which must be an OutputFile or a Rule) is associated.
*/
public ArtifactRoot getBinOrGenfilesDirectory();

/**
* Returns the root-relative path fragment under which output artifacts of this rule should go.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -878,10 +878,17 @@ static JavaCommon createJavaCommonWithAndroidDataBinding(
JavaSemantics semantics,
DataBindingContext dataBindingContext,
boolean isLibrary) {
ImmutableList<Artifact> srcs =
dataBindingContext.addAnnotationFileToSrcs(
ruleContext.getPrerequisiteArtifacts("srcs", RuleConfiguredTarget.Mode.TARGET).list(),
ruleContext);

ImmutableList<Artifact> ruleSources =
ruleContext.getPrerequisiteArtifacts("srcs", RuleConfiguredTarget.Mode.TARGET).list();

ImmutableList<Artifact> dataBindingSources =
dataBindingContext.getAnnotationSourceFiles(ruleContext);

ImmutableList<Artifact> srcs = ImmutableList.<Artifact>builder()
.addAll(ruleSources)
.addAll(dataBindingSources)
.build();

ImmutableList<TransitiveInfoCollection> compileDeps;
ImmutableList<TransitiveInfoCollection> runtimeDeps;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright 2018 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.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.rules.android;

import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.ArtifactRoot;
import com.google.devtools.build.lib.vfs.PathFragment;

/** Builder for creating databinding processing action. */
public class AndroidDataBindingProcessorBuilder {

/**
* Creates and registers an action to strip databinding from layout xml and generate the layout
* info file.
*
* @param dataContext The android data context.
* @param androidResources The resources to process.
* @param appId The app id (the app's java package).
* @param dataBindingLayoutInfoOut The output layout info file to write.
* @return The new AndroidResources that has been processed by databinding.
*/
public static AndroidResources create(
AndroidDataContext dataContext,
AndroidResources androidResources,
String appId,
Artifact dataBindingLayoutInfoOut) {

ImmutableList.Builder<Artifact> databindingProcessedResourcesBuilder = ImmutableList.builder();
for (Artifact resource : androidResources.getResources()) {

// Create resources that will be processed by databinding under paths that look like:
//
// <bazel-pkg>/databinding-processed-resources/<rule-name>/<bazal-pkg>/<resource-dir>

Artifact databindingProcessedResource =
dataContext.getUniqueDirectoryArtifact("databinding-processed-resources",
resource.getRootRelativePath());

databindingProcessedResourcesBuilder.add(databindingProcessedResource);
}
ImmutableList<Artifact> databindingProcessedResources =
databindingProcessedResourcesBuilder.build();

BusyBoxActionBuilder builder = BusyBoxActionBuilder.create(dataContext, "PROCESS_DATABINDING");

// Create output resource roots that correspond to the paths of the resources created above:
//
// <bazel-pkg>/databinding-processed-resources/<rule-name>/<resource-root>
//
// AndroidDataBindingProcessingAction will append each value of --resource_root to its
// corresponding --output_resource_root, so the only part that needs to be constructed here is
//
// <bazel-pkg>/databinding-processed-resources/<rule-name>
ArtifactRoot binOrGenfiles = dataContext.getBinOrGenfilesDirectory();
PathFragment uniqueDir =
dataContext.getUniqueDirectory(PathFragment.create("databinding-processed-resources"));
PathFragment outputResourceRoot = binOrGenfiles.getExecPath().getRelative(uniqueDir);

ImmutableList.Builder<PathFragment> outputResourceRootsBuilder = ImmutableList.builder();
for (PathFragment resourceRoot : androidResources.getResourceRoots()) {

outputResourceRootsBuilder.add(outputResourceRoot);

// The order of these matter, the input root and the output root have to be matched up
// because the resource processor will iterate over them in pairs.
builder.addFlag("--resource_root", resourceRoot.toString());
builder.addFlag("--output_resource_root", outputResourceRoot.toString());
}

// Even though the databinding processor really only cares about layout files, we send
// all the resources so that the new resource root that is created for databinding processing
// can be used for later processing (e.g. aapt). It would be nice to send only the layout
// files, but then we'd have to mix roots and rely on sandboxing to "hide" the
// old unprocessed files, which might not work if, for example, the actions run locally.
builder.addInputs(androidResources.getResources());

builder.addOutputs(databindingProcessedResources);

builder.addOutput("--dataBindingInfoOut", dataBindingLayoutInfoOut);
builder.addFlag("--appId", appId);

builder.buildAndRegister("Processing data binding", "ProcessDatabinding");

return new AndroidResources(databindingProcessedResources, outputResourceRootsBuilder.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.ArtifactRoot;
import com.google.devtools.build.lib.analysis.FilesToRunProvider;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
Expand All @@ -24,6 +25,7 @@
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SafeImplicitOutputsFunction;
import com.google.devtools.build.lib.skylarkbuildapi.android.AndroidDataContextApi;
import com.google.devtools.build.lib.vfs.PathFragment;

/**
* Wraps common tools and settings used for working with Android assets, resources, and manifests.
Expand All @@ -37,39 +39,45 @@
* are used in BusyBox actions.
*/
public class AndroidDataContext implements AndroidDataContextApi {

private final Label label;
private final ActionConstructionContext actionConstructionContext;
private final FilesToRunProvider busybox;
private final AndroidSdkProvider sdk;
private final boolean persistentBusyboxToolsEnabled;
private final boolean useDataBindingV2;

public static AndroidDataContext forNative(RuleContext ruleContext) {
return makeContext(ruleContext);
}

public static AndroidDataContext makeContext(RuleContext ruleContext) {
AndroidConfiguration androidConfig = ruleContext
.getConfiguration()
.getFragment(AndroidConfiguration.class);

return new AndroidDataContext(
ruleContext.getLabel(),
ruleContext,
ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST),
ruleContext
.getConfiguration()
.getFragment(AndroidConfiguration.class)
.persistentBusyboxTools(),
AndroidSdkProvider.fromRuleContext(ruleContext));
androidConfig.persistentBusyboxTools(),
AndroidSdkProvider.fromRuleContext(ruleContext),
androidConfig.useDataBindingV2());
}

protected AndroidDataContext(
Label label,
ActionConstructionContext actionConstructionContext,
FilesToRunProvider busybox,
boolean persistentBusyboxToolsEnabled,
AndroidSdkProvider sdk) {
AndroidSdkProvider sdk,
boolean useDataBindingV2) {
this.label = label;
this.persistentBusyboxToolsEnabled = persistentBusyboxToolsEnabled;
this.actionConstructionContext = actionConstructionContext;
this.busybox = busybox;
this.sdk = sdk;
this.useDataBindingV2 = useDataBindingV2;
}

public Label getLabel() {
Expand Down Expand Up @@ -111,6 +119,22 @@ public Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, String
return actionConstructionContext.getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative);
}

public Artifact getUniqueDirectoryArtifact(String uniqueDirectorySuffix, PathFragment relative) {
return actionConstructionContext.getUniqueDirectoryArtifact(uniqueDirectorySuffix, relative);
}

public PathFragment getUniqueDirectory(PathFragment fragment) {
return actionConstructionContext.getUniqueDirectory(fragment);
}

public ArtifactRoot getBinOrGenfilesDirectory() {
return actionConstructionContext.getBinOrGenfilesDirectory();
}

public PathFragment getPackageDirectory() {
return actionConstructionContext.getPackageDirectory();
}

public AndroidConfiguration getAndroidConfig() {
return actionConstructionContext.getConfiguration().getFragment(AndroidConfiguration.class);
}
Expand All @@ -124,4 +148,8 @@ public boolean useDebug() {
public boolean isPersistentBusyboxToolsEnabled() {
return persistentBusyboxToolsEnabled;
}

public boolean useDataBindingV2() {
return useDataBindingV2;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -214,23 +214,35 @@ public ProcessedAndroidData build(
StampedAndroidManifest primaryManifest,
DataBindingContext dataBindingContext) {

if (aaptVersion == AndroidAaptVersion.AAPT2) {
createAapt2ApkAction(dataContext, primaryResources, primaryAssets, primaryManifest);
} else {
createAaptAction(dataContext, primaryResources, primaryAssets, primaryManifest);
}

// Wrap the new manifest, if any
ProcessedAndroidManifest processedManifest =
new ProcessedAndroidManifest(
manifestOut == null ? primaryManifest.getManifest() : manifestOut,
primaryManifest.getPackage(),
primaryManifest.isExported());

// In databinding v2, this strips out the databinding and generates the layout info file.
AndroidResources databindingProcessedResources = dataBindingContext.processResources(
dataContext, primaryResources, processedManifest.getPackage());

if (aaptVersion == AndroidAaptVersion.AAPT2) {
createAapt2ApkAction(
dataContext,
databindingProcessedResources,
primaryAssets,
primaryManifest);
} else {
createAaptAction(
dataContext,
databindingProcessedResources,
primaryAssets,
primaryManifest);
}

// Wrap the parsed resources
ParsedAndroidResources parsedResources =
ParsedAndroidResources.of(
primaryResources,
databindingProcessedResources,
symbols,
/* compiledSymbols = */ null,
dataContext.getLabel(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,11 @@ Generated files (from genrules) can be referenced by
attr(DataBinding.DATABINDING_ANNOTATION_PROCESSOR_ATTR, LABEL)
.cfg(HostTransition.INSTANCE)
.value(env.getToolsLabel("//tools/android:databinding_annotation_processor")))
.add(
attr(DataBinding.DATABINDING_EXEC_PROCESSOR_ATTR, LABEL)
.cfg(HostTransition.INSTANCE)
.exec()
.value(env.getToolsLabel("//tools/android:databinding_exec")))
.advertiseSkylarkProvider(
SkylarkProviderIdentifier.forKey(AndroidResourcesInfo.PROVIDER.getKey()))
.advertiseSkylarkProvider(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public AndroidResourcesInfo resourcesFromDeps(
}
return ResourceApk.processFromTransitiveLibraryData(
ctx,
DataBinding.asDisabledDataBindingContext(),
DataBinding.getDisabledDataBindingContext(ctx),
ResourceDependencies.fromProviders(deps, /* neverlink = */ neverlink),
AssetDependencies.empty(),
StampedAndroidManifest.createEmpty(
Expand Down Expand Up @@ -374,7 +374,7 @@ public SkylarkDict<Provider, NativeInfo> processAarImportData(
AndroidManifest.forAarImport(androidManifestArtifact),
ResourceDependencies.fromProviders(
getProviders(deps, AndroidResourcesInfo.PROVIDER), /* neverlink = */ false),
DataBinding.asDisabledDataBindingContext(),
DataBinding.getDisabledDataBindingContext(ctx),
aaptVersion);

MergedAndroidAssets mergedAssets =
Expand Down Expand Up @@ -420,7 +420,7 @@ public SkylarkDict<Provider, NativeInfo> processLocalTestData(
ctx,
getAndroidSemantics(),
errorReporter,
DataBinding.asDisabledDataBindingContext(),
DataBinding.getDisabledDataBindingContext(ctx),
rawManifest,
AndroidResources.from(errorReporter, getFileProviders(resources), "resource_files"),
AndroidAssets.from(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ public BusyBoxActionBuilder addInput(
return this;
}

/** Adds the given input artifacts without any command line options. */
public BusyBoxActionBuilder addInputs(Iterable<Artifact> inputs) {
this.inputs.addAll(inputs);
return this;
}

/** Adds an input artifact if it is non-null */
public BusyBoxActionBuilder maybeAddInput(
@CompileTimeConstant String arg, @Nullable Artifact value) {
Expand Down Expand Up @@ -150,6 +156,12 @@ public BusyBoxActionBuilder addOutput(@CompileTimeConstant String arg, Artifact
return this;
}

/** Adds the given output artifacts without adding any command line options. */
public BusyBoxActionBuilder addOutputs(Iterable<Artifact> outputs) {
this.outputs.addAll(outputs);
return this;
}

/** Adds an output artifact if it is non-null */
public BusyBoxActionBuilder maybeAddOutput(
@CompileTimeConstant String arg, @Nullable Artifact value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ public static ParsedAndroidResources parseFrom(
getDummyDataBindingArtifact(dataContext.getActionConstructionContext())));
}

// In databinding v2, this strips out the databinding and generates the layout info file.
AndroidResources databindingProcessedResources =
dataBindingContext.processResources(dataContext, resources, manifest.getPackage());

return builder
.setOutput(dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_MERGED_SYMBOLS))
.setCompiledSymbolsOutput(
Expand All @@ -64,7 +68,7 @@ public static ParsedAndroidResources parseFrom(
: null)
.build(
dataContext,
dataBindingContext.processResources(resources),
databindingProcessedResources,
manifest,
dataBindingContext);
}
Expand Down
Loading

0 comments on commit 4b00ab1

Please sign in to comment.