aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/android/ResourceDependencies.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/android/ResourceDependencies.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/ResourceDependencies.java162
1 files changed, 162 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceDependencies.java b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceDependencies.java
new file mode 100644
index 0000000000..f55b46361a
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceDependencies.java
@@ -0,0 +1,162 @@
+// Copyright 2015 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.Iterables;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.rules.android.AndroidResourcesProvider.ResourceContainer;
+
+/**
+ * Represents a container for the {@link ResourceContainer}s for a given library. This is
+ * abstraction simplifies the process of managing and exporting the direct and transitive resource
+ * dependencies of an android rule, as well as providing type safety.
+ */
+public class ResourceDependencies {
+ /**
+ * Contains all the transitive resources that are not generated by the direct ancestors of the
+ * current rule.
+ */
+ private final NestedSet<ResourceContainer> transitiveResources;
+ /**
+ * Contains all the direct dependencies of the current target. Since a given direct dependency can
+ * act as a "forwarding" library, collecting all the direct resource from it's deps
+ * and providing them as "direct" dependencies to maintain merge order, this uses a NestedSet to
+ * properly maintain ordering and ease of merging.
+ */
+ private final NestedSet<ResourceContainer> directResources;
+
+ public static ResourceDependencies fromRuleResources(RuleContext ruleContext) {
+
+ NestedSetBuilder<ResourceContainer> transitiveDependencies = NestedSetBuilder.naiveLinkOrder();
+ NestedSetBuilder<ResourceContainer> directDependencies = NestedSetBuilder.naiveLinkOrder();
+ extractFromAttribute("resources", ruleContext, transitiveDependencies, directDependencies);
+ return new ResourceDependencies(transitiveDependencies.build(), directDependencies.build());
+ }
+
+ public static ResourceDependencies fromRuleDeps(RuleContext ruleContext) {
+ NestedSetBuilder<ResourceContainer> transitiveDependencies = NestedSetBuilder.naiveLinkOrder();
+ NestedSetBuilder<ResourceContainer> directDependencies = NestedSetBuilder.naiveLinkOrder();
+ extractFromAttribute("deps", ruleContext, transitiveDependencies, directDependencies);
+ return new ResourceDependencies(transitiveDependencies.build(), directDependencies.build());
+ }
+
+ public static ResourceDependencies fromRuleResourceAndDeps(RuleContext ruleContext) {
+ NestedSetBuilder<ResourceContainer> transitiveDependencies = NestedSetBuilder.naiveLinkOrder();
+ NestedSetBuilder<ResourceContainer> directDependencies = NestedSetBuilder.naiveLinkOrder();
+ extractFromAttribute("resources",ruleContext, transitiveDependencies, directDependencies);
+ if (directDependencies.isEmpty()) {
+ // There are no resources, so this library will forward the direct and transitive dependencies
+ // without changes.
+ extractFromAttribute("deps", ruleContext, transitiveDependencies, directDependencies);
+ } else {
+ // There are resources, so the direct dependencies and the transitive will be merged into
+ // the transitive dependencies. This maintains the relationship of the resources being
+ // directly on the rule.
+ extractFromAttribute("deps", ruleContext, transitiveDependencies, transitiveDependencies);
+ }
+ return new ResourceDependencies(transitiveDependencies.build(), directDependencies.build());
+ }
+
+ private static void extractFromAttribute(String attribute,
+ RuleContext ruleContext, NestedSetBuilder<ResourceContainer> builderForTransitive,
+ NestedSetBuilder<ResourceContainer> builderForDirect) {
+ for (AndroidResourcesProvider resources :
+ ruleContext.getPrerequisites(attribute, Mode.TARGET, AndroidResourcesProvider.class)) {
+ builderForTransitive.addTransitive(resources.getTransitiveAndroidResources());
+ builderForDirect.addTransitive(resources.getDirectAndroidResources());
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "ResourceDependencies [transitiveResources=" + transitiveResources + ", directResources="
+ + directResources + "]";
+ }
+
+ /**
+ * Creates an empty ResourceDependencies instance. This is used when an AndroidResources rule
+ * is the only resource dependency. The most common case is the AndroidTest rule.
+ */
+ public static ResourceDependencies empty() {
+ return new ResourceDependencies(
+ NestedSetBuilder.<ResourceContainer>emptySet(Order.NAIVE_LINK_ORDER),
+ NestedSetBuilder.<ResourceContainer>emptySet(Order.NAIVE_LINK_ORDER));
+ }
+
+ public ResourceDependencies(
+ NestedSet<ResourceContainer> transitiveResources,
+ NestedSet<ResourceContainer> directResources) {
+ this.transitiveResources = transitiveResources;
+ this.directResources = directResources;
+ }
+
+ /**
+ * Creates a new AndroidResourcesProvider with the supplied ResourceContainer as the direct dep.
+ *
+ * <p>When a library produces a new resource container the AndroidResourcesProvider should use
+ * that container as a the direct dependency for that library. This makes the consuming rule
+ * to identify the new container and merge appropriately. The previous direct dependencies are
+ * then added to the transitive dependencies.
+ *
+ * @param label The label of the library exporting this provider.
+ * @param newDirectResource The new direct dependency for AndroidResourcesProvider
+ * @return A provider with the current resources and label.
+ */
+ public AndroidResourcesProvider toProvider(Label label, ResourceContainer newDirectResource) {
+ return new AndroidResourcesProvider(
+ label,
+ NestedSetBuilder.<ResourceContainer>naiveLinkOrder()
+ .addTransitive(transitiveResources)
+ .addTransitive(directResources)
+ .build(),
+ NestedSetBuilder.<ResourceContainer>naiveLinkOrder().add(newDirectResource).build());
+ }
+
+ /**
+ * Create a new AndroidResourcesProvider from the dependencies of this library.
+ *
+ * <p>When a library doesn't export resources it should simply forward the current transitive and
+ * direct resources to the consuming rule. This allows the consuming rule to make decisions about
+ * the resource merging as if this library didn't exist.
+ *
+ * @param label The label of the library exporting this provider.
+ * @return A provider with the current resources and label.
+ */
+ public AndroidResourcesProvider toProvider(Label label) {
+ return new AndroidResourcesProvider(label, transitiveResources, directResources);
+ }
+
+ /**
+ * Provides an NestedSet of the direct and transitive resources.
+ */
+ public Iterable<ResourceContainer> getResources() {
+ return NestedSetBuilder.<ResourceContainer>naiveLinkOrder()
+ .addTransitive(directResources)
+ .addTransitive(transitiveResources)
+ .build();
+ }
+
+ public NestedSet<ResourceContainer> getTransitiveResources() {
+ return transitiveResources;
+ }
+
+ public NestedSet<ResourceContainer> getDirectResources() {
+ return directResources;
+ }
+}