diff options
author | 2018-03-29 08:57:14 -0700 | |
---|---|---|
committer | 2018-03-29 08:58:22 -0700 | |
commit | 6db5972b93ac1178a2ddee88c56342fc4dcd2c0a (patch) | |
tree | d25f622d2b87e4c8426b825da5d2401f236d8750 | |
parent | 6fc594815dae501077e3b038b256c1f9249b58df (diff) |
Split AndroidAssets class out of LocalResourceContainer
AndroidAssets will be the new home for asset-related code (including, in the
future, from ResourceContainer). This is the first step towards decoupling
Android asset and resource processing. LocalResourceContainer will be replaced
with resource-specific code in the next change.
RELNOTES: none
PiperOrigin-RevId: 190936954
4 files changed, 125 insertions, 51 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidAssets.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidAssets.java new file mode 100644 index 0000000000..10c82988a6 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidAssets.java @@ -0,0 +1,117 @@ +// 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.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact; +import com.google.devtools.build.lib.analysis.FileProvider; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; +import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode; +import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; +import com.google.devtools.build.lib.syntax.Type; +import com.google.devtools.build.lib.vfs.PathFragment; + +/** Wraps this target's Android assets */ +public final class AndroidAssets { + private static final String ASSETS_ATTR = "assets"; + private static final String ASSETS_DIR_ATTR = "assets_dir"; + + static void validateAssetsAndAssetsDir(RuleContext ruleContext) throws RuleErrorException { + if (ruleContext.attributes().isAttributeValueExplicitlySpecified(ASSETS_ATTR) + ^ ruleContext.attributes().isAttributeValueExplicitlySpecified(ASSETS_DIR_ATTR)) { + ruleContext.throwWithRuleError( + String.format( + "'%s' and '%s' should be either both empty or both non-empty", + ASSETS_ATTR, ASSETS_DIR_ATTR)); + } + } + + /** Collects this rule's android assets. */ + public static AndroidAssets from(RuleContext ruleContext) throws RuleErrorException { + validateAssetsAndAssetsDir(ruleContext); + + if (!ruleContext.attributes().has(ASSETS_ATTR)) { + return new AndroidAssets(ImmutableList.of(), ImmutableList.of()); + } + + PathFragment assetsDir = getAssetDir(ruleContext); + + ImmutableList.Builder<Artifact> assets = ImmutableList.builder(); + ImmutableList.Builder<PathFragment> assetRoots = ImmutableList.builder(); + + for (TransitiveInfoCollection target : + ruleContext.getPrerequisitesIf(ASSETS_ATTR, Mode.TARGET, FileProvider.class)) { + for (Artifact file : target.getProvider(FileProvider.class).getFilesToBuild()) { + PathFragment packageFragment = + file.getArtifactOwner().getLabel().getPackageIdentifier().getSourceRoot(); + PathFragment packageRelativePath = file.getRootRelativePath().relativeTo(packageFragment); + if (packageRelativePath.startsWith(assetsDir)) { + PathFragment relativePath = packageRelativePath.relativeTo(assetsDir); + PathFragment path = file.getExecPath(); + assetRoots.add(path.subFragment(0, path.segmentCount() - relativePath.segmentCount())); + } else { + ruleContext.attributeError(ASSETS_ATTR, + String.format( + "'%s' (generated by '%s') is not beneath '%s'", + file.getRootRelativePath(), target.getLabel(), assetsDir)); + throw new RuleErrorException(); + } + assets.add(file); + } + } + + return new AndroidAssets(assets.build(), assetRoots.build()); + } + + static PathFragment getAssetDir(RuleContext ruleContext) { + if (!ruleContext.attributes().has(ASSETS_DIR_ATTR)) { + return PathFragment.EMPTY_FRAGMENT; + } + return PathFragment.create(ruleContext.attributes().get(ASSETS_DIR_ATTR, Type.STRING)); + } + + /** + * Creates a {@link AndroidAssets} containing all the assets in a directory artifact, for use with + * AarImport rules. + * + * <p>In general, {@link #from(RuleContext)} should be used instead, but it can't be for AarImport + * since we don't know about its individual assets at analysis time. + * + * @param assetsDir the tree artifact containing a {@code assets/} directory + */ + static AndroidAssets forAarImport(SpecialArtifact assetsDir) { + Preconditions.checkArgument(assetsDir.isTreeArtifact()); + return new AndroidAssets( + ImmutableList.of(assetsDir), ImmutableList.of(assetsDir.getExecPath().getChild("assets"))); + } + + private final ImmutableList<Artifact> assets; + private final ImmutableList<PathFragment> assetRoots; + + private AndroidAssets(ImmutableList<Artifact> assets, ImmutableList<PathFragment> assetRoots) { + this.assets = assets; + this.assetRoots = assetRoots; + } + + public ImmutableList<Artifact> getAssets() { + return assets; + } + + public ImmutableList<PathFragment> getAssetRoots() { + return assetRoots; + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java index 871e36263c..5834c50b0f 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java @@ -45,7 +45,6 @@ import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.packages.TriState; import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion; -import com.google.devtools.build.lib.rules.android.ResourceContainer.ResourceType; import com.google.devtools.build.lib.rules.cpp.CcLinkParams; import com.google.devtools.build.lib.rules.cpp.CcLinkParamsInfo; import com.google.devtools.build.lib.rules.cpp.CcLinkParamsStore; @@ -791,14 +790,6 @@ public class AndroidCommon { asNeverLink); } - public static PathFragment getAssetDir(RuleContext ruleContext) { - if (ruleContext.attributes().has(ResourceType.ASSETS.getAttribute() + "_dir")) { - return PathFragment.create( - ruleContext.attributes().get(ResourceType.ASSETS.getAttribute() + "_dir", Type.STRING)); - } - return PathFragment.EMPTY_FRAGMENT; - } - /** * Collects Java compilation arguments for this target. * diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java b/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java index f3ecd81b13..ac2a51d376 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java @@ -296,7 +296,7 @@ public final class ApplicationManifest { throws InterruptedException, RuleErrorException { LocalResourceContainer data = LocalResourceContainer.forAssetsAndResources( - ruleContext, "assets", AndroidCommon.getAssetDir(ruleContext), "local_resource_files"); + ruleContext, "assets", AndroidAssets.getAssetDir(ruleContext), "local_resource_files"); ResourceContainer resourceContainer = ResourceContainer.builderFromRule(ruleContext) @@ -447,7 +447,7 @@ public final class ApplicationManifest { throws InterruptedException, RuleErrorException { LocalResourceContainer data = LocalResourceContainer.forAssetsAndResources( - ruleContext, "assets", AndroidCommon.getAssetDir(ruleContext), "resource_files"); + ruleContext, "assets", AndroidAssets.getAssetDir(ruleContext), "resource_files"); // Filter the resources during analysis to prevent processing of dependencies on unwanted // resources during execution. @@ -522,7 +522,7 @@ public final class ApplicationManifest { throws InterruptedException, RuleErrorException { LocalResourceContainer data = LocalResourceContainer.forAssetsAndResources( - ruleContext, "assets", AndroidCommon.getAssetDir(ruleContext), "resource_files"); + ruleContext, "assets", AndroidAssets.getAssetDir(ruleContext), "resource_files"); ResourceFilter resourceFilter = resourceFilterFactory.getResourceFilter(ruleContext, resourceDeps, data); @@ -604,7 +604,7 @@ public final class ApplicationManifest { // resources during execution. LocalResourceContainer data = LocalResourceContainer.forAssetsAndResources( - ruleContext, "assets", AndroidCommon.getAssetDir(ruleContext), "resource_files"); + ruleContext, "assets", AndroidAssets.getAssetDir(ruleContext), "resource_files"); ResourceFilter resourceFilter = ResourceFilterFactory.fromRuleContext(ruleContext) .getResourceFilter(ruleContext, resourceDeps, data); diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/LocalResourceContainer.java b/src/main/java/com/google/devtools/build/lib/rules/android/LocalResourceContainer.java index 68806fcf93..d849166e7a 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/LocalResourceContainer.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/LocalResourceContainer.java @@ -22,13 +22,11 @@ import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.FileProvider; import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.packages.AttributeMap; import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.packages.RuleErrorConsumer; -import com.google.devtools.build.lib.rules.android.ResourceContainer.ResourceType; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.Arrays; import java.util.LinkedHashSet; @@ -85,20 +83,11 @@ public final class LocalResourceContainer { * via {@code ruleContext} */ public static void validateRuleContext(RuleContext ruleContext) throws RuleErrorException { - validateAssetsAndAssetsDir(ruleContext); + AndroidAssets.validateAssetsAndAssetsDir(ruleContext); validateNoAndroidResourcesInSources(ruleContext); validateManifest(ruleContext); } - private static void validateAssetsAndAssetsDir(RuleContext ruleContext) - throws RuleErrorException { - if (ruleContext.attributes().isAttributeValueExplicitlySpecified("assets") - ^ ruleContext.attributes().isAttributeValueExplicitlySpecified("assets_dir")) { - ruleContext.throwWithRuleError( - "'assets' and 'assets_dir' should be either both empty or both non-empty"); - } - } - /** * Validates that there are no targets with resources in the srcs, as they * should not be used with the Android data logic. @@ -138,30 +127,7 @@ public final class LocalResourceContainer { ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), ImmutableList.of()); } - ImmutableList.Builder<Artifact> assets = ImmutableList.builder(); - ImmutableList.Builder<PathFragment> assetRoots = ImmutableList.builder(); - - for (TransitiveInfoCollection target : - ruleContext.getPrerequisitesIf(assetsAttr, Mode.TARGET, FileProvider.class)) { - for (Artifact file : target.getProvider(FileProvider.class).getFilesToBuild()) { - PathFragment packageFragment = - file.getArtifactOwner().getLabel().getPackageIdentifier().getSourceRoot(); - PathFragment packageRelativePath = file.getRootRelativePath().relativeTo(packageFragment); - if (packageRelativePath.startsWith(assetsDir)) { - PathFragment relativePath = packageRelativePath.relativeTo(assetsDir); - PathFragment path = file.getExecPath(); - assetRoots.add(path.subFragment(0, path.segmentCount() - relativePath.segmentCount())); - } else { - ruleContext.attributeError( - ResourceType.ASSETS.getAttribute(), - String.format( - "'%s' (generated by '%s') is not beneath '%s'", - file.getRootRelativePath(), target.getLabel(), assetsDir)); - throw new RuleErrorException(); - } - assets.add(file); - } - } + AndroidAssets assets = AndroidAssets.from(ruleContext); ImmutableList<Artifact> resources = getResources( @@ -170,8 +136,8 @@ public final class LocalResourceContainer { return new LocalResourceContainer( resources, getResourceRoots(ruleContext, resources, resourcesAttr), - assets.build(), - assetRoots.build()); + assets.getAssets(), + assets.getAssetRoots()); } |