From 81dbe79d09b4fa98d7803018b5d6d026e2e52a2e Mon Sep 17 00:00:00 2001 From: asteinb Date: Tue, 3 Apr 2018 07:08:09 -0700 Subject: Add methods to parse resources without assets - Add ParsedAndroidResources to wrap AndroidResources and resource parsing output. - Implement parse() method in AndroidResources, and support for it elsewhere - Move some supporting methods to the right place (setting up an aapt2 sdk for tests goes to the base test rule, and creating a dummy DataBinding zip goes to the DataBinding class). - Tests for new parse() method, including support for getting a test RuleContext instance RELNOTES: none PiperOrigin-RevId: 191436027 --- .../AndroidResourceParsingActionBuilder.java | 19 +++- .../build/lib/rules/android/AndroidResources.java | 28 ++++- .../build/lib/rules/android/DataBinding.java | 8 +- .../lib/rules/android/ParsedAndroidResources.java | 115 +++++++++++++++++++++ 4 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidResources.java (limited to 'src/main') diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceParsingActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceParsingActionBuilder.java index 1b7125be7d..c890627b71 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceParsingActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceParsingActionBuilder.java @@ -46,10 +46,13 @@ public class AndroidResourceParsingActionBuilder { private AndroidResources resources = AndroidResources.empty(); private AndroidAssets assets = AndroidAssets.empty(); + + // The symbols file is a required output private Artifact output; - private Artifact compiledSymbols; - private Artifact dataBindingInfoZip; + // Optional outputs + @Nullable private Artifact compiledSymbols; + @Nullable private Artifact dataBindingInfoZip; /** @param ruleContext The RuleContext that was used to create the SpawnAction.Builder. */ public AndroidResourceParsingActionBuilder(RuleContext ruleContext) { @@ -183,6 +186,18 @@ public class AndroidResourceParsingActionBuilder { } } + /** + * Builds and registers the action, and returns a copy of the passed resources with artifacts for + * parsed and compiled information. + */ + public ParsedAndroidResources build(AndroidResources androidResources) { + setResources(androidResources); + build(ruleContext); + + return ParsedAndroidResources.of( + androidResources, output, compiledSymbols, ruleContext.getLabel()); + } + /** * Builds and registers the action, and updates the given resourceContainer with the output * symbols. diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResources.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResources.java index 0402d62ba8..d4e11efe15 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResources.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResources.java @@ -31,6 +31,7 @@ import com.google.devtools.build.lib.vfs.PathFragment; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.Set; import javax.annotation.Nullable; @@ -41,7 +42,7 @@ import javax.annotation.Nullable; *

This is used to encapsulate the logic and the data associated with the resources derived from * an appropriate android rule in a reusable instance. */ -public final class AndroidResources { +public class AndroidResources { private static final String DEFAULT_RESOURCES_ATTR = "resource_files"; public static final String[] RESOURCES_ATTRIBUTES = @@ -293,6 +294,10 @@ public final class AndroidResources { private final ImmutableList resources; private final ImmutableList resourceRoots; + AndroidResources(AndroidResources other) { + this(other.resources, other.resourceRoots); + } + @VisibleForTesting public AndroidResources( ImmutableList resources, ImmutableList resourceRoots) { @@ -385,4 +390,25 @@ public final class AndroidResources { return Optional.of(new AndroidResources(filtered.get(), filteredResourcesRootsBuilder.build())); } + + public ParsedAndroidResources parse( + RuleContext ruleContext, + StampedAndroidManifest manifest) throws InterruptedException, RuleErrorException { + return ParsedAndroidResources.parseFrom(ruleContext, this, manifest); + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof AndroidResources)) { + return false; + } + + AndroidResources other = (AndroidResources) object; + return resources.equals(other.resources) && resourceRoots.equals(other.resourceRoots); + } + + @Override + public int hashCode() { + return Objects.hash(resources, resourceRoots); + } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/DataBinding.java b/src/main/java/com/google/devtools/build/lib/rules/android/DataBinding.java index b8925ea8f2..338494eb4f 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/DataBinding.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/DataBinding.java @@ -132,9 +132,13 @@ public final class DataBinding { * outputs are zipped up into a single container. */ static Artifact getLayoutInfoFile(RuleContext ruleContext) { - // The data binding library expects this to be called "layout-info.zip". + return getSuffixedInfoFile(ruleContext, ""); + } + + /** Gets a layout info file with the specified suffix (for use in having different outputs) */ + static Artifact getSuffixedInfoFile(RuleContext ruleContext, String suffix) { return ruleContext.getUniqueDirectoryArtifact( - "databinding", "layout-info.zip", ruleContext.getBinOrGenfilesDirectory()); + "databinding", "layout-info" + suffix + ".zip", ruleContext.getBinOrGenfilesDirectory()); } /** diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidResources.java b/src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidResources.java new file mode 100644 index 0000000000..fc0af30386 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidResources.java @@ -0,0 +1,115 @@ +// 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.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; +import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion; +import java.util.Objects; +import javax.annotation.Nullable; + +/** Wraps parsed (and, if requested, compiled) android resources. */ +public class ParsedAndroidResources extends AndroidResources { + private final Artifact symbols; + @Nullable private final Artifact compiledSymbols; + private final Label label; + + public static ParsedAndroidResources parseFrom( + RuleContext ruleContext, AndroidResources resources, StampedAndroidManifest manifest) + throws RuleErrorException, InterruptedException { + + boolean isAapt2 = + AndroidAaptVersion.chooseTargetAaptVersion(ruleContext).equals(AndroidAaptVersion.AAPT2); + + AndroidResourceParsingActionBuilder builder = + new AndroidResourceParsingActionBuilder(ruleContext); + + if (DataBinding.isEnabled(ruleContext) && isAapt2) { + // TODO(corysmith): Centralize the data binding processing and zipping into a single + // action. Data binding processing needs to be triggered here as well as the merger to + // avoid aapt2 from throwing an error during compilation. + builder + .setDataBindingInfoZip(DataBinding.getSuffixedInfoFile(ruleContext, "_unused")) + .setManifest(manifest.getManifest()) + .setJavaPackage(manifest.getPackage()); + } + + return builder + .setOutput(ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_MERGED_SYMBOLS)) + .setCompiledSymbolsOutput( + isAapt2 + ? ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_COMPILED_SYMBOLS) + : null) + .build(resources); + } + + public static ParsedAndroidResources of( + AndroidResources resources, + Artifact symbols, + @Nullable Artifact compiledSymbols, + Label label) { + return new ParsedAndroidResources( + resources, + symbols, + compiledSymbols, + label); + } + + ParsedAndroidResources(ParsedAndroidResources other) { + this(other, other.symbols, other.compiledSymbols, other.label); + } + + private ParsedAndroidResources( + AndroidResources resources, + Artifact symbols, + @Nullable Artifact compiledSymbols, + Label label) { + super(resources); + this.symbols = symbols; + this.compiledSymbols = compiledSymbols; + this.label = label; + } + + public Artifact getSymbols() { + return symbols; + } + + @Nullable + public Artifact getCompiledSymbols() { + return compiledSymbols; + } + + public Label getLabel() { + return label; + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof ParsedAndroidResources) || !super.equals(object)) { + return false; + } + + ParsedAndroidResources other = (ParsedAndroidResources) object; + return symbols.equals(other.symbols) + && Objects.equals(compiledSymbols, other.compiledSymbols) + && label.equals(other.label); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), symbols, compiledSymbols, label); + } +} -- cgit v1.2.3