Bundle managed directories and custom dirtiness checker (which is always a RepositoryDirectoryDirtinessChecker) together: the abstraction of a general SkyValueDirtinessChecker just obscures what's going on.

PiperOrigin-RevId: 420056804
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index 8aee071..76bd650 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -327,14 +327,13 @@
         "//src/main/java/com/google/devtools/build/lib/skyframe:diff_awareness",
         "//src/main/java/com/google/devtools/build/lib/skyframe:execution_finished_event",
         "//src/main/java/com/google/devtools/build/lib/skyframe:loading_phase_started_event",
-        "//src/main/java/com/google/devtools/build/lib/skyframe:managed_directories_knowledge",
         "//src/main/java/com/google/devtools/build/lib/skyframe:package_progress_receiver",
         "//src/main/java/com/google/devtools/build/lib/skyframe:package_roots_no_symlink_creation",
         "//src/main/java/com/google/devtools/build/lib/skyframe:package_value",
         "//src/main/java/com/google/devtools/build/lib/skyframe:precomputed_value",
         "//src/main/java/com/google/devtools/build/lib/skyframe:sky_functions",
-        "//src/main/java/com/google/devtools/build/lib/skyframe:sky_value_dirtiness_checker",
         "//src/main/java/com/google/devtools/build/lib/skyframe:skyframe_cluster",
+        "//src/main/java/com/google/devtools/build/lib/skyframe:skyframe_executor_repository_helpers_holder",
         "//src/main/java/com/google/devtools/build/lib/skyframe:target_pattern_phase_value",
         "//src/main/java/com/google/devtools/build/lib/skyframe:workspace_info",
         "//src/main/java/com/google/devtools/build/lib/unix",
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/BUILD b/src/main/java/com/google/devtools/build/lib/bazel/BUILD
index ea1a5e7..832f906 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/bazel/BUILD
@@ -46,6 +46,7 @@
         "//src/main/java/com/google/devtools/build/lib/skyframe:precomputed_value",
         "//src/main/java/com/google/devtools/build/lib/skyframe:sky_functions",
         "//src/main/java/com/google/devtools/build/lib/skyframe:skyframe_cluster",
+        "//src/main/java/com/google/devtools/build/lib/skyframe:skyframe_executor_repository_helpers_holder",
         "//src/main/java/com/google/devtools/build/lib/starlarkbuildapi/repository",
         "//src/main/java/com/google/devtools/build/lib/util:abrupt_exit_exception",
         "//src/main/java/com/google/devtools/build/lib/util:detailed_exit_code",
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
index 6994f6d..0569527 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
@@ -81,6 +81,7 @@
 import com.google.devtools.build.lib.skyframe.PrecomputedValue;
 import com.google.devtools.build.lib.skyframe.PrecomputedValue.Injected;
 import com.google.devtools.build.lib.skyframe.SkyFunctions;
+import com.google.devtools.build.lib.skyframe.SkyframeExecutorRepositoryHelpersHolder;
 import com.google.devtools.build.lib.starlarkbuildapi.repository.RepositoryBootstrap;
 import com.google.devtools.build.lib.util.AbruptExitException;
 import com.google.devtools.build.lib.util.DetailedExitCode;
@@ -204,12 +205,15 @@
   @Override
   public void workspaceInit(
       BlazeRuntime runtime, BlazeDirectories directories, WorkspaceBuilder builder) {
-    builder.setManagedDirectoriesKnowledge(managedDirectoriesKnowledge);
+    // TODO(b/27143724): Remove this guard when Google-internal flavor no longer uses repositories.
+    if ("bazel".equals(runtime.getProductName())) {
+      builder.setSkyframeExecutorRepositoryHelpersHolder(
+          SkyframeExecutorRepositoryHelpersHolder.create(
+              managedDirectoriesKnowledge,
+              new RepositoryDirectoryDirtinessChecker(
+                  directories.getWorkspace(), managedDirectoriesKnowledge)));
+    }
 
-    RepositoryDirectoryDirtinessChecker customDirtinessChecker =
-        new RepositoryDirectoryDirtinessChecker(
-            directories.getWorkspace(), managedDirectoriesKnowledge);
-    builder.addCustomDirtinessChecker(customDirtinessChecker);
     // Create the repository function everything flows through.
     RepositoryDelegatorFunction repositoryDelegatorFunction =
         new RepositoryDelegatorFunction(
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/WorkspaceBuilder.java b/src/main/java/com/google/devtools/build/lib/runtime/WorkspaceBuilder.java
index d4d1ed8..a49603d 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/WorkspaceBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/WorkspaceBuilder.java
@@ -23,15 +23,15 @@
 import com.google.devtools.build.lib.packages.PackageFactory;
 import com.google.devtools.build.lib.profiler.memory.AllocationTracker;
 import com.google.devtools.build.lib.skyframe.DiffAwareness;
-import com.google.devtools.build.lib.skyframe.ManagedDirectoriesKnowledge;
 import com.google.devtools.build.lib.skyframe.SequencedSkyframeExecutorFactory;
-import com.google.devtools.build.lib.skyframe.SkyValueDirtinessChecker;
 import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
 import com.google.devtools.build.lib.skyframe.SkyframeExecutorFactory;
+import com.google.devtools.build.lib.skyframe.SkyframeExecutorRepositoryHelpersHolder;
 import com.google.devtools.build.lib.util.AbruptExitException;
 import com.google.devtools.build.skyframe.SkyFunction;
 import com.google.devtools.build.skyframe.SkyFunctionName;
 import java.util.Map;
+import javax.annotation.Nullable;
 
 /**
  * Builder class to create a {@link BlazeWorkspace} instance. This class is part of the module API,
@@ -49,11 +49,12 @@
   // is inserted.
   private final ImmutableMap.Builder<SkyFunctionName, SkyFunction> skyFunctions =
       ImmutableMap.builder();
-  private final ImmutableList.Builder<SkyValueDirtinessChecker> customDirtinessCheckers =
-      ImmutableList.builder();
   private AllocationTracker allocationTracker;
-  private ManagedDirectoriesKnowledge managedDirectoriesKnowledge;
-  private SkyframeExecutor.SkyKeyStateReceiver skyKeyStateReceiver = null;
+
+  @Nullable
+  private SkyframeExecutorRepositoryHelpersHolder skyframeExecutorRepositoryHelpersHolder = null;
+
+  @Nullable private SkyframeExecutor.SkyKeyStateReceiver skyKeyStateReceiver = null;
 
   WorkspaceBuilder(BlazeDirectories directories, BinTools binTools) {
     this.directories = directories;
@@ -78,8 +79,7 @@
             workspaceStatusActionFactory,
             diffAwarenessFactories.build(),
             skyFunctions.build(),
-            customDirtinessCheckers.build(),
-            managedDirectoriesKnowledge,
+            skyframeExecutorRepositoryHelpersHolder,
             skyKeyStateReceiver == null
                 ? SkyframeExecutor.SkyKeyStateReceiver.NULL_INSTANCE
                 : skyKeyStateReceiver,
@@ -152,15 +152,9 @@
     return this;
   }
 
-  public WorkspaceBuilder addCustomDirtinessChecker(
-      SkyValueDirtinessChecker customDirtinessChecker) {
-    this.customDirtinessCheckers.add(Preconditions.checkNotNull(customDirtinessChecker));
-    return this;
-  }
-
-  public WorkspaceBuilder setManagedDirectoriesKnowledge(
-      ManagedDirectoriesKnowledge managedDirectoriesKnowledge) {
-    this.managedDirectoriesKnowledge = managedDirectoriesKnowledge;
+  public WorkspaceBuilder setSkyframeExecutorRepositoryHelpersHolder(
+      SkyframeExecutorRepositoryHelpersHolder skyframeExecutorRepositoryHelpersHolder) {
+    this.skyframeExecutorRepositoryHelpersHolder = skyframeExecutorRepositoryHelpersHolder;
     return this;
   }
 
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 56f8468..7831315 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
@@ -184,6 +184,7 @@
         ":sky_functions",
         ":sky_value_dirtiness_checker",
         ":skyframe_aware_action",
+        ":skyframe_executor_repository_helpers_holder",
         ":skyframe_incremental_build_monitor",
         ":skylark_module_cycle_reporter",
         ":starlark_builtins_value",
@@ -2262,6 +2263,16 @@
 )
 
 java_library(
+    name = "skyframe_executor_repository_helpers_holder",
+    srcs = ["SkyframeExecutorRepositoryHelpersHolder.java"],
+    deps = [
+        ":managed_directories_knowledge",
+        "//src/main/java/com/google/devtools/build/lib/rules:repository/repository_function",
+        "//third_party:auto_value",
+    ],
+)
+
+java_library(
     name = "skyframe_incremental_build_monitor",
     srcs = ["SkyframeIncrementalBuildMonitor.java"],
     deps = [
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
index e0fa360..844093a 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
@@ -13,6 +13,8 @@
 // limitations under the License.
 package com.google.devtools.build.lib.skyframe;
 
+import static com.google.common.collect.ImmutableList.toImmutableList;
+
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Joiner;
 import com.google.common.base.Preconditions;
@@ -110,10 +112,12 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Consumer;
+import java.util.stream.Stream;
 import javax.annotation.Nullable;
 
 /**
@@ -139,7 +143,8 @@
   // that on the next build we try to inject/invalidate some nodes that aren't needed for the build.
   private final RecordingDifferencer recordingDiffer = new SequencedRecordingDifferencer();
   private final DiffAwarenessManager diffAwarenessManager;
-  private final Iterable<SkyValueDirtinessChecker> customDirtinessCheckers;
+  // If this is null then workspace header pre-calculation won't happen.
+  @Nullable private final SkyframeExecutorRepositoryHelpersHolder repositoryHelpersHolder;
   private Set<String> previousClientEnvironment = ImmutableSet.of();
 
   private int modifiedFiles;
@@ -149,8 +154,6 @@
   private int numSourceFilesCheckedBecauseOfMissingDiffs;
   private Duration outputTreeDiffCheckingDuration = Duration.ofSeconds(-1L);
 
-  // If this is null then workspace header pre-calculation won't happen.
-  @Nullable private final ManagedDirectoriesKnowledge managedDirectoriesKnowledge;
   private final WorkspaceInfoFromDiffReceiver workspaceInfoFromDiffReceiver;
 
   private SequencedSkyframeExecutor(
@@ -164,13 +167,12 @@
       Iterable<? extends DiffAwareness.Factory> diffAwarenessFactories,
       WorkspaceInfoFromDiffReceiver workspaceInfoFromDiffReceiver,
       ImmutableMap<SkyFunctionName, SkyFunction> extraSkyFunctions,
-      Iterable<SkyValueDirtinessChecker> customDirtinessCheckers,
       SkyFunction ignoredPackagePrefixesFunction,
       CrossRepositoryLabelViolationStrategy crossRepositoryLabelViolationStrategy,
       ImmutableList<BuildFileName> buildFilesByPriority,
       ExternalPackageHelper externalPackageHelper,
+      @Nullable SkyframeExecutorRepositoryHelpersHolder repositoryHelpersHolder,
       ActionOnIOExceptionReadingBuildFile actionOnIOExceptionReadingBuildFile,
-      @Nullable ManagedDirectoriesKnowledge managedDirectoriesKnowledge,
       SkyKeyStateReceiver skyKeyStateReceiver,
       BugReporter bugReporter) {
     super(
@@ -192,12 +194,13 @@
         GraphInconsistencyReceiver.THROWING,
         new PackageProgressReceiver(),
         new ConfiguredTargetProgressReceiver(),
-        managedDirectoriesKnowledge,
+        repositoryHelpersHolder == null
+            ? null
+            : repositoryHelpersHolder.managedDirectoriesKnowledge(),
         skyKeyStateReceiver,
         bugReporter);
     this.diffAwarenessManager = new DiffAwarenessManager(diffAwarenessFactories);
-    this.customDirtinessCheckers = customDirtinessCheckers;
-    this.managedDirectoriesKnowledge = managedDirectoriesKnowledge;
+    this.repositoryHelpersHolder = repositoryHelpersHolder;
     this.workspaceInfoFromDiffReceiver = workspaceInfoFromDiffReceiver;
   }
 
@@ -337,7 +340,7 @@
     numSourceFilesCheckedBecauseOfMissingDiffs = 0;
 
     boolean managedDirectoriesChanged =
-        managedDirectoriesKnowledge != null && refreshWorkspaceHeader(eventHandler);
+        repositoryHelpersHolder != null && refreshWorkspaceHeader(eventHandler);
     if (managedDirectoriesChanged) {
       invalidateCachedWorkspacePathsStates();
     }
@@ -415,7 +418,7 @@
     Iterable<SkyKey> deletedKeys =
         Sets.difference(previousClientEnvironment, clientEnv.get().keySet()).stream()
             .map(ClientEnvironmentFunction::key)
-            .collect(ImmutableList.toImmutableList());
+            .collect(toImmutableList());
     recordingDiffer.invalidate(deletedKeys);
     previousClientEnvironment = clientEnv.get().keySet();
     // Inject current client environmental values. We can inject unconditionally without fearing
@@ -478,7 +481,7 @@
     ExternalFilesKnowledge externalFilesKnowledge = externalFilesHelper.getExternalFilesKnowledge();
     if (!pathEntriesWithoutDiffInformation.isEmpty()
         || (externalFilesKnowledge.anyOutputFilesSeen && checkOutputFiles)
-        || !Iterables.isEmpty(customDirtinessCheckers)
+        || repositoryHelpersHolder != null
         || externalFilesKnowledge.anyFilesInExternalReposSeen
         || externalFilesKnowledge.tooManyNonOutputExternalFilesSeen) {
 
@@ -523,11 +526,14 @@
             fsvc.getDirtyKeys(
                 memoizingEvaluator.getValues(),
                 new UnionDirtinessChecker(
-                    Iterables.concat(
-                        customDirtinessCheckers,
-                        ImmutableList.<SkyValueDirtinessChecker>of(
+                    Stream.of(
                             new ExternalDirtinessChecker(tmpExternalFilesHelper, fileTypesToCheck),
-                            new MissingDiffDirtinessChecker(diffPackageRootsUnderWhichToCheck)))));
+                            new MissingDiffDirtinessChecker(diffPackageRootsUnderWhichToCheck),
+                            repositoryHelpersHolder == null
+                                ? null
+                                : repositoryHelpersHolder.repositoryDirectoryDirtinessChecker())
+                        .filter(Objects::nonNull)
+                        .collect(toImmutableList())));
       }
       handleChangedFiles(
           diffPackageRootsUnderWhichToCheck,
@@ -970,7 +976,9 @@
                                   .ILLEGAL_WORKSPACE_FILE_SYMLINK_WITH_MANAGED_DIRECTORIES))
                   .build()));
     }
-    return managedDirectoriesKnowledge.workspaceHeaderReloaded(oldValue, newValue);
+    return repositoryHelpersHolder
+        .managedDirectoriesKnowledge()
+        .workspaceHeaderReloaded(oldValue, newValue);
   }
 
   // We only check the FileStateValue of the WORKSPACE file; we do not support the case
@@ -1033,7 +1041,6 @@
     private ImmutableList<BuildFileName> buildFilesByPriority;
     private ExternalPackageHelper externalPackageHelper;
     private ActionOnIOExceptionReadingBuildFile actionOnIOExceptionReadingBuildFile;
-    @Nullable private ManagedDirectoriesKnowledge managedDirectoriesKnowledge;
 
     // Fields with default values.
     private ImmutableMap<SkyFunctionName, SkyFunction> extraSkyFunctions = ImmutableMap.of();
@@ -1041,7 +1048,7 @@
     private Iterable<? extends DiffAwareness.Factory> diffAwarenessFactories = ImmutableList.of();
     private WorkspaceInfoFromDiffReceiver workspaceInfoFromDiffReceiver =
         (ignored1, ignored2) -> {};
-    private Iterable<SkyValueDirtinessChecker> customDirtinessCheckers = ImmutableList.of();
+    @Nullable private SkyframeExecutorRepositoryHelpersHolder repositoryHelpersHolder = null;
     private Consumer<SkyframeExecutor> skyframeExecutorConsumerOnInit = skyframeExecutor -> {};
     private SkyFunction ignoredPackagePrefixesFunction;
     private BugReporter bugReporter = BugReporter.defaultInstance();
@@ -1073,13 +1080,12 @@
               diffAwarenessFactories,
               workspaceInfoFromDiffReceiver,
               extraSkyFunctions,
-              customDirtinessCheckers,
               ignoredPackagePrefixesFunction,
               crossRepositoryLabelViolationStrategy,
               buildFilesByPriority,
               externalPackageHelper,
+              repositoryHelpersHolder,
               actionOnIOExceptionReadingBuildFile,
-              managedDirectoriesKnowledge,
               skyKeyStateReceiver,
               bugReporter);
       skyframeExecutor.init();
@@ -1139,9 +1145,9 @@
       return this;
     }
 
-    public Builder setCustomDirtinessCheckers(
-        Iterable<SkyValueDirtinessChecker> customDirtinessCheckers) {
-      this.customDirtinessCheckers = customDirtinessCheckers;
+    public Builder setRepositoryHelpersHolder(
+        SkyframeExecutorRepositoryHelpersHolder repositoryHelpersHolder) {
+      this.repositoryHelpersHolder = repositoryHelpersHolder;
       return this;
     }
 
@@ -1177,11 +1183,5 @@
       this.skyKeyStateReceiver = Preconditions.checkNotNull(skyKeyStateReceiver);
       return this;
     }
-
-    public Builder setManagedDirectoriesKnowledge(
-        @Nullable ManagedDirectoriesKnowledge managedDirectoriesKnowledge) {
-      this.managedDirectoriesKnowledge = managedDirectoriesKnowledge;
-      return this;
-    }
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutorFactory.java b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutorFactory.java
index a838c29..b719147 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutorFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutorFactory.java
@@ -26,7 +26,6 @@
 
 /** A factory of SkyframeExecutors that returns SequencedSkyframeExecutor. */
 public final class SequencedSkyframeExecutorFactory implements SkyframeExecutorFactory {
-
   @Override
   public SkyframeExecutor create(
       PackageFactory pkgFactory,
@@ -36,8 +35,7 @@
       Factory workspaceStatusActionFactory,
       Iterable<? extends DiffAwareness.Factory> diffAwarenessFactories,
       ImmutableMap<SkyFunctionName, SkyFunction> extraSkyFunctions,
-      Iterable<SkyValueDirtinessChecker> customDirtinessCheckers,
-      @Nullable ManagedDirectoriesKnowledge managedDirectoriesKnowledge,
+      @Nullable SkyframeExecutorRepositoryHelpersHolder repositoryHelpersHolder,
       SkyframeExecutor.SkyKeyStateReceiver skyKeyStateReceiver,
       BugReporter bugReporter) {
     return BazelSkyframeExecutorConstants.newBazelSkyframeExecutorBuilder()
@@ -48,8 +46,7 @@
         .setWorkspaceStatusActionFactory(workspaceStatusActionFactory)
         .setDiffAwarenessFactories(diffAwarenessFactories)
         .setExtraSkyFunctions(extraSkyFunctions)
-        .setCustomDirtinessCheckers(customDirtinessCheckers)
-        .setManagedDirectoriesKnowledge(managedDirectoriesKnowledge)
+        .setRepositoryHelpersHolder(repositoryHelpersHolder)
         .setSkyKeyStateReceiver(skyKeyStateReceiver)
         .setBugReporter(bugReporter)
         .build();
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutorFactory.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutorFactory.java
index 46451e1..20a26b4 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutorFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutorFactory.java
@@ -49,8 +49,7 @@
       Factory workspaceStatusActionFactory,
       Iterable<? extends DiffAwareness.Factory> diffAwarenessFactories,
       ImmutableMap<SkyFunctionName, SkyFunction> extraSkyFunctions,
-      Iterable<SkyValueDirtinessChecker> customDirtinessCheckers,
-      ManagedDirectoriesKnowledge managedDirectoriesKnowledge,
+      SkyframeExecutorRepositoryHelpersHolder repositoryHelpersHolder,
       SkyframeExecutor.SkyKeyStateReceiver skyKeyStateReceiver,
       BugReporter bugReporter)
       throws AbruptExitException;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutorRepositoryHelpersHolder.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutorRepositoryHelpersHolder.java
new file mode 100644
index 0000000..a858478
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutorRepositoryHelpersHolder.java
@@ -0,0 +1,33 @@
+// Copyright 2022 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.skyframe;
+
+import com.google.auto.value.AutoValue;
+import com.google.devtools.build.lib.rules.repository.RepositoryDirectoryDirtinessChecker;
+
+/** Provides repository-related objects for use by {@link SequencedSkyframeExecutor}. */
+@AutoValue
+public abstract class SkyframeExecutorRepositoryHelpersHolder {
+  public abstract ManagedDirectoriesKnowledge managedDirectoriesKnowledge();
+
+  public abstract RepositoryDirectoryDirtinessChecker repositoryDirectoryDirtinessChecker();
+
+  public static SkyframeExecutorRepositoryHelpersHolder create(
+      ManagedDirectoriesKnowledge managedDirectoriesKnowledge,
+      RepositoryDirectoryDirtinessChecker repositoryDirectoryDirtinessChecker) {
+    return new AutoValue_SkyframeExecutorRepositoryHelpersHolder(
+        managedDirectoriesKnowledge, repositoryDirectoryDirtinessChecker);
+  }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/BUILD b/src/test/java/com/google/devtools/build/lib/analysis/util/BUILD
index 08ec507..575352d 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/util/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/BUILD
@@ -109,6 +109,7 @@
         "//src/main/java/com/google/devtools/build/lib/skyframe:precomputed_value",
         "//src/main/java/com/google/devtools/build/lib/skyframe:sky_functions",
         "//src/main/java/com/google/devtools/build/lib/skyframe:skyframe_cluster",
+        "//src/main/java/com/google/devtools/build/lib/skyframe:skyframe_executor_repository_helpers_holder",
         "//src/main/java/com/google/devtools/build/lib/skyframe:starlark_builtins_value",
         "//src/main/java/com/google/devtools/build/lib/skyframe:target_pattern_phase_value",
         "//src/main/java/com/google/devtools/build/lib/skyframe:toolchain_exception",
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
index 41508dd..b068623 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
@@ -146,6 +146,7 @@
 import com.google.devtools.build.lib.pkgcache.PackageOptions;
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
 import com.google.devtools.build.lib.rules.repository.RepositoryDelegatorFunction;
+import com.google.devtools.build.lib.rules.repository.RepositoryDirectoryDirtinessChecker;
 import com.google.devtools.build.lib.skyframe.AspectKeyCreator;
 import com.google.devtools.build.lib.skyframe.AspectKeyCreator.AspectKey;
 import com.google.devtools.build.lib.skyframe.BazelSkyframeExecutorConstants;
@@ -161,6 +162,7 @@
 import com.google.devtools.build.lib.skyframe.SequencedSkyframeExecutor;
 import com.google.devtools.build.lib.skyframe.SkyFunctions;
 import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
+import com.google.devtools.build.lib.skyframe.SkyframeExecutorRepositoryHelpersHolder;
 import com.google.devtools.build.lib.skyframe.StarlarkBuiltinsValue;
 import com.google.devtools.build.lib.skyframe.TargetPatternPhaseValue;
 import com.google.devtools.build.lib.testutil.FoundationTestCase;
@@ -304,16 +306,23 @@
     }
     pkgFactory = pkgFactoryBuilder.build(ruleClassProvider, fileSystem);
     tsgm = new TimestampGranularityMonitor(BlazeClock.instance());
-    skyframeExecutor =
+    SequencedSkyframeExecutor.Builder builder =
         BazelSkyframeExecutorConstants.newBazelSkyframeExecutorBuilder()
             .setPkgFactory(pkgFactory)
             .setFileSystem(fileSystem)
             .setDirectories(directories)
             .setActionKeyContext(actionKeyContext)
             .setWorkspaceStatusActionFactory(workspaceStatusActionFactory)
-            .setExtraSkyFunctions(analysisMock.getSkyFunctions(directories))
-            .setManagedDirectoriesKnowledge(getManagedDirectoriesKnowledge())
-            .build();
+            .setExtraSkyFunctions(analysisMock.getSkyFunctions(directories));
+    ManagedDirectoriesKnowledge managedDirectoriesKnowledge = getManagedDirectoriesKnowledge();
+    if (managedDirectoriesKnowledge != null) {
+      builder.setRepositoryHelpersHolder(
+          SkyframeExecutorRepositoryHelpersHolder.create(
+              managedDirectoriesKnowledge,
+              new RepositoryDirectoryDirtinessChecker(
+                  directories.getWorkspace(), managedDirectoriesKnowledge)));
+    }
+    skyframeExecutor = builder.build();
     if (usesInliningBzlLoadFunction()) {
       injectInliningBzlLoadFunction(skyframeExecutor, pkgFactory, directories);
     }
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/AbstractCollectPackagesUnderDirectoryTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/AbstractCollectPackagesUnderDirectoryTest.java
index 451ee5b..c5b420f 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/AbstractCollectPackagesUnderDirectoryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/AbstractCollectPackagesUnderDirectoryTest.java
@@ -293,8 +293,7 @@
                 /*workspaceStatusActionFactory=*/ null,
                 /*diffAwarenessFactories=*/ ImmutableList.of(),
                 getExtraSkyFunctions(),
-                /*customDirtinessCheckers=*/ ImmutableList.of(),
-                /*managedDirectoriesKnowledge=*/ null,
+                /*repositoryHelpersHolder=*/ null,
                 SkyframeExecutor.SkyKeyStateReceiver.NULL_INSTANCE,
                 BugReporter.defaultInstance());
     skyframeExecutor.injectExtraPrecomputedValues(