diff options
11 files changed, 228 insertions, 475 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/CustomCommandLine.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/CustomCommandLine.java index 584944f0e9..8eed18804e 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/actions/CustomCommandLine.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/CustomCommandLine.java @@ -129,22 +129,6 @@ public final class CustomCommandLine extends CommandLine { } } - private static final class JoinStringsArg extends ArgvFragment { - - private final String delimiter; - private final Iterable<String> strings; - - private JoinStringsArg(String delimiter, Iterable<String> strings) { - this.delimiter = delimiter; - this.strings = CollectionUtils.makeImmutable(strings); - } - - @Override - void eval(ImmutableList.Builder<String> builder) { - builder.add(Joiner.on(delimiter).join(strings)); - } - } - /** * Arguments that intersperse strings between the items in a sequence. There are two forms of * interspersing, and either may be used by this implementation: @@ -277,14 +261,6 @@ public final class CustomCommandLine extends CommandLine { return this; } - public Builder addJoinStrings(String arg, String delimiter, Iterable<String> strings) { - if (arg != null && strings != null) { - arguments.add(new ObjectArg(arg)); - arguments.add(new JoinStringsArg(delimiter, strings)); - } - return this; - } - public Builder addJoinExecPaths(String arg, String delimiter, Iterable<Artifact> artifacts) { if (arg != null && artifacts != null) { arguments.add(new ObjectArg(arg)); diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java index 6c8fd51b0b..876d796fc8 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java @@ -49,6 +49,7 @@ import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.packages.BuildType; import com.google.devtools.build.lib.packages.TriState; import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory; +import com.google.devtools.build.lib.rules.android.AndroidResourcesProvider.ResourceContainer; import com.google.devtools.build.lib.rules.android.AndroidRuleClasses.MultidexMode; import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider; import com.google.devtools.build.lib.rules.cpp.CppHelper; @@ -96,19 +97,11 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { AndroidCommon androidCommon = new AndroidCommon( ruleContext, javaCommon, true /* asNeverLink */, true /* exportDeps */); try { - ResourceDependencies resourceDeps = LocalResourceContainer.definesAndroidResources( - ruleContext.attributes()) - ? ResourceDependencies.fromRuleDeps(ruleContext) - : ResourceDependencies.fromRuleResourceAndDeps(ruleContext); - RuleConfiguredTargetBuilder builder = init( - ruleContext, - filesBuilder, - resourceDeps, - javaCommon, - androidCommon, - javaSemantics, - androidSemantics, - ImmutableList.<String>of("deps")); + RuleConfiguredTargetBuilder builder = + init(ruleContext, filesBuilder, + AndroidCommon.getTransitiveResourceContainers(ruleContext, true), + javaCommon, androidCommon, javaSemantics, androidSemantics, + ImmutableList.<String>of("deps")); if (builder == null) { return null; } @@ -123,7 +116,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { private static RuleConfiguredTargetBuilder init( RuleContext ruleContext, NestedSetBuilder<Artifact> filesBuilder, - ResourceDependencies resourceDeps, + NestedSet<ResourceContainer> resourceContainers, JavaCommon javaCommon, AndroidCommon androidCommon, JavaSemantics javaSemantics, @@ -190,11 +183,11 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { throw new RuleConfigurationException(); } applicationManifest = androidSemantics.getManifestForRule(ruleContext) - .mergeWith(ruleContext, resourceDeps); + .mergeWith(ruleContext, resourceContainers); resourceApk = applicationManifest.packWithDataAndResources( ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_APK), ruleContext, - resourceDeps, + resourceContainers, null, /* Artifact rTxt */ null, /* Artifact symbolsTxt */ ruleContext.getTokenizedStringListAttr("resource_configuration_filters"), @@ -208,7 +201,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { .packWithDataAndResources(ruleContext .getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_INCREMENTAL_RESOURCES_APK), ruleContext, - resourceDeps, + resourceContainers, null, /* Artifact rTxt */ null, /* Artifact symbolsTxt */ ruleContext.getTokenizedStringListAttr("resource_configuration_filters"), @@ -222,7 +215,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { .createSplitManifest(ruleContext, "android_resources", false) .packWithDataAndResources(getDxArtifact(ruleContext, "android_resources.ap_"), ruleContext, - resourceDeps, + resourceContainers, null, /* Artifact rTxt */ null, /* Artifact symbolsTxt */ ruleContext.getTokenizedStringListAttr("resource_configuration_filters"), @@ -236,13 +229,13 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { // Retrieve the resources from the resources attribute on the android_binary rule // and recompile them if necessary. applicationManifest = ApplicationManifest.fromResourcesRule(ruleContext).mergeWith( - ruleContext, resourceDeps); + ruleContext, resourceContainers); // Always recompiling resources causes AndroidTest to fail in certain circumstances. - if (shouldRegenerate(ruleContext, resourceDeps)) { + if (shouldRegenerate(ruleContext, resourceContainers)) { resourceApk = applicationManifest.packWithResources( ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_APK), ruleContext, - resourceDeps, + resourceContainers, true, getProguardConfigArtifact(ruleContext, "")); } else { @@ -255,7 +248,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { ruleContext.getImplicitOutputArtifact( AndroidRuleClasses.ANDROID_INCREMENTAL_RESOURCES_APK), ruleContext, - resourceDeps, + resourceContainers, false, getProguardConfigArtifact(ruleContext, "incremental")); @@ -263,7 +256,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { .createSplitManifest(ruleContext, "android_resources", false) .packWithResources(getDxArtifact(ruleContext, "android_resources.ap_"), ruleContext, - resourceDeps, + resourceContainers, false, getProguardConfigArtifact(ruleContext, "incremental_split")); } @@ -1279,8 +1272,8 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { * </ul> */ public static boolean shouldRegenerate(RuleContext ruleContext, - ResourceDependencies resourceDeps) { - return Iterables.size(resourceDeps.getResources()) > 1 + Iterable<ResourceContainer> resourceContainers) { + return Iterables.size(resourceContainers) > 1 || ruleContext.attributes().isAttributeValueExplicitlySpecified("densities") || ruleContext.attributes().isAttributeValueExplicitlySpecified( "resource_configuration_filters") 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 2712eb298e..59f7ac7770 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 @@ -95,6 +95,7 @@ public class AndroidCommon { private Artifact genClassJar; private Artifact genSourceJar; + private NestedSet<ResourceContainer> transitiveResources; private boolean asNeverLink; private boolean exportDeps; private Artifact manifestProtoOutput; @@ -258,11 +259,36 @@ public class AndroidCommon { return jackCompilationHelper.compileAsDex(mode, mainDexList, proguardSpecs); } + public static NestedSet<ResourceContainer> getTransitiveResourceContainers( + RuleContext ruleContext, boolean withDeps) { + // Traverse through all android_library targets looking for resources + NestedSetBuilder<ResourceContainer> resourcesBuilder = NestedSetBuilder.naiveLinkOrder(); + List<String> attributes = new ArrayList<>(); + attributes.add("resources"); + if (withDeps) { + attributes.add("deps"); + } + + for (String attribute : attributes) { + if (!ruleContext.attributes().has(attribute, BuildType.LABEL) + && !ruleContext.attributes().has(attribute, BuildType.LABEL_LIST)) { + continue; + } + + for (AndroidResourcesProvider resources : + ruleContext.getPrerequisites(attribute, Mode.TARGET, AndroidResourcesProvider.class)) { + resourcesBuilder.addTransitive(resources.getTransitiveAndroidResources()); + } + } + + return resourcesBuilder.build(); + } + private void compileResources( JavaSemantics javaSemantics, JavaCompilationArtifacts.Builder artifactsBuilder, JavaTargetAttributes.Builder attributes, - ResourceDependencies resourceDeps, + NestedSet<ResourceContainer> resourceContainers, ResourceContainer updatedResources) throws InterruptedException { Artifact binaryResourcesJar = ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_CLASS_JAR); @@ -273,7 +299,7 @@ public class AndroidCommon { // Repackages the R.java for each dependency package and places the resultant jars // before the dependency libraries to ensure that the generated resource ids are // correct. - createJarJarActions(attributes, resourceDeps.getResources(), + createJarJarActions(attributes, resourceContainers, updatedResources.getJavaPackage(), binaryResourcesJar); } @@ -369,11 +395,12 @@ public class AndroidCommon { JavaTargetAttributes.Builder attributes = init( androidSemantics, + resourceApk.getTransitiveResources(), extraSourcesBuilder.build()); JavaCompilationArtifacts.Builder artifactsBuilder = new JavaCompilationArtifacts.Builder(); if (resourceApk.isLegacy()) { compileResources(javaSemantics, artifactsBuilder, attributes, - resourceApk.getResourceDependencies(), resourceApk.getPrimaryResource()); + resourceApk.getTransitiveResources(), resourceApk.getPrimaryResource()); } JavaCompilationHelper helper = initAttributes(attributes, javaSemantics); @@ -404,9 +431,12 @@ public class AndroidCommon { private JavaTargetAttributes.Builder init( AndroidSemantics androidSemantics, + NestedSet<AndroidResourcesProvider.ResourceContainer> transitiveResources, Collection<Artifact> extraArtifacts) { + this.transitiveResources = transitiveResources; javaCommon.initializeJavacOpts(androidSemantics.getJavacArguments()); JavaTargetAttributes.Builder attributes = javaCommon.initCommon(extraArtifacts); + attributes.setBootClassPath(ImmutableList.of( AndroidSdkProvider.fromRuleContext(ruleContext).getAndroidJar())); return attributes; @@ -568,7 +598,8 @@ public class AndroidCommon { new JavaRuntimeJarProvider(javaCommon.getJavaCompilationArtifacts().getRuntimeJars())) .add(RunfilesProvider.class, RunfilesProvider.simple(runfiles)) .add( - AndroidResourcesProvider.class, resourceApk.toResourceProvider(ruleContext.getLabel())) + AndroidResourcesProvider.class, + new AndroidResourcesProvider(ruleContext.getLabel(), transitiveResources)) .add( AndroidIdeInfoProvider.class, createAndroidIdeInfoProvider(ruleContext, androidSemantics, idlHelper, diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java index 0eec811d57..bb90189242 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java @@ -62,6 +62,8 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory { List<? extends TransitiveInfoCollection> deps = ruleContext.getPrerequisites("deps", Mode.TARGET); checkResourceInlining(ruleContext); + NestedSet<AndroidResourcesProvider.ResourceContainer> transitiveResources = + AndroidCommon.getTransitiveResourceContainers(ruleContext, true); NestedSetBuilder<Aar> transitiveAars = collectTransitiveAars(ruleContext); NestedSet<LinkerInput> transitiveNativeLibraries = AndroidCommon.collectTransitiveNativeLibraries(deps); @@ -82,8 +84,7 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory { try { resourceApk = applicationManifest.packWithDataAndResources( ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_APK), - ruleContext, - ResourceDependencies.fromRuleDeps(ruleContext), + ruleContext, transitiveResources, ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT), ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_SYMBOLS_TXT), ImmutableList.<String>of(), /* configurationFilters */ @@ -101,8 +102,7 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory { return null; } } else { - resourceApk = ResourceApk.fromTransitiveResources( - ResourceDependencies.fromRuleResourceAndDeps(ruleContext)); + resourceApk = ResourceApk.fromTransitiveResources(transitiveResources); } JavaTargetAttributes javaTargetAttributes = androidCommon.init( @@ -129,7 +129,7 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory { transitiveAars.add(aar); } else if (AndroidCommon.getAndroidResources(ruleContext) != null) { primaryResources = Iterables.getOnlyElement( - AndroidCommon.getAndroidResources(ruleContext).getDirectAndroidResources()); + AndroidCommon.getAndroidResources(ruleContext).getTransitiveAndroidResources()); aar = new Aar(aarOut, primaryResources.getManifest()); transitiveAars.add(aar); } else { @@ -157,7 +157,7 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory { .setSourceJarOut(resourceContainer.getJavaSourceJar()) .setJavaPackage(resourceContainer.getJavaPackage()) .withPrimary(resourceContainer) - .withDependencies(resourceApk.getResourceDependencies()) + .withDependencies(transitiveResources) .setDebug( ruleContext.getConfiguration().getCompilationMode() != CompilationMode.OPT) .build(ruleContext); @@ -172,8 +172,8 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory { .build(ruleContext); RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(ruleContext); - androidCommon.addTransitiveInfoProviders(builder, androidSemantics, resourceApk, null, - ImmutableList.<Artifact>of()); + androidCommon.addTransitiveInfoProviders(builder, androidSemantics, + definesLocalResources ? resourceApk : null, null, ImmutableList.<Artifact>of()); androidSemantics.addTransitiveInfoProviders( builder, ruleContext, javaCommon, androidCommon, null); @@ -220,7 +220,7 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory { } ResourceContainer container = Iterables.getOnlyElement( - resources.getDirectAndroidResources()); + resources.getTransitiveAndroidResources()); if (container.getConstantsInlined() && !container.getArtifacts(ResourceType.RESOURCES).isEmpty()) { diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java index 2e1c274004..0fa9ecd291 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java @@ -14,11 +14,9 @@ package com.google.devtools.build.lib.rules.android; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.base.Joiner; import com.google.common.base.Strings; -import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Iterators; @@ -26,11 +24,7 @@ import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; import com.google.devtools.build.lib.analysis.actions.SpawnAction; -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; import com.google.devtools.build.lib.rules.android.AndroidResourcesProvider.ResourceType; @@ -38,25 +32,13 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import javax.annotation.Nullable; - /** * Builder for creating resource processing action. */ public class AndroidResourcesProcessorBuilder { - private static final ResourceContainerToArtifacts RESOURCE_CONTAINER_TO_ARTIFACTS = - new ResourceContainerToArtifacts(false); - - private static final ResourceContainerToArtifacts RESOURCE_DEP_TO_ARTIFACTS = - new ResourceContainerToArtifacts(true); - - private static final ResourceContainerToArg RESOURCE_CONTAINER_TO_ARG = - new ResourceContainerToArg(false); - private static final ResourceContainerToArg RESOURCE_DEP_TO_ARG = - new ResourceContainerToArg(true); private ResourceContainer primary; - private ResourceDependencies dependencies; + private List<ResourceContainer> dependencies = Collections.emptyList(); private Artifact proguardOut; private Artifact rTxtOut; private Artifact sourceJarOut; @@ -93,8 +75,8 @@ public class AndroidResourcesProcessorBuilder { return this; } - public AndroidResourcesProcessorBuilder withDependencies(ResourceDependencies resourceDeps) { - this.dependencies = resourceDeps; + public AndroidResourcesProcessorBuilder withDependencies(Iterable<ResourceContainer> nestedSet) { + this.dependencies = ImmutableList.copyOf(nestedSet); return this; } @@ -149,179 +131,160 @@ public class AndroidResourcesProcessorBuilder { return this; } - private static class ResourceContainerToArg implements Function<ResourceContainer, String> { - private boolean includeSymbols; - - public ResourceContainerToArg(boolean includeSymbols) { - this.includeSymbols = includeSymbols; - } - - @Override - public String apply(ResourceContainer container) { - StringBuilder builder = new StringBuilder(); - builder.append(convertRoots(container, ResourceType.RESOURCES)) - .append(":") - .append(convertRoots(container, ResourceType.ASSETS)) - .append(":") - .append(container.getManifest().getExecPathString()); - if (includeSymbols) { - builder.append(":") - .append(container.getRTxt() == null ? "" : container.getRTxt().getExecPath()) - .append(":") - .append( - container.getSymbolsTxt() == null ? "" : container.getSymbolsTxt().getExecPath()); - } - return builder.toString(); - } + private void addResourceContainer(List<Artifact> inputs, List<String> args, + ResourceContainer container) { + Iterables.addAll(inputs, container.getArtifacts()); + inputs.add(container.getManifest()); + inputs.add(container.getRTxt()); + + args.add(String.format("%s:%s:%s:%s:%s", + convertRoots(container, ResourceType.RESOURCES), + convertRoots(container, ResourceType.ASSETS), + container.getManifest().getExecPathString(), + container.getRTxt() == null ? "" : container.getRTxt().getExecPath(), + container.getSymbolsTxt() == null ? "" : container.getSymbolsTxt().getExecPath() + )); } - private static class ResourceContainerToArtifacts - implements Function<ResourceContainer, NestedSet<Artifact>> { - - private boolean includeSymbols; - - public ResourceContainerToArtifacts(boolean includeSymbols) { - this.includeSymbols = includeSymbols; - } - - @Override - public NestedSet<Artifact> apply(ResourceContainer container) { - NestedSetBuilder<Artifact> artifacts = NestedSetBuilder.naiveLinkOrder(); - addIfNotNull(container.getManifest(), artifacts); - if (includeSymbols) { - addIfNotNull(container.getRTxt(), artifacts); - addIfNotNull(container.getSymbolsTxt(), artifacts); - } - artifacts.addAll(container.getArtifacts()); - return artifacts.build(); - } - - private void addIfNotNull(@Nullable Artifact artifact, NestedSetBuilder<Artifact> artifacts) { - if (artifact != null) { - artifacts.add(artifact); - } - } + private void addPrimaryResourceContainer(List<Artifact> inputs, List<String> args, + ResourceContainer container) { + Iterables.addAll(inputs, container.getArtifacts()); + inputs.add(container.getManifest()); + + // no R.txt, because it will be generated from this action. + args.add(String.format("%s:%s:%s", + convertRoots(container, ResourceType.RESOURCES), + convertRoots(container, ResourceType.ASSETS), + container.getManifest().getExecPathString() + )); } @VisibleForTesting public static String convertRoots(ResourceContainer container, ResourceType resourceType) { - return Joiner.on("#").join(Iterators.transform( - container.getRoots(resourceType).iterator(), Functions.toStringFunction())); + return Joiner.on("#").join( + Iterators.transform( + container.getRoots(resourceType).iterator(), Functions.toStringFunction())); } public ResourceContainer build(ActionConstructionContext context) { List<Artifact> outs = new ArrayList<>(); - CustomCommandLine.Builder builder = new CustomCommandLine.Builder(); + List<Artifact> ins = new ArrayList<>(); + List<String> args = new ArrayList<>(); + + args.add("--aapt"); + args.add(sdk.getAapt().getExecutable().getExecPathString()); - builder.addExecPath("--aapt", sdk.getAapt().getExecutable()); - // Use a FluentIterable to avoid flattening the NestedSets - NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder(); - inputs.addAll(ruleContext.getExecutablePrerequisite("$android_resources_processor", Mode.HOST) + Iterables.addAll(ins, + ruleContext.getExecutablePrerequisite("$android_resources_processor", Mode.HOST) .getRunfilesSupport() .getRunfilesArtifactsWithoutMiddlemen()); - builder.addExecPath("--annotationJar", sdk.getAnnotationsJar()); - inputs.add(sdk.getAnnotationsJar()); - - builder.addExecPath("--androidJar", sdk.getAndroidJar()); - inputs.add(sdk.getAndroidJar()); - - builder.add("--primaryData").add(RESOURCE_CONTAINER_TO_ARG.apply(primary)); - inputs.addTransitive(RESOURCE_CONTAINER_TO_ARTIFACTS.apply(primary)); - - if (dependencies != null) { - // add transitive data - builder.addJoinStrings("--data", ",", - Iterables.transform(dependencies.getTransitiveResources(), RESOURCE_DEP_TO_ARG)); - // add direct data - builder.addJoinStrings("--directData", ",", - Iterables.transform(dependencies.getDirectResources(), RESOURCE_DEP_TO_ARG)); - - // This flattens the nested set. Since each ResourceContainer needs to be transformed into - // Artifacts, and the NestedSetBuilder.wrap doesn't support lazy Iterator evaluation - // and SpawnActionBuilder.addInputs evaluates Iterables, it becomes necessary to make the - // best effort and let it get flattened. - inputs.addTransitive( - NestedSetBuilder.wrap( - Order.NAIVE_LINK_ORDER, - FluentIterable.from(dependencies.getResources()) - .transformAndConcat(RESOURCE_DEP_TO_ARTIFACTS))); + args.add("--annotationJar"); + args.add(sdk.getAnnotationsJar().getExecPathString()); + ins.add(sdk.getAnnotationsJar()); + args.add("--androidJar"); + args.add(sdk.getAndroidJar().getExecPathString()); + ins.add(sdk.getAndroidJar()); + + args.add("--primaryData"); + addPrimaryResourceContainer(ins, args, primary); + if (!dependencies.isEmpty()) { + args.add("--data"); + List<String> data = new ArrayList<>(); + for (ResourceContainer container : dependencies) { + addResourceContainer(ins, data, container); + } + args.add(Joiner.on(",").join(data)); } if (rTxtOut != null) { - builder.addExecPath("--rOutput", rTxtOut); + args.add("--rOutput"); + args.add(rTxtOut.getExecPathString()); outs.add(rTxtOut); // If R.txt is not null, dependency R.javas will not be regenerated from the R.txt found in // the deps, which means the resource processor needs to be told it is creating a library so // that it will generate the R.txt. - builder.add("--packageType").add("LIBRARY"); + args.add("--packageType"); + args.add("LIBRARY"); } - if (symbolsTxt != null) { - builder.addExecPath("--symbolsTxtOut", symbolsTxt); + args.add("--symbolsTxtOut"); + args.add(symbolsTxt.getExecPathString()); outs.add(symbolsTxt); } if (sourceJarOut != null) { - builder.addExecPath("--srcJarOutput", sourceJarOut); + args.add("--srcJarOutput"); + args.add(sourceJarOut.getExecPathString()); outs.add(sourceJarOut); } if (proguardOut != null) { - builder.addExecPath("--proguardOutput", proguardOut); + args.add("--proguardOutput"); + args.add(proguardOut.getExecPathString()); outs.add(proguardOut); } if (apkOut != null) { - builder.addExecPath("--packagePath", apkOut); + args.add("--packagePath"); + args.add(apkOut.getExecPathString()); outs.add(apkOut); } if (!resourceConfigs.isEmpty()) { - builder.addJoinStrings("--resourceConfigs", ",", resourceConfigs); + args.add("--resourceConfigs"); + args.add(Joiner.on(',').join(resourceConfigs)); } if (!densities.isEmpty()) { - builder.addJoinStrings("--densities", "'", densities); + args.add("--densities"); + args.add(Joiner.on(',').join(densities)); } if (!uncompressedExtensions.isEmpty()) { - builder.addJoinStrings("--uncompressedExtensions", ",", uncompressedExtensions); + args.add("--uncompressedExtensions"); + args.add(Joiner.on(',').join(uncompressedExtensions)); } if (!assetsToIgnore.isEmpty()) { - builder.addJoinStrings("--assetsToIgnore", ",", assetsToIgnore); + args.add("--assetsToIgnore"); + args.add( + Joiner.on(',').join(assetsToIgnore)); } if (debug) { - builder.add("--debug"); + args.add("--debug"); } if (versionCode != null) { - builder.add("--versionCode").add(versionCode); + args.add("--versionCode"); + args.add(versionCode); } if (versionName != null) { - builder.add("--versionName").add(versionName); + args.add("--versionName"); + args.add(versionName); } if (applicationId != null) { - builder.add("--applicationId").add(applicationId); + args.add("--applicationId"); + args.add(applicationId); } if (!Strings.isNullOrEmpty(customJavaPackage)) { // Sets an alternative java package for the generated R.java // this is allows android rules to generate resources outside of the java{,tests} tree. - builder.add("--packageForR").add(customJavaPackage); + args.add("--packageForR"); + args.add(customJavaPackage); } // Create the spawn action. - ruleContext.registerAction( - this.spawnActionBuilder - .addTool(sdk.getAapt()) - .addTransitiveInputs(inputs.build()) - .addOutputs(ImmutableList.<Artifact>copyOf(outs)) - .setCommandLine(builder.build()) - .setExecutable( - ruleContext.getExecutablePrerequisite("$android_resources_processor", Mode.HOST)) - .setProgressMessage("Processing resources") - .setMnemonic("AndroidAapt") - .build(context)); + ruleContext.registerAction(this.spawnActionBuilder + .addTool(sdk.getAapt()) + .addInputs(ImmutableList.<Artifact>copyOf(ins)) + .addOutputs(ImmutableList.<Artifact>copyOf(outs)) + .addArguments(ImmutableList.<String>copyOf(args)) + .setExecutable( + ruleContext.getExecutablePrerequisite("$android_resources_processor", Mode.HOST)) + .setProgressMessage("Processing resources") + .setMnemonic("AndroidAapt") + .build(context)); // Return the full set of processed transitive dependencies. - return new ResourceContainer(primary.getLabel(), + return new ResourceContainer( + primary.getLabel(), primary.getJavaPackage(), primary.getRenameManifestPackage(), primary.getConstantsInlined(), @@ -330,7 +293,8 @@ public class AndroidResourcesProcessorBuilder { // for this resource processing action (in case of just creating an R.txt or // proguard merging), reuse the primary resource from the dependencies. apkOut != null ? apkOut : primary.getApk(), - primary.getManifest(), sourceJarOut, + primary.getManifest(), + sourceJarOut, primary.getArtifacts(ResourceType.ASSETS), primary.getArtifacts(ResourceType.RESOURCES), primary.getRoots(ResourceType.ASSETS), diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProvider.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProvider.java index 24e3174a42..e2fda51aba 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProvider.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProvider.java @@ -28,50 +28,43 @@ import java.util.Objects; import javax.annotation.Nullable; /** - * A provider that supplies ResourceContainers from its transitive closure. + * A provider that supplies Android resources from its transitive closure. */ @Immutable public final class AndroidResourcesProvider implements TransitiveInfoProvider { + private final Label label; private final NestedSet<ResourceContainer> transitiveAndroidResources; - private final NestedSet<ResourceContainer> directAndroidResources; - public AndroidResourcesProvider( - Label label, NestedSet<ResourceContainer> transitiveAndroidResources, - NestedSet<ResourceContainer> directAndroidResources) { + public AndroidResourcesProvider(Label label, + NestedSet<ResourceContainer> transitiveAndroidResources) { this.label = label; - this.directAndroidResources = directAndroidResources; this.transitiveAndroidResources = transitiveAndroidResources; } /** * Returns the label that is associated with this piece of information. + * + * <p> + * This is usually the label of the target that provides the information. */ public Label getLabel() { return label; } /** - * Returns the transitive ResourceContainers for the label. + * Returns transitive Android resources (APK, assets, etc.). */ public NestedSet<ResourceContainer> getTransitiveAndroidResources() { return transitiveAndroidResources; } - /** - * Returns the immediate ResourceContainers for the label. - */ - public NestedSet<ResourceContainer> getDirectAndroidResources() { - return directAndroidResources; - } - /** * The type of resource in question: either asset or a resource. */ public enum ResourceType { - ASSETS("assets"), - RESOURCES("resources"); + ASSETS("assets"), RESOURCES("resources"); private final String attribute; @@ -90,6 +83,7 @@ public final class AndroidResourcesProvider implements TransitiveInfoProvider { */ @Immutable public static final class ResourceContainer { + private final Label label; private final String javaPackage; private final String renameManifestPackage; @@ -108,8 +102,10 @@ public final class AndroidResourcesProvider implements TransitiveInfoProvider { public ResourceContainer(Label label, String javaPackage, @Nullable String renameManifestPackage, - boolean constantsInlined, Artifact apk, - Artifact manifest, Artifact javaSourceJar, + boolean constantsInlined, + Artifact apk, + Artifact manifest, + Artifact javaSourceJar, ImmutableList<Artifact> assets, ImmutableList<Artifact> resources, ImmutableList<PathFragment> assetsRoots, @@ -188,7 +184,7 @@ public final class AndroidResourcesProvider implements TransitiveInfoProvider { @Override public int hashCode() { - return Objects.hash(label, rTxt, symbolsTxt); + return Objects.hashCode(label); } @Override @@ -200,20 +196,7 @@ public final class AndroidResourcesProvider implements TransitiveInfoProvider { return false; } ResourceContainer other = (ResourceContainer) obj; - return Objects.equals(label, other.label) - && Objects.equals(rTxt, other.rTxt) - && Objects.equals(symbolsTxt, other.symbolsTxt); - } - - @Override - public String toString() { - return String.format( - "ResourceContainer [label=%s, javaPackage=%s, renameManifestPackage=%s," - + " constantsInlined=%s, apk=%s, manifest=%s, assets=%s, resources=%s, assetsRoots=%s," - + " resourcesRoots=%s, manifestExported=%s, javaSourceJar=%s, rTxt=%s, symbolsTxt=%s]", - label, javaPackage, renameManifestPackage, constantsInlined, apk, manifest, assets, - resources, assetsRoots, resourcesRoots, manifestExported, javaSourceJar, rTxt, - symbolsTxt); + return label.equals(other.label); } } } 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 42ffbae043..3c14b8ec6e 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 @@ -26,6 +26,9 @@ import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; import com.google.devtools.build.lib.analysis.actions.FileWriteAction; import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.analysis.config.CompilationMode; +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; import com.google.devtools.build.lib.rules.android.AndroidResourcesProvider.ResourceType; import com.google.devtools.build.lib.rules.android.LocalResourceContainer.Builder.InvalidAssetPath; @@ -45,7 +48,7 @@ public final class ApplicationManifest { throw new RuleConfigurationException(); } return new ApplicationManifest(Iterables.getOnlyElement( - resources.getDirectAndroidResources()) + resources.getTransitiveAndroidResources()) .getManifest()); } @@ -88,7 +91,7 @@ public final class ApplicationManifest { AndroidResourcesProvider resourcesProvider = AndroidCommon.getAndroidResources(ruleContext); if (resourcesProvider != null) { ResourceContainer resourceContainer = Iterables.getOnlyElement( - resourcesProvider.getDirectAndroidResources()); + resourcesProvider.getTransitiveAndroidResources()); return resourceContainer.getRenameManifestPackage(); } else { return null; @@ -165,10 +168,9 @@ public final class ApplicationManifest { } public ApplicationManifest mergeWith(RuleContext ruleContext, - ResourceDependencies resourceDeps) { - Iterable<Artifact> mergeeManifests = getMergeeManifests(resourceDeps.getResources()); - if (!Iterables.isEmpty(mergeeManifests)) { - Iterable<Artifact> exportedManifests = mergeeManifests; + Iterable<ResourceContainer> resourceContainers) { + if (!Iterables.isEmpty(getMergeeManifests(resourceContainers))) { + Iterable<Artifact> exportedManifests = getMergeeManifests(resourceContainers); Artifact outputManifest = ruleContext.getUniqueDirectoryArtifact( ruleContext.getRule().getName() + "_merged", "AndroidManifest.xml", ruleContext.getBinOrGenfilesDirectory()); @@ -196,7 +198,7 @@ public final class ApplicationManifest { public ResourceApk packWithAssets( Artifact resourceApk, RuleContext ruleContext, - ResourceDependencies resourceDeps, + NestedSet<ResourceContainer> resourceContainers, Artifact rTxt, boolean incremental, Artifact proguardCfg) throws InterruptedException { @@ -212,7 +214,7 @@ public final class ApplicationManifest { return createApk(resourceApk, ruleContext, - resourceDeps, + resourceContainers, rTxt, null, /* configurationFilters */ ImmutableList.<String>of(), /* uncompressedExtensions */ @@ -235,7 +237,7 @@ public final class ApplicationManifest { public ResourceApk packWithDataAndResources( Artifact resourceApk, RuleContext ruleContext, - ResourceDependencies resourceDeps, + NestedSet<ResourceContainer> resourceContainers, Artifact rTxt, Artifact symbolsTxt, List<String> configurationFilters, @@ -262,7 +264,7 @@ public final class ApplicationManifest { return createApk(resourceApk, ruleContext, - resourceDeps, + resourceContainers, rTxt, symbolsTxt, configurationFilters, @@ -285,7 +287,7 @@ public final class ApplicationManifest { private ResourceApk createApk(Artifact resourceApk, RuleContext ruleContext, - ResourceDependencies resourceDeps, + NestedSet<ResourceContainer> resourceContainers, Artifact rTxt, Artifact symbolsTxt, List<String> configurationFilters, @@ -303,10 +305,7 @@ public final class ApplicationManifest { .withROutput(rTxt) .withSymbolsFile(symbolsTxt) .buildFromRule(ruleContext, resourceApk), - resourceDeps.getResources(), // TODO(bazel-team): Figure out if we really need to check - // the ENTIRE transitive closure, or just the direct dependencies. Given that each rule with - // resources would check for inline resources, we can rely on the previous rule to have - // checked its dependencies. + resourceContainers, ruleContext); AndroidResourcesProcessorBuilder builder = @@ -317,7 +316,7 @@ public final class ApplicationManifest { .setJavaPackage(resourceContainer.getJavaPackage()) .setDebug(ruleContext.getConfiguration().getCompilationMode() != CompilationMode.OPT) .withPrimary(resourceContainer) - .withDependencies(resourceDeps) + .withDependencies(resourceContainers) .setDensities(densities) .setProguardOut(proguardCfg) .setApplicationId(applicationId) @@ -332,9 +331,16 @@ public final class ApplicationManifest { } ResourceContainer processed = builder.build(ruleContext); + NestedSet<ResourceContainer> transitiveResources = + NestedSetBuilder.<ResourceContainer>naiveLinkOrder() + // TODO(bazel-team): If this is replaced with .addTransitive(), a few tests fail. + // Investigate. + .addAll(resourceContainers) + .add(processed) + .build(); return new ResourceApk( - resourceApk, processed.getJavaSourceJar(), resourceDeps, processed, manifest, + resourceApk, processed.getJavaSourceJar(), transitiveResources, processed, manifest, proguardCfg, false); } @@ -357,7 +363,15 @@ public final class ApplicationManifest { /** Uses the resource apk from the resources attribute, as opposed to recompiling. */ public ResourceApk useCurrentResources(RuleContext ruleContext, Artifact proguardCfg) { ResourceContainer resourceContainer = Iterables.getOnlyElement( - AndroidCommon.getAndroidResources(ruleContext).getDirectAndroidResources()); + AndroidCommon.getAndroidResources(ruleContext).getTransitiveAndroidResources()); + NestedSet<ResourceContainer> resourceContainers = + NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER); + + NestedSet<ResourceContainer> transitiveResources = + NestedSetBuilder.<ResourceContainer>naiveLinkOrder() + .addAll(resourceContainers) + .add(resourceContainer) + .build(); new AndroidAaptActionHelper( ruleContext, @@ -367,7 +381,7 @@ public final class ApplicationManifest { return new ResourceApk( resourceContainer.getApk(), null /* javaSrcJar */, - ResourceDependencies.empty(), + transitiveResources, resourceContainer, manifest, proguardCfg, @@ -384,7 +398,7 @@ public final class ApplicationManifest { public ResourceApk packWithResources( Artifact resourceApk, RuleContext ruleContext, - ResourceDependencies resourceDeps, + NestedSet<ResourceContainer> resourceContainers, boolean createSource, Artifact proguardCfg) throws InterruptedException { @@ -392,15 +406,10 @@ public final class ApplicationManifest { ruleContext.getPrerequisite("resources", Mode.TARGET); ResourceContainer resourceContainer = Iterables.getOnlyElement( resourcesPrerequisite.getProvider(AndroidResourcesProvider.class) - .getDirectAndroidResources()); - // It's ugly, but flattening now is more performant given the rest of the checks. - List<ResourceContainer> resourceContainers = - ImmutableList.<ResourceContainer>builder() - //.add(resourceContainer) - .addAll(resourceDeps.getResources()).build(); + .getTransitiveAndroidResources()); // Dealing with Android library projects - if (Iterables.size(resourceDeps.getResources()) > 1) { + if (Iterables.size(resourceContainers) > 1) { if (resourceContainer.getConstantsInlined() && !resourceContainer.getArtifacts(ResourceType.RESOURCES).isEmpty()) { ruleContext.ruleError("This android_binary depends on an android_library, so the" @@ -461,7 +470,7 @@ public final class ApplicationManifest { aaptActionHelper.createGenerateProguardAction(proguardCfg); return new ResourceApk(resourceApk, updatedResources.getJavaSourceJar(), - resourceDeps, updatedResources, manifest, proguardCfg, true); + resourceContainers, updatedResources, manifest, proguardCfg, true); } public Artifact getManifest() { diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java index 8a14507c95..920f4cd68f 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java @@ -14,7 +14,7 @@ package com.google.devtools.build.lib.rules.android; import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.rules.android.AndroidResourcesProvider.ResourceContainer; @@ -31,7 +31,7 @@ public class ResourceApk { // to do this. @Nullable private final Artifact resourceApk; // The .ap_ file @Nullable private final Artifact resourceJavaSrcJar; // Source jar containing R.java and friends - private final ResourceDependencies resourceDeps; + private final NestedSet<ResourceContainer> transitiveResources; @Nullable private final ResourceContainer primaryResource; @Nullable private final Artifact manifest; // The non-binary XML version of AndroidManifest.xml @Nullable private final Artifact resourceProguardConfig; @@ -40,14 +40,14 @@ public class ResourceApk { public ResourceApk( @Nullable Artifact resourceApk, @Nullable Artifact resourceJavaSrcJar, - ResourceDependencies resourceDeps, + NestedSet<ResourceContainer> transitiveResources, @Nullable ResourceContainer primaryResource, @Nullable Artifact manifest, @Nullable Artifact resourceProguardConfig, boolean legacy) { this.resourceApk = resourceApk; this.resourceJavaSrcJar = resourceJavaSrcJar; - this.resourceDeps = resourceDeps; + this.transitiveResources = transitiveResources; this.primaryResource = primaryResource; this.manifest = manifest; this.resourceProguardConfig = resourceProguardConfig; @@ -74,36 +74,16 @@ public class ResourceApk { return legacy; } + public NestedSet<ResourceContainer> getTransitiveResources() { + return transitiveResources; + } + public static ResourceApk fromTransitiveResources( - ResourceDependencies resourceDeps) { - return new ResourceApk(null, null, resourceDeps, null, null, null, false); + NestedSet<ResourceContainer> transitiveResources) { + return new ResourceApk(null, null, transitiveResources, null, null, null, false); } public Artifact getResourceProguardConfig() { return resourceProguardConfig; } - - public ResourceDependencies getResourceDependencies() { - return resourceDeps; - } - - /** - * Creates an provider from the resources in the ResourceApk. - * - * <p>If the ResourceApk was created from transitive resources, the provider will effectively - * contain the "forwarded" resources: The merged transitive and merged direct dependencies of this - * library. - * - * <p>If the ResourceApk was generated from a "resources" attribute, it will contain the - * "resources" container in the direct dependencies and the rest as transitive. - * - * <p>If the ResourceApk was generated from local resources, that will be the direct dependencies and - * the rest will be transitive. - */ - public AndroidResourcesProvider toResourceProvider(Label label) { - if (primaryResource == null) { - return resourceDeps.toProvider(label); - } - return resourceDeps.toProvider(label, primaryResource); - } } 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 deleted file mode 100644 index f55b46361a..0000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceDependencies.java +++ /dev/null @@ -1,162 +0,0 @@ -// 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; - } -} diff --git a/src/test/java/com/google/devtools/build/lib/actions/CustomCommandLineTest.java b/src/test/java/com/google/devtools/build/lib/actions/CustomCommandLineTest.java index a61790d645..d94780f2ff 100644 --- a/src/test/java/com/google/devtools/build/lib/actions/CustomCommandLineTest.java +++ b/src/test/java/com/google/devtools/build/lib/actions/CustomCommandLineTest.java @@ -69,13 +69,6 @@ public class CustomCommandLineTest { } @Test - public void testArtifactJoinStringArgs() { - CustomCommandLine cl = CustomCommandLine.builder().addJoinStrings("--path", ":", - ImmutableList.of("foo", "bar")).build(); - assertEquals(ImmutableList.of("--path", "foo:bar"), cl.arguments()); - } - - @Test public void testArtifactExecPathArgs() { CustomCommandLine cl = CustomCommandLine.builder().addExecPath("--path", artifact1).build(); assertEquals(ImmutableList.of("--path", "dir/file1.txt"), cl.arguments()); diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java index c9a25b26d6..5d8ef6c27c 100644 --- a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java @@ -137,21 +137,11 @@ public class AndroidResourceProcessingAction { defaultValue = "", converter = DependencyAndroidDataListConverter.class, category = "input", - help = "Transitive Data dependencies. These values will be used if not defined in the " + help = "Additional Data dependencies. These values will be used if not defined in the " + "primary resources. The expected format is " - + "resources[#resources]:assets[#assets]:manifest:r.txt:symbols.bin" - + "[,resources[#resources]:assets[#assets]:manifest:r.txt:symbols.bin]") - public List<DependencyAndroidData> transitiveData; - - @Option(name = "directData", - defaultValue = "", - converter = DependencyAndroidDataListConverter.class, - category = "input", - help = "Direct Data dependencies. These values will be used if not defined in the " - + "primary resources. The expected format is " - + "resources[#resources]:assets[#assets]:manifest:r.txt:symbols.bin" - + "[,resources[#resources]:assets[#assets]:manifest:r.txt:symbols.bin]") - public List<DependencyAndroidData> directData; + + "resources[#resources]:assets[#assets]:manifest:r.txt:symbols.txt" + + "[,resources[#resources]:assets[#assets]:manifest:r.txt:symbols.txt]") + public List<DependencyAndroidData> data; @Option(name = "rOutput", defaultValue = "null", @@ -308,15 +298,11 @@ public class AndroidResourceProcessingAction { new PackedResourceTarExpander(expandedOut, working), new FileDeDuplicator(Hashing.murmur3_128(), deduplicatedOut, working)); - List<DependencyAndroidData> data = ImmutableList.<DependencyAndroidData>builder() - .addAll(options.directData) - .addAll(options.transitiveData) - .build(); final AndroidBuilder builder = sdkTools.createAndroidBuilder(); final MergedAndroidData mergedData = resourceProcessor.mergeData( options.primaryData, - data, + options.data, mergedResources, mergedAssets, modifiers, @@ -343,7 +329,7 @@ public class AndroidResourceProcessingAction { options.versionCode, options.versionName, filteredData, - data, + options.data, working.resolve("manifest"), generatedSources, options.packagePath, |