skyfocus: ensure re-run if analysis cache drops (e.g. due to build setting change). This adds a subscriber for `AnalysisPhaseCompleteEvent`, which contains information when the analysis cache was dropped (and therefore rebuilt), and needs a Skyfocus re-run. With Skymeld, `AnalysisPhaseCompleteEvent` is fired from a callback (when `AnalysisOperationWatcher#handleTopLevelEntityAnalysisConcluded` empties out the set of expected top level keys), so it's when analysis is _fully_ finished. RELNOTES: PiperOrigin-RevId: 613529397 Change-Id: I738c0e390cd2338dbbed909272dabe2aeb3cbe91
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD index c39eab3..e149a63 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD +++ b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
@@ -2483,6 +2483,7 @@ ":precomputed_value", "//src/main/java/com/google/devtools/build/lib:runtime", "//src/main/java/com/google/devtools/build/lib/actions:artifacts", + "//src/main/java/com/google/devtools/build/lib/analysis:analysis_phase_complete_event", "//src/main/java/com/google/devtools/build/lib/collect/nestedset:artifact_nested_set_key", "//src/main/java/com/google/devtools/build/lib/concurrent", "//src/main/java/com/google/devtools/build/lib/events",
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyfocusModule.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyfocusModule.java index 5355a86..f602348 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyfocusModule.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyfocusModule.java
@@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import com.google.common.eventbus.Subscribe; +import com.google.devtools.build.lib.analysis.AnalysisPhaseCompleteEvent; import com.google.devtools.build.lib.buildtool.BuildPrecompleteEvent; import com.google.devtools.build.lib.buildtool.BuildToolFinalizingEvent; import com.google.devtools.build.lib.events.Event; @@ -231,6 +232,21 @@ } } + /** Subscriber trigger for Skyfocus using information from {@link AnalysisPhaseCompleteEvent}. */ + @SuppressWarnings("unused") + @Subscribe + public void onAnalysisPhaseComplete(AnalysisPhaseCompleteEvent event) { + if (!skyfocusEnabled()) { + return; + } + + // If there's an active working set and the analysis cache was dropped for any reason (e.g. + // configuration change), we need to re-run Skyfocus. + if (event.wasAnalysisCacheDropped() && !env.getSkyframeExecutor().getWorkingSet().isEmpty()) { + pendingSkyfocusState = PendingSkyfocusState.RUN_FOCUS; + } + } + /** * Subscriber trigger for Skyfocus using {@link BuildToolFinalizingEvent}. *
diff --git a/src/test/shell/integration/focus_test.sh b/src/test/shell/integration/focus_test.sh index 4eb083d..f00007f 100755 --- a/src/test/shell/integration/focus_test.sh +++ b/src/test/shell/integration/focus_test.sh
@@ -656,4 +656,78 @@ expect_log "Skyfocus did not run due to an unsuccessful build." } +function test_reanalysis_with_label_flag_change() { + local -r pkg=${FUNCNAME[0]} + mkdir -p ${pkg} + touch ${pkg}/in.txt + + cat > ${pkg}/BUILD <<EOF +load("//${pkg}:rules.bzl", "my_rule", "simple_rule") + +my_rule(name = "my_rule", src = "in.txt") + +simple_rule(name = "default", value = "default_val") + +simple_rule(name = "command_line", value = "command_line_val") + +label_flag( + name = "my_label_build_setting", + build_setting_default = ":default" +) +EOF + + cat > ${pkg}/rules.bzl <<EOF +def _impl(ctx): + _setting = "value=" + ctx.attr._label_flag[SimpleRuleInfo].value + + out = ctx.actions.declare_file(ctx.attr.name + ".txt") + ctx.actions.run_shell( + inputs = [ctx.file.src], + outputs = [out], + command = " ".join(["cat", ctx.file.src.path, ">", out.path, "&&", "echo", _setting, ">>", out.path]), + ) + + return [DefaultInfo(files = depset([out]))] + +my_rule = rule( + implementation = _impl, + attrs = { + "src": attr.label(allow_single_file = True), + "_label_flag": attr.label(default = Label("//${pkg}:my_label_build_setting")), + }, +) + +SimpleRuleInfo = provider(fields = ['value']) + +def _simple_rule_impl(ctx): + return [SimpleRuleInfo(value = ctx.attr.value)] + +simple_rule = rule( + implementation = _simple_rule_impl, + attrs = { + "value": attr.string(), + }, +) +EOF + + out=$(bazel info "${PRODUCT_NAME}-bin")/${pkg}/my_rule.txt + bazel build //${pkg}:my_rule --experimental_working_set=${pkg}/in.txt \ + || fail "expected build to succeed" + + assert_contains "value=default_val" ${out} + + # Change the configuration dep. + bazel build //${pkg}:my_rule --//${pkg}:my_label_build_setting=//${pkg}:command_line &> "$TEST_log" \ + || fail "expected build to succeed" + + # Analysis cache should be dropped due to the changed configuration. + expect_log "WARNING: Build option --//${pkg}:my_label_build_setting has changed, discarding analysis cache" + + # Skyfocus should rerun due to the dropped analysis cache. + expect_log "Focusing on .\+ roots, .\+ leafs" + + # New result. + assert_contains "value=command_line_val" ${out} +} + run_suite "Tests for Skyfocus"