Fix AndroidBinaryRule.Builder so that build() can be invoked multiple times. Summary: A previous diff introduced a change to `AndroidBinaryRule.Builder` such that invoking `build()` would leave around some state (only if pre-dexing was applied) that would cause a problem if `build()` were invoked again on the same `Builder` object. When `buckd` is not running, `build()` is only invoked once, so this went undetected in the original diff.
diff --git a/src/com/facebook/buck/android/AndroidBinaryRule.java b/src/com/facebook/buck/android/AndroidBinaryRule.java index 826fabd..401dc5c 100644 --- a/src/com/facebook/buck/android/AndroidBinaryRule.java +++ b/src/com/facebook/buck/android/AndroidBinaryRule.java
@@ -1235,29 +1235,44 @@ BuildRuleParams originalParams = createBuildRuleParams(ruleResolver); ImmutableSortedSet<BuildRule> originalDeps = originalParams.getDeps(); + ImmutableSet<BuildRule> preDexDepsAsBuildRules; ImmutableSet<DexProducedFromJavaLibraryThatContainsClassFiles> preDexDeps; if (!disablePreDex && PackageType.DEBUG.equals(packageType) && !dexSplitMode.isShouldSplitDex() // TODO(mbolin): Support predex for split dex. && !preprocessJavaClassesBash.isPresent() // TODO(mbolin): Support predex post-preprocess. ) { - preDexDeps = enhanceGraphToLeveragePreDexing(originalDeps, + preDexDepsAsBuildRules = enhanceGraphToLeveragePreDexing(originalDeps, buildRulesToExcludeFromDex, ruleResolver, originalParams.getPathRelativizer(), originalParams.getRuleKeyBuilderFactory()); - for (DexProducedFromJavaLibraryThatContainsClassFiles preDexDep : preDexDeps) { - addDep(preDexDep.getBuildTarget()); + ImmutableSet.Builder<DexProducedFromJavaLibraryThatContainsClassFiles> preDexDepsBuilder = + ImmutableSet.builder(); + for (BuildRule preDexDepBuildRule : preDexDepsAsBuildRules) { + preDexDepsBuilder.add( + (DexProducedFromJavaLibraryThatContainsClassFiles) preDexDepBuildRule.getBuildable()); } + preDexDeps = preDexDepsBuilder.build(); } else { + preDexDepsAsBuildRules = ImmutableSet.of(); preDexDeps = ImmutableSortedSet.of(); } boolean allowNonExistentRule = false; - // Must invoke this a second time, as the preDexDeps may have been added to the builder. - BuildRuleParams finalParams = createBuildRuleParams(ruleResolver); + // Must create a new BuildRuleParams to supersede the one built by + // createBuildRuleParams(ruleResolver). + ImmutableSortedSet<BuildRule> totalDeps = ImmutableSortedSet.<BuildRule>naturalOrder() + .addAll(originalDeps) + .addAll(preDexDepsAsBuildRules) + .build(); + BuildRuleParams finalParams = new BuildRuleParams(getBuildTarget(), + totalDeps, + originalParams.getVisibilityPatterns(), + originalParams.getPathRelativizer(), + originalParams.getRuleKeyBuilderFactory()); return new AndroidBinaryRule( finalParams, @@ -1285,17 +1300,17 @@ /** * @return The set of build rules that correspond to pre-dex'd artifacts that should be merged - * to create the final classes.dex for the APK. + * to create the final classes.dex for the APK. For every element in the set, its + * {@link BuildRule#getBuildable()} method will return an instance of + * {@link DexProducedFromJavaLibraryThatContainsClassFiles}. */ - private ImmutableSet<DexProducedFromJavaLibraryThatContainsClassFiles> - enhanceGraphToLeveragePreDexing( + private ImmutableSet<BuildRule> enhanceGraphToLeveragePreDexing( ImmutableSortedSet<BuildRule> originalDeps, Set<BuildTarget> buildRulesToExcludeFromDex, BuildRuleResolver ruleResolver, Function<String, Path> pathRelativizer, RuleKeyBuilderFactory ruleKeyBuilderFactory) { - ImmutableSet.Builder<DexProducedFromJavaLibraryThatContainsClassFiles> preDexDeps = - ImmutableSet.builder(); + ImmutableSet.Builder<BuildRule> preDexDeps = ImmutableSet.builder(); ImmutableSet<JavaLibraryRule> transitiveJavaDeps = Classpaths .getClasspathEntries(originalDeps).keySet(); for (JavaLibraryRule javaLibraryRule : transitiveJavaDeps) { @@ -1317,8 +1332,7 @@ "dex"); BuildRule preDexRule = ruleResolver.get(preDexTarget); if (preDexRule != null) { - preDexDeps.add( - (DexProducedFromJavaLibraryThatContainsClassFiles) preDexRule.getBuildable()); + preDexDeps.add(preDexRule); continue; } @@ -1348,7 +1362,7 @@ preDexBuilder.addDep(accumulateClassNamesBuildTarget); preDexBuilder.addVisibilityPattern(BuildTargetPattern.MATCH_ALL); BuildRule preDex = ruleResolver.buildAndAddToIndex(preDexBuilder); - preDexDeps.add((DexProducedFromJavaLibraryThatContainsClassFiles) preDex.getBuildable()); + preDexDeps.add(preDex); } return preDexDeps.build(); }
diff --git a/src/com/facebook/buck/rules/AbstractBuildRuleBuilder.java b/src/com/facebook/buck/rules/AbstractBuildRuleBuilder.java index f51f13e..f07c96a 100644 --- a/src/com/facebook/buck/rules/AbstractBuildRuleBuilder.java +++ b/src/com/facebook/buck/rules/AbstractBuildRuleBuilder.java
@@ -46,6 +46,10 @@ this.ruleKeyBuilderFactory = params.getRuleKeyBuilderFactory(); } + /** + * This method must support being able to be invoked multiple times, as this builder will be + * reused when buckd is being used. + */ @Override public abstract T build(BuildRuleResolver ruleResolver);