aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/ResourceContainer.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/ResourceDependencies.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/ResourceFilter.java234
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java2
5 files changed, 137 insertions, 113 deletions
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 8a28a16a6e..d690366140 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
@@ -453,8 +453,8 @@ public final class ApplicationManifest {
// Filter the resources during analysis to prevent processing of and dependencies on unwanted
// resources during execution.
- resourceContainer = resourceContainer.filter(resourceFilter);
- resourceDeps = resourceDeps.filter(resourceFilter);
+ resourceContainer = resourceContainer.filter(ruleContext, resourceFilter);
+ resourceDeps = resourceDeps.filter(ruleContext, resourceFilter);
ResourceContainer processed;
if (isLibrary && AndroidCommon.getAndroidConfig(ruleContext).useParallelResourceProcessing()) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceContainer.java b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceContainer.java
index a18daa0027..a24d77d333 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceContainer.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceContainer.java
@@ -128,8 +128,8 @@ public abstract class ResourceContainer {
/**
* Returns a copy of this container with filtered resources. The original container is unchanged.
*/
- public ResourceContainer filter(ResourceFilter filter) {
- return toBuilder().setResources(filter.filter(getResources())).build();
+ public ResourceContainer filter(RuleContext ruleContext, ResourceFilter filter) {
+ return toBuilder().setResources(filter.filter(ruleContext, getResources())).build();
}
/** Creates a new builder with default values. */
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
index 72e76c8763..b72e105c5d 100644
--- 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
@@ -153,9 +153,11 @@ public final class ResourceDependencies {
}
/** Returns a copy of this instance with filtered resources. The original object is unchanged. */
- public ResourceDependencies filter(ResourceFilter filter) {
+ public ResourceDependencies filter(RuleContext ruleContext, ResourceFilter filter) {
return new ResourceDependencies(
- neverlink, filter.filter(transitiveResources), filter.filter(directResources));
+ neverlink,
+ filter.filterDependencies(ruleContext, transitiveResources),
+ filter.filterDependencies(ruleContext, directResources));
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceFilter.java b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceFilter.java
index e7652efbba..70e4732049 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceFilter.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceFilter.java
@@ -26,6 +26,7 @@ import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.packages.AttributeMap;
import com.google.devtools.build.lib.syntax.Type;
import java.util.ArrayList;
import java.util.Collection;
@@ -43,73 +44,71 @@ public class ResourceFilter {
public static final String RESOURCE_CONFIGURATION_FILTERS_NAME = "resource_configuration_filters";
public static final String DENSITIES_NAME = "densities";
- /** The current {@link RuleContext}, used for reporting errors. */
- private final RuleContext ruleContext;
+ private static enum FilterBehavior {
+ /**
+ * Resources will be filtered in execution. This class will just pass the filtering parameters
+ * to the appropriate resource processing actions.
+ */
+ FILTER_IN_EXECUTION,
- /**
- * A list of configuration filters that should be applied during the analysis phase. If resources
- * should not be filtered in analysis (e.g., if android_binary.prefilter_resources is set to 0),
- * this list should be empty.
- */
- private final ImmutableList<FolderConfiguration> configurationFilters;
+ /**
+ * Resources will be filtered in analysis. In android_binary targets, all resources will be
+ * filtered by this class, and only resources that are accepted will be passed to resource
+ * processing actions.
+ */
+ FILTER_IN_ANALYSIS,
- /**
- * The value of the {@link #RESOURCE_CONFIGURATION_FILTERS_NAME} attribute, as a list of qualifier
- * strings. This value is passed directly as input to resource processing utilities that run in
- * the execution phase, so it may represent different qualifiers than those in {@link
- * #configurationFilters} if resources should not be pre-filtered during analysis.
- */
- private final ImmutableList<String> configurationFilterStrings;
+ /**
+ * Resources will be filtered in each android target in analysis. Filter settings will be
+ * extracted from android_binary targets and passed to all their dependencies using dynamic
+ * configuration. Only resources that are accepted by filtering will be passed to resource
+ * processing actions or to reverse dependencies.
+ */
+ FILTER_IN_ANALYSIS_WITH_DYNAMIC_CONFIGURATION;
+ }
- /**
- * A list of density filters that should be applied during the analysis phase. If resources should
- * not be filtered in analysis (e.g., if prefilter_resources = 0), this list should be empty.
- */
- private final ImmutableList<Density> densities;
+ static final FilterBehavior DEFAULT_BEHAVIOR = FilterBehavior.FILTER_IN_EXECUTION;
/**
- * The value of the {@link #DENSITIES_NAME} attribute, as a list of qualifier strings. This value
- * is passed directly as input to resource processing utilities that run in the execution phase,
- * so it may represent different qualifiers than those in {@link #densities} if resources should
- * not be pre-filtered during analysis.
+ * The value of the {@link #RESOURCE_CONFIGURATION_FILTERS_NAME} attribute, as a list of qualifier
+ * strings.
*/
- private final ImmutableList<String> densityStrings;
+ private final ImmutableList<String> configFilters;
+ /** The value of the {@link #DENSITIES_NAME} attribute, as a list of qualifier strings. */
+ private final ImmutableList<String> densities;
+
+ /** A builder for a set of strings representing resources that were filtered using this class. */
private final ImmutableSet.Builder<String> filteredResources = ImmutableSet.builder();
+ private final FilterBehavior filterBehavior;
+
/**
* Constructor.
*
- * @param ruleContext the current {@link RuleContext}, used for reporting errors
- * @param configurationFilters a list of configuration filters that should be applied during
- * analysis time. If resources should not be filtered in analysis (e.g., if
- * prefilter_resources = 0), this list should be empty.
- * @param configurationFilterStrings the resource configuration filters, as a list of strings.
- * @param densities a list of densities that should be applied to filter resources during analysis
- * time. If resources should not be filtered in analysis (e.g., if prefilter_resources = 0),
- * this list should be empty.
- * @param densityStrings the densities, as a list of strings.
+ * @param configFilters the resource configuration filters, as a list of strings.
+ * @param densities the density filters, as a list of strings.
+ * @param filterBehavior the behavior of this filter.
*/
private ResourceFilter(
- RuleContext ruleContext,
- ImmutableList<FolderConfiguration> configurationFilters,
- ImmutableList<String> configurationFilterStrings,
- ImmutableList<Density> densities,
- ImmutableList<String> densityStrings) {
- this.ruleContext = ruleContext;
- this.configurationFilters = configurationFilters;
- this.configurationFilterStrings = configurationFilterStrings;
+ ImmutableList<String> configFilters,
+ ImmutableList<String> densities,
+ FilterBehavior filterBehavior) {
+ this.configFilters = configFilters;
this.densities = densities;
- this.densityStrings = densityStrings;
+ this.filterBehavior = filterBehavior;
}
- private static boolean hasAttr(RuleContext ruleContext, String attrName) {
- return ruleContext.attributes().isAttributeValueExplicitlySpecified(attrName);
+ private static boolean hasAttr(AttributeMap attrs, String attrName) {
+ return attrs.isAttributeValueExplicitlySpecified(attrName);
}
static boolean hasFilters(RuleContext ruleContext) {
- return hasAttr(ruleContext, RESOURCE_CONFIGURATION_FILTERS_NAME)
- || hasAttr(ruleContext, DENSITIES_NAME);
+ return hasFilters(ruleContext.attributes());
+ }
+
+ static boolean hasFilters(AttributeMap attrs) {
+ return hasAttr(attrs, RESOURCE_CONFIGURATION_FILTERS_NAME) || hasAttr(attrs, DENSITIES_NAME);
}
/**
@@ -121,8 +120,8 @@ public class ResourceFilter {
*
* @return the values of this attribute contained in the {@link RuleContext}, as a list.
*/
- private static ImmutableList<String> extractFilters(RuleContext ruleContext, String attrName) {
- if (!hasAttr(ruleContext, attrName)) {
+ private static ImmutableList<String> extractFilters(AttributeMap attrs, String attrName) {
+ if (!hasAttr(attrs, attrName)) {
return ImmutableList.<String>of();
}
@@ -136,7 +135,7 @@ public class ResourceFilter {
* empty filter values result in all resources matching the empty filter, meaning that filtering
* does nothing (even if non-empty filters were also provided).
*/
- List<String> rawValues = ruleContext.attributes().get(attrName, Type.STRING_LIST);
+ List<String> rawValues = attrs.get(attrName, Type.STRING_LIST);
ImmutableList.Builder<String> builder = ImmutableList.builder();
for (String rawValue : rawValues) {
@@ -157,43 +156,49 @@ public class ResourceFilter {
static ResourceFilter fromRuleContext(RuleContext ruleContext) {
Preconditions.checkNotNull(ruleContext);
- if (!hasFilters(ruleContext)) {
- return empty(ruleContext);
- }
+ return empty(ruleContext).withAttrsFrom(ruleContext.attributes());
+ }
- ImmutableList<String> resourceConfigurationFilters =
- extractFilters(ruleContext, RESOURCE_CONFIGURATION_FILTERS_NAME);
- ImmutableList<String> densities = extractFilters(ruleContext, DENSITIES_NAME);
+ /**
+ * Creates a new {@link ResourceFilter} based on this object's properties, overridden by any
+ * filters specified in the passed {@link AttributeMap}.
+ *
+ * <p>A new object will always be returned, as returning the same object across multiple rules (as
+ * would be done with {@link FilterBehavior#FILTER_IN_ANALYSIS_WITH_DYNAMIC_CONFIGURATION}) causes
+ * problems.
+ */
+ ResourceFilter withAttrsFrom(AttributeMap attrs) {
+ if (!hasFilters(attrs)) {
+ return new ResourceFilter(configFilters, densities, filterBehavior);
+ }
- boolean usePrefiltering =
- ruleContext.getFragment(AndroidConfiguration.class).useResourcePrefiltering();
+ return new ResourceFilter(
+ extractFilters(attrs, RESOURCE_CONFIGURATION_FILTERS_NAME),
+ extractFilters(attrs, DENSITIES_NAME),
+ filterBehavior);
+ }
+ private ImmutableList<FolderConfiguration> getConfigurationFilters(RuleContext ruleContext) {
ImmutableList.Builder<FolderConfiguration> filterBuilder = ImmutableList.builder();
- if (usePrefiltering) {
- for (String filter : resourceConfigurationFilters) {
- addIfNotNull(
- FolderConfiguration.getConfigForQualifierString(filter),
- filter,
- filterBuilder,
- ruleContext,
- RESOURCE_CONFIGURATION_FILTERS_NAME);
- }
+ for (String filter : configFilters) {
+ addIfNotNull(
+ FolderConfiguration.getConfigForQualifierString(filter),
+ filter,
+ filterBuilder,
+ ruleContext,
+ RESOURCE_CONFIGURATION_FILTERS_NAME);
}
+ return filterBuilder.build();
+ }
+
+ private ImmutableList<Density> getDensities(RuleContext ruleContext) {
ImmutableList.Builder<Density> densityBuilder = ImmutableList.builder();
- if (usePrefiltering) {
- for (String density : densities) {
- addIfNotNull(
- Density.getEnum(density), density, densityBuilder, ruleContext, DENSITIES_NAME);
- }
+ for (String density : densities) {
+ addIfNotNull(Density.getEnum(density), density, densityBuilder, ruleContext, DENSITIES_NAME);
}
- return new ResourceFilter(
- ruleContext,
- filterBuilder.build(),
- resourceConfigurationFilters,
- densityBuilder.build(),
- densities);
+ return densityBuilder.build();
}
/** Reports an attribute error if the given item is null, and otherwise adds it to the builder. */
@@ -212,19 +217,28 @@ public class ResourceFilter {
}
static ResourceFilter empty(RuleContext ruleContext) {
+ if (!ruleContext.isLegalFragment(AndroidConfiguration.class)) {
+ return empty(DEFAULT_BEHAVIOR);
+ }
+
+ FilterBehavior filterBehavior =
+ ruleContext.getFragment(AndroidConfiguration.class).useResourcePrefiltering()
+ ? FilterBehavior.FILTER_IN_ANALYSIS
+ : FilterBehavior.FILTER_IN_EXECUTION;
+ return empty(filterBehavior);
+ }
+
+ private static ResourceFilter empty(FilterBehavior filterBehavior) {
return new ResourceFilter(
- ruleContext,
- ImmutableList.<FolderConfiguration>of(),
- ImmutableList.<String>of(),
- ImmutableList.<Density>of(),
- ImmutableList.<String>of());
+ ImmutableList.<String>of(), ImmutableList.<String>of(), filterBehavior);
}
/**
- * Filters a NestedSet of resource containers. This may be a no-op if this filter is empty or if
- * resource prefiltering is disabled.
+ * Filters a NestedSet of resource containers that contain dependencies of the current rule. This
+ * may be a no-op if this filter is empty or if resource prefiltering is disabled.
*/
- NestedSet<ResourceContainer> filter(NestedSet<ResourceContainer> resources) {
+ NestedSet<ResourceContainer> filterDependencies(
+ RuleContext ruleContext, NestedSet<ResourceContainer> resources) {
if (!isPrefiltering()) {
/*
* If the filter is empty or resource prefiltering is disabled, just return the original,
@@ -245,13 +259,13 @@ public class ResourceFilter {
NestedSetBuilder<ResourceContainer> builder = new NestedSetBuilder<>(resources.getOrder());
for (ResourceContainer resource : resources) {
- builder.add(resource.filter(this));
+ builder.add(resource.filter(ruleContext, this));
}
return builder.build();
}
- ImmutableList<Artifact> filter(ImmutableList<Artifact> artifacts) {
+ ImmutableList<Artifact> filter(RuleContext ruleContext, ImmutableList<Artifact> artifacts) {
if (!isPrefiltering()) {
return artifacts;
}
@@ -263,13 +277,15 @@ public class ResourceFilter {
ImmutableSet.Builder<Artifact> builder = ImmutableSet.builder();
List<BestArtifactsForDensity> bestArtifactsForAllDensities = new ArrayList<>();
- for (Density density : densities) {
- bestArtifactsForAllDensities.add(new BestArtifactsForDensity(density));
+ for (Density density : getDensities(ruleContext)) {
+ bestArtifactsForAllDensities.add(new BestArtifactsForDensity(ruleContext, density));
}
+ ImmutableList<FolderConfiguration> folderConfigs = getConfigurationFilters(ruleContext);
+
for (Artifact artifact : artifacts) {
- FolderConfiguration configuration = getConfigForArtifact(artifact);
- if (!matchesConfigurationFilters(configuration)) {
+ if (!matchesConfigurationFilters(
+ folderConfigs, getConfigForArtifact(ruleContext, artifact))) {
continue;
}
@@ -304,13 +320,15 @@ public class ResourceFilter {
* Tracks the best artifact for a desired density for each combination of filename and non-density
* qualifiers.
*/
- private class BestArtifactsForDensity {
+ private static class BestArtifactsForDensity {
+ private final RuleContext ruleContext;
private final Density desiredDensity;
// Use a LinkedHashMap to preserve determinism.
private final Map<String, Artifact> nameAndConfigurationToBestArtifact = new LinkedHashMap<>();
- public BestArtifactsForDensity(Density density) {
+ public BestArtifactsForDensity(RuleContext ruleContext, Density density) {
+ this.ruleContext = ruleContext;
desiredDensity = density;
}
@@ -319,7 +337,7 @@ public class ResourceFilter {
* other artifacts with the same name and non-density configuration, adds it to this object.
*/
public void maybeAddArtifact(Artifact artifact) {
- FolderConfiguration config = getConfigForArtifact(artifact);
+ FolderConfiguration config = getConfigForArtifact(ruleContext, artifact);
// We want to find a single best artifact for each combination of non-density qualifiers and
// filename. Combine those two values to create a single unique key.
@@ -368,7 +386,8 @@ public class ResourceFilter {
* @return a score for how well the artifact matches. Lower scores indicate better matches.
*/
private double computeAffinity(Artifact artifact) {
- DensityQualifier resourceQualifier = getConfigForArtifact(artifact).getDensityQualifier();
+ DensityQualifier resourceQualifier =
+ getConfigForArtifact(ruleContext, artifact).getDensityQualifier();
if (resourceQualifier == null) {
return Double.MAX_VALUE;
}
@@ -401,7 +420,8 @@ public class ResourceFilter {
}
}
- private FolderConfiguration getConfigForArtifact(Artifact artifact) {
+ private static FolderConfiguration getConfigForArtifact(
+ RuleContext ruleContext, Artifact artifact) {
String containingFolder = getContainingFolder(artifact);
FolderConfiguration config = FolderConfiguration.getConfigForFolder(containingFolder);
@@ -438,14 +458,15 @@ public class ResourceFilter {
return artifact.getPath().getParentDirectory().getBaseName();
}
- private boolean matchesConfigurationFilters(FolderConfiguration config) {
- for (FolderConfiguration filter : configurationFilters) {
+ private static boolean matchesConfigurationFilters(
+ ImmutableList<FolderConfiguration> folderConfigs, FolderConfiguration config) {
+ for (FolderConfiguration filter : folderConfigs) {
if (config.isMatchFor(filter)) {
return true;
}
}
- return configurationFilters.isEmpty();
+ return folderConfigs.isEmpty();
}
/**
@@ -455,11 +476,11 @@ public class ResourceFilter {
* phase.
*/
boolean hasConfigurationFilters() {
- return !configurationFilterStrings.isEmpty();
+ return !configFilters.isEmpty();
}
String getConfigurationFilterString() {
- return Joiner.on(',').join(configurationFilterStrings);
+ return Joiner.on(',').join(configFilters);
}
/**
@@ -469,19 +490,20 @@ public class ResourceFilter {
* phase.
*/
boolean hasDensities() {
- return !densityStrings.isEmpty();
+ return !densities.isEmpty();
}
String getDensityString() {
- return Joiner.on(',').join(densityStrings);
+ return Joiner.on(',').join(densities);
}
List<String> getDensities() {
- return densityStrings;
+ return densities;
}
boolean isPrefiltering() {
- return !densities.isEmpty() || !configurationFilters.isEmpty();
+ return filterBehavior == FilterBehavior.FILTER_IN_ANALYSIS
+ || filterBehavior == FilterBehavior.FILTER_IN_ANALYSIS_WITH_DYNAMIC_CONFIGURATION;
}
/**
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java
index 5cdedf9828..34b5cbbb08 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java
@@ -1115,7 +1115,7 @@ public class AndroidBinaryTest extends AndroidBuildViewTestCase {
badQualifier,
"android_binary(name = 'r',",
" manifest = 'AndroidManifest.xml',",
- " resource_files = glob(['res/**']),",
+ " resource_files = ['res/values/foo.xml'],",
" resource_configuration_filters = ['" + badQualifier + "'])");
}