diff options
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.java | 162 |
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; + } +} |