// 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.annotations.VisibleForTesting; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode; 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; /** * Contains transitive asset dependencies for a target. * *

In addition to NestedSets of transitive artifacts, we also keep transitive NestedSets of * direct and transitive parsed assets. These NestedSets contain the same information (and it may * appear in both the direct and transitive parsed asset NestedSets); we need to keep them both * separately to record relationships between assets, asset directories, and symbol artifacts and to * distinguish between direct and transitive assets. */ public class AssetDependencies { private final boolean neverlink; private final NestedSet directParsedAssets; private final NestedSet transitiveParsedAssets; private final NestedSet transitiveAssets; private final NestedSet transitiveSymbols; private final NestedSet transitiveCompiledSymbols; public static AssetDependencies fromRuleDeps(RuleContext ruleContext, boolean neverlink) { return fromProviders( AndroidCommon.getTransitivePrerequisites( ruleContext, Mode.TARGET, AndroidAssetsInfo.PROVIDER), neverlink); } public static AssetDependencies fromProviders( Iterable providers, boolean neverlink) { NestedSetBuilder direct = NestedSetBuilder.naiveLinkOrder(); NestedSetBuilder transitive = NestedSetBuilder.naiveLinkOrder(); NestedSetBuilder assets = NestedSetBuilder.naiveLinkOrder(); NestedSetBuilder symbols = NestedSetBuilder.naiveLinkOrder(); NestedSetBuilder compiledSymbols = NestedSetBuilder.naiveLinkOrder(); for (AndroidAssetsInfo info : providers) { direct.addTransitive(info.getDirectParsedAssets()); transitive.addTransitive(info.getTransitiveParsedAssets()); assets.addTransitive(info.getAssets()); symbols.addTransitive(info.getSymbols()); compiledSymbols.addTransitive(info.getCompiledSymbols()); } return of( neverlink, direct.build(), transitive.build(), assets.build(), symbols.build(), compiledSymbols.build()); } public static AssetDependencies empty() { return of( false, NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER), NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER), NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER), NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER), NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER)); } @VisibleForTesting static AssetDependencies of( boolean neverlink, NestedSet directParsedAssets, NestedSet transitiveParsedAssets, NestedSet transitiveAssets, NestedSet transitiveSymbols, NestedSet transitiveCompiledSymbols) { return new AssetDependencies( neverlink, directParsedAssets, transitiveParsedAssets, transitiveAssets, transitiveSymbols, transitiveCompiledSymbols); } private AssetDependencies( boolean neverlink, NestedSet directParsedAssets, NestedSet transitiveParsedAssets, NestedSet transitiveAssets, NestedSet transitiveSymbols, NestedSet transitiveCompiledSymbols) { this.neverlink = neverlink; this.directParsedAssets = directParsedAssets; this.transitiveParsedAssets = transitiveParsedAssets; this.transitiveAssets = transitiveAssets; this.transitiveSymbols = transitiveSymbols; this.transitiveCompiledSymbols = transitiveCompiledSymbols; } /** Creates a new AndroidAssetInfo using the passed assets as the direct dependency. */ public AndroidAssetsInfo toInfo(MergedAndroidAssets assets) { if (neverlink) { return AndroidAssetsInfo.empty(assets.getLabel()); } NestedSet updatedTransitiveParsedAssets = NestedSetBuilder.naiveLinkOrder() .addTransitive(transitiveParsedAssets) .addTransitive(directParsedAssets) .build(); if (assets.getAssets().isEmpty()) { return AndroidAssetsInfo.of( assets.getLabel(), // Even though no new assets were added, we should still make merging output available so // callers can ensure validation succeeded. assets.getMergedAssets(), NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER), updatedTransitiveParsedAssets, transitiveAssets, transitiveSymbols, transitiveCompiledSymbols); } // Create a new object to avoid passing around unwanted merge information to the provider ParsedAndroidAssets parsedAssets = new ParsedAndroidAssets(assets); NestedSetBuilder transitiveCompiledSymbolsBuilder = NestedSetBuilder.naiveLinkOrder().addTransitive(transitiveCompiledSymbols); if (assets.getCompiledSymbols() != null) { transitiveCompiledSymbolsBuilder.add(assets.getCompiledSymbols()); } return AndroidAssetsInfo.of( assets.getLabel(), assets.getMergedAssets(), NestedSetBuilder.create(Order.NAIVE_LINK_ORDER, parsedAssets), updatedTransitiveParsedAssets, NestedSetBuilder.naiveLinkOrder() .addTransitive(transitiveAssets) .addAll(assets.getAssets()) .build(), NestedSetBuilder.naiveLinkOrder() .addTransitive(transitiveSymbols) .add(assets.getSymbols()) .build(), transitiveCompiledSymbolsBuilder.build()); } /** Creates a new AndroidAssetsInfo from this target's dependencies, without any local assets. */ public AndroidAssetsInfo toInfo(Label label) { if (neverlink) { return AndroidAssetsInfo.empty(label); } return AndroidAssetsInfo.of( label, null, directParsedAssets, transitiveParsedAssets, transitiveAssets, transitiveSymbols, transitiveCompiledSymbols); } public NestedSet getDirectParsedAssets() { return directParsedAssets; } public NestedSet getTransitiveParsedAssets() { return transitiveParsedAssets; } public NestedSet getTransitiveAssets() { return transitiveAssets; } public NestedSet getTransitiveSymbols() { return transitiveSymbols; } public NestedSet getTransitiveCompiledSymbols() { return transitiveCompiledSymbols; } }