// Copyright 2014 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 static com.google.devtools.build.lib.concurrent.Uninterruptibles.callUninterruptibly; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.base.Stopwatch; import com.google.common.base.Throwables; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Iterables; import com.google.common.collect.Multimap; import com.google.common.collect.Range; import com.google.common.eventbus.EventBus; import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; import com.google.devtools.build.lib.actions.ActionCacheChecker; import com.google.devtools.build.lib.actions.ActionExecutionStatusReporter; import com.google.devtools.build.lib.actions.ActionGraph; import com.google.devtools.build.lib.actions.ActionInputMap; import com.google.devtools.build.lib.actions.ActionInputPrefetcher; import com.google.devtools.build.lib.actions.ActionKeyContext; import com.google.devtools.build.lib.actions.ActionLogBufferPathGenerator; import com.google.devtools.build.lib.actions.ActionLookupValue; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.ArtifactFactory; import com.google.devtools.build.lib.actions.ArtifactOwner; import com.google.devtools.build.lib.actions.ArtifactPathResolver; import com.google.devtools.build.lib.actions.ArtifactResolver.ArtifactResolverSupplier; import com.google.devtools.build.lib.actions.ArtifactRoot; import com.google.devtools.build.lib.actions.CommandLineExpansionException; import com.google.devtools.build.lib.actions.EnvironmentalExecException; import com.google.devtools.build.lib.actions.Executor; import com.google.devtools.build.lib.actions.FileStateType; import com.google.devtools.build.lib.actions.FileStateValue; import com.google.devtools.build.lib.actions.FileValue; import com.google.devtools.build.lib.actions.MetadataProvider; import com.google.devtools.build.lib.actions.ResourceManager; import com.google.devtools.build.lib.analysis.AnalysisProtos.ActionGraphContainer; import com.google.devtools.build.lib.analysis.AspectCollection; import com.google.devtools.build.lib.analysis.BlazeDirectories; import com.google.devtools.build.lib.analysis.ConfiguredAspect; import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.Dependency; import com.google.devtools.build.lib.analysis.ToolchainContext; import com.google.devtools.build.lib.analysis.TopLevelArtifactContext; import com.google.devtools.build.lib.analysis.WorkspaceStatusAction; import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory; import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory.BuildInfoKey; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection; import com.google.devtools.build.lib.analysis.config.BuildOptions; import com.google.devtools.build.lib.analysis.config.ConfigurationFragmentFactory; import com.google.devtools.build.lib.analysis.config.ConfigurationResolver; import com.google.devtools.build.lib.analysis.config.FragmentClassSet; import com.google.devtools.build.lib.analysis.config.HostTransition; import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException; import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition; import com.google.devtools.build.lib.analysis.config.transitions.NoTransition; import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget; import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget.DuplicateException; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.LabelSyntaxException; import com.google.devtools.build.lib.cmdline.PackageIdentifier; import com.google.devtools.build.lib.cmdline.RepositoryName; import com.google.devtools.build.lib.cmdline.TargetParsingException; import com.google.devtools.build.lib.concurrent.ThreadSafety; import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible; import com.google.devtools.build.lib.events.ErrorSensingEventHandler; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.EventHandler; import com.google.devtools.build.lib.events.ExtendedEventHandler; import com.google.devtools.build.lib.events.Reporter; import com.google.devtools.build.lib.packages.AspectDescriptor; import com.google.devtools.build.lib.packages.AstParseResult; import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException; import com.google.devtools.build.lib.packages.BuildFileName; import com.google.devtools.build.lib.packages.NoSuchPackageException; import com.google.devtools.build.lib.packages.NoSuchTargetException; import com.google.devtools.build.lib.packages.NoSuchThingException; import com.google.devtools.build.lib.packages.Package; import com.google.devtools.build.lib.packages.PackageFactory; import com.google.devtools.build.lib.packages.RuleClassProvider; import com.google.devtools.build.lib.packages.RuleVisibility; import com.google.devtools.build.lib.packages.SkylarkSemanticsOptions; import com.google.devtools.build.lib.pkgcache.LoadingOptions; import com.google.devtools.build.lib.pkgcache.PackageCacheOptions; import com.google.devtools.build.lib.pkgcache.PackageManager; import com.google.devtools.build.lib.pkgcache.PathPackageLocator; import com.google.devtools.build.lib.pkgcache.TargetParsingPhaseTimeEvent; import com.google.devtools.build.lib.pkgcache.TargetPatternEvaluator; import com.google.devtools.build.lib.pkgcache.TestFilter; import com.google.devtools.build.lib.pkgcache.TransitivePackageLoader; import com.google.devtools.build.lib.profiler.Profiler; import com.google.devtools.build.lib.profiler.SilentCloseable; import com.google.devtools.build.lib.rules.repository.ResolvedHashesFunction; import com.google.devtools.build.lib.skyframe.AspectValue.AspectValueKey; import com.google.devtools.build.lib.skyframe.CompletionFunction.PathResolverFactory; import com.google.devtools.build.lib.skyframe.DirtinessCheckerUtils.FileDirtinessChecker; import com.google.devtools.build.lib.skyframe.ExternalFilesHelper.ExternalFileAction; import com.google.devtools.build.lib.skyframe.PackageFunction.ActionOnIOExceptionReadingBuildFile; import com.google.devtools.build.lib.skyframe.PackageFunction.IncrementalityIntent; import com.google.devtools.build.lib.skyframe.PackageFunction.LoadedPackageCacheEntry; import com.google.devtools.build.lib.skyframe.PackageLookupFunction.CrossRepositoryLabelViolationStrategy; import com.google.devtools.build.lib.skyframe.SkyframeActionExecutor.ActionCompletedReceiver; import com.google.devtools.build.lib.skyframe.SkyframeActionExecutor.ProgressSupplier; import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey; import com.google.devtools.build.lib.syntax.SkylarkSemantics; import com.google.devtools.build.lib.util.AbruptExitException; import com.google.devtools.build.lib.util.ResourceUsage; import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor; import com.google.devtools.build.lib.vfs.Dirent; import com.google.devtools.build.lib.vfs.FileSystem; import com.google.devtools.build.lib.vfs.ModifiedFileSet; import com.google.devtools.build.lib.vfs.OutputService; import com.google.devtools.build.lib.vfs.Path; import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.lib.vfs.Root; import com.google.devtools.build.lib.vfs.RootedPath; import com.google.devtools.build.lib.vfs.UnixGlob; import com.google.devtools.build.skyframe.BuildDriver; import com.google.devtools.build.skyframe.CycleInfo; import com.google.devtools.build.skyframe.CyclesReporter; import com.google.devtools.build.skyframe.Differencer; import com.google.devtools.build.skyframe.Differencer.DiffWithDelta.Delta; import com.google.devtools.build.skyframe.ErrorInfo; import com.google.devtools.build.skyframe.EvaluationProgressReceiver; import com.google.devtools.build.skyframe.EvaluationResult; import com.google.devtools.build.skyframe.EventFilter; import com.google.devtools.build.skyframe.GraphInconsistencyReceiver; import com.google.devtools.build.skyframe.ImmutableDiff; import com.google.devtools.build.skyframe.InMemoryMemoizingEvaluator; import com.google.devtools.build.skyframe.Injectable; import com.google.devtools.build.skyframe.MemoizingEvaluator; import com.google.devtools.build.skyframe.MemoizingEvaluator.EvaluatorSupplier; import com.google.devtools.build.skyframe.SkyFunction; import com.google.devtools.build.skyframe.SkyFunctionName; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.SkyValue; import com.google.devtools.build.skyframe.WalkableGraph.WalkableGraphFactory; import com.google.devtools.common.options.OptionsClassProvider; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.Nullable; /** * A helper object to support Skyframe-driven execution. * *

This object is mostly used to inject external state, such as the executor engine or some * additional artifacts (workspace status and build info artifacts) into SkyFunctions for use during * the build. */ public abstract class SkyframeExecutor implements WalkableGraphFactory { private final EvaluatorSupplier evaluatorSupplier; protected MemoizingEvaluator memoizingEvaluator; private final MemoizingEvaluator.EmittedEventState emittedEventState = new MemoizingEvaluator.EmittedEventState(); private final PackageFactory pkgFactory; private final WorkspaceStatusAction.Factory workspaceStatusActionFactory; private final FileSystem fileSystem; private final BlazeDirectories directories; protected final ExternalFilesHelper externalFilesHelper; private final GraphInconsistencyReceiver graphInconsistencyReceiver; @Nullable protected OutputService outputService; // TODO(bazel-team): Figure out how to handle value builders that block internally. Blocking // operations may need to be handled in another (bigger?) thread pool. Also, we should detect // the number of cores and use that as the thread-pool size for CPU-bound operations. // I just bumped this to 200 to get reasonable execution phase performance; that may cause // significant overhead for CPU-bound processes (i.e. analysis). [skyframe-analysis] @VisibleForTesting public static final int DEFAULT_THREAD_COUNT = // Reduce thread count while running tests of Bazel. Test cases are typically small, and large // thread pools vying for a relatively small number of CPU cores may induce non-optimal // performance. System.getenv("TEST_TMPDIR") == null ? 200 : 5; // Cache of partially constructed Package instances, stored between reruns of the PackageFunction // (because of missing dependencies, within the same evaluate() run) to avoid loading the same // package twice (first time loading to find imported bzl files and declare Skyframe // dependencies). // TODO(bazel-team): remove this cache once we have skyframe-native package loading // [skyframe-loading] private final Cache packageFunctionCache = newPkgFunctionCache(); private final Cache astCache = newAstCache(); private final AtomicInteger numPackagesLoaded = new AtomicInteger(0); @Nullable private final PackageProgressReceiver packageProgress; private final SkyframeBuildView skyframeBuildView; private ActionLogBufferPathGenerator actionLogBufferPathGenerator; protected BuildDriver buildDriver; // AtomicReferences are used here as mutable boxes shared with value builders. private final AtomicBoolean showLoadingProgress = new AtomicBoolean(); protected final AtomicReference syscalls = new AtomicReference<>(UnixGlob.DEFAULT_SYSCALLS); protected final AtomicReference pkgLocator = new AtomicReference<>(); protected final AtomicReference> deletedPackages = new AtomicReference<>(ImmutableSet.of()); private ImmutableMap artifactRoots; private final AtomicReference eventBus = new AtomicReference<>(); protected final AtomicReference tsgm = new AtomicReference<>(); protected final AtomicReference> clientEnv = new AtomicReference<>(); private final ImmutableMap buildInfoFactories; // Under normal circumstances, the artifact factory persists for the life of a Blaze server, but // since it is not yet created when we create the value builders, we have to use a supplier, // initialized when the build view is created. private final MutableArtifactFactorySupplier artifactFactory; // Used to give to WriteBuildInfoAction via a supplier. Relying on BuildVariableValue.BUILD_ID // would be preferable, but we have no way to have the Action depend on that value directly. // Having the BuildInfoFunction own the supplier is currently not possible either, because then // it would be invalidated on every build, since it would depend on the build id value. private final MutableSupplier buildId = new MutableSupplier<>(); private final ActionKeyContext actionKeyContext; protected boolean active = true; private final SkyframePackageManager packageManager; private final ResourceManager resourceManager; /** Used to lock evaluator on legacy calls to get existing values. */ private final Object valueLookupLock = new Object(); private final AtomicReference statusReporterRef = new AtomicReference<>(); private final SkyframeActionExecutor skyframeActionExecutor; private CompletionReceiver actionExecutionFunction; protected SkyframeProgressReceiver progressReceiver; private final AtomicReference cyclesReporter = new AtomicReference<>(); protected int modifiedFiles; protected int outputDirtyFiles; protected int modifiedFilesDuringPreviousBuild; private final ExternalFileAction externalFileAction; private final ImmutableMap extraSkyFunctions; protected SkyframeIncrementalBuildMonitor incrementalBuildMonitor = new SkyframeIncrementalBuildMonitor(); private MutableSupplier> configurationFragments = new MutableSupplier<>(); private final ImmutableSet hardcodedBlacklistedPackagePrefixes; private final PathFragment additionalBlacklistedPackagePrefixesFile; private final RuleClassProvider ruleClassProvider; private final CrossRepositoryLabelViolationStrategy crossRepositoryLabelViolationStrategy; private final List buildFilesByPriority; private final ActionOnIOExceptionReadingBuildFile actionOnIOExceptionReadingBuildFile; private final boolean shouldUnblockCpuWorkWhenFetchingDeps; private final BuildOptions defaultBuildOptions; private PerBuildSyscallCache perBuildSyscallCache; private int lastConcurrencyLevel = -1; private static final Logger logger = Logger.getLogger(SkyframeExecutor.class.getName()); private final PathResolverFactory pathResolverFactory = new PathResolverFactoryImpl(); /** An {@link ArtifactResolverSupplier} that supports setting of an {@link ArtifactFactory}. */ public static class MutableArtifactFactorySupplier implements ArtifactResolverSupplier { private ArtifactFactory artifactFactory; void set(ArtifactFactory artifactFactory) { this.artifactFactory = artifactFactory; } @Override public ArtifactFactory get() { return artifactFactory; } } class PathResolverFactoryImpl implements PathResolverFactory { @Override public boolean shouldCreatePathResolverForArtifactValues() { return outputService != null && outputService.supportsPathResolverForArtifactValues(); } @Override public ArtifactPathResolver createPathResolverForArtifactValues( ActionInputMap actionInputMap, Map> expandedArtifacts) { Preconditions.checkState(shouldCreatePathResolverForArtifactValues()); return outputService.createPathResolverForArtifactValues( directories.getExecRoot().asFragment(), fileSystem, getPathEntries(), actionInputMap, expandedArtifacts); } } protected SkyframeExecutor( EvaluatorSupplier evaluatorSupplier, PackageFactory pkgFactory, FileSystem fileSystem, BlazeDirectories directories, ActionKeyContext actionKeyContext, WorkspaceStatusAction.Factory workspaceStatusActionFactory, ImmutableList buildInfoFactories, ImmutableMap extraSkyFunctions, ExternalFileAction externalFileAction, ImmutableSet hardcodedBlacklistedPackagePrefixes, PathFragment additionalBlacklistedPackagePrefixesFile, CrossRepositoryLabelViolationStrategy crossRepositoryLabelViolationStrategy, List buildFilesByPriority, ActionOnIOExceptionReadingBuildFile actionOnIOExceptionReadingBuildFile, boolean shouldUnblockCpuWorkWhenFetchingDeps, GraphInconsistencyReceiver graphInconsistencyReceiver, BuildOptions defaultBuildOptions, @Nullable PackageProgressReceiver packageProgress, MutableArtifactFactorySupplier artifactResolverSupplier) { // Strictly speaking, these arguments are not required for initialization, but all current // callsites have them at hand, so we might as well set them during construction. this.evaluatorSupplier = evaluatorSupplier; this.pkgFactory = pkgFactory; this.shouldUnblockCpuWorkWhenFetchingDeps = shouldUnblockCpuWorkWhenFetchingDeps; this.graphInconsistencyReceiver = graphInconsistencyReceiver; this.pkgFactory.setSyscalls(syscalls); this.workspaceStatusActionFactory = workspaceStatusActionFactory; this.packageManager = new SkyframePackageManager( new SkyframePackageLoader(), new SkyframeTransitivePackageLoader(), syscalls, cyclesReporter, pkgLocator, numPackagesLoaded, this); this.resourceManager = ResourceManager.instance(); this.skyframeActionExecutor = new SkyframeActionExecutor(actionKeyContext, statusReporterRef, this::getPathEntries); this.fileSystem = fileSystem; this.directories = Preconditions.checkNotNull(directories); this.actionKeyContext = Preconditions.checkNotNull(actionKeyContext); ImmutableMap.Builder factoryMapBuilder = ImmutableMap.builder(); for (BuildInfoFactory factory : buildInfoFactories) { factoryMapBuilder.put(factory.getKey(), factory); } this.buildInfoFactories = factoryMapBuilder.build(); this.extraSkyFunctions = extraSkyFunctions; this.externalFileAction = externalFileAction; this.hardcodedBlacklistedPackagePrefixes = hardcodedBlacklistedPackagePrefixes; this.additionalBlacklistedPackagePrefixesFile = additionalBlacklistedPackagePrefixesFile; this.ruleClassProvider = pkgFactory.getRuleClassProvider(); this.defaultBuildOptions = defaultBuildOptions; this.skyframeBuildView = new SkyframeBuildView( directories, this, (ConfiguredRuleClassProvider) ruleClassProvider, skyframeActionExecutor); this.artifactFactory = artifactResolverSupplier; this.artifactFactory.set(skyframeBuildView.getArtifactFactory()); this.externalFilesHelper = ExternalFilesHelper.create( pkgLocator, this.externalFileAction, directories); this.crossRepositoryLabelViolationStrategy = crossRepositoryLabelViolationStrategy; this.buildFilesByPriority = buildFilesByPriority; this.actionOnIOExceptionReadingBuildFile = actionOnIOExceptionReadingBuildFile; this.packageProgress = packageProgress; } private ImmutableMap skyFunctions( PackageFactory pkgFactory) { ConfiguredRuleClassProvider ruleClassProvider = (ConfiguredRuleClassProvider) pkgFactory.getRuleClassProvider(); SkylarkImportLookupFunction skylarkImportLookupFunctionForInlining = getSkylarkImportLookupFunctionForInlining(); // TODO(janakr): use this semaphore to bound memory usage for SkyFunctions besides // ConfiguredTargetFunction that may have a large temporary memory blow-up. Semaphore cpuBoundSemaphore = new Semaphore(ResourceUsage.getAvailableProcessors()); // We use an immutable map builder for the nice side effect that it throws if a duplicate key // is inserted. ImmutableMap.Builder map = ImmutableMap.builder(); map.put(SkyFunctions.PRECOMPUTED, new PrecomputedFunction()); map.put(SkyFunctions.CLIENT_ENVIRONMENT_VARIABLE, new ClientEnvironmentFunction(clientEnv)); map.put(SkyFunctions.ACTION_ENVIRONMENT_VARIABLE, new ActionEnvironmentFunction()); map.put(FileStateValue.FILE_STATE, new FileStateFunction(tsgm, externalFilesHelper)); map.put(SkyFunctions.DIRECTORY_LISTING_STATE, new DirectoryListingStateFunction(externalFilesHelper)); map.put(SkyFunctions.FILE_SYMLINK_CYCLE_UNIQUENESS, new FileSymlinkCycleUniquenessFunction()); map.put(SkyFunctions.FILE_SYMLINK_INFINITE_EXPANSION_UNIQUENESS, new FileSymlinkInfiniteExpansionUniquenessFunction()); map.put(FileValue.FILE, new FileFunction(pkgLocator)); map.put(SkyFunctions.DIRECTORY_LISTING, new DirectoryListingFunction()); map.put( SkyFunctions.PACKAGE_LOOKUP, new PackageLookupFunction( deletedPackages, crossRepositoryLabelViolationStrategy, buildFilesByPriority)); map.put(SkyFunctions.CONTAINING_PACKAGE_LOOKUP, new ContainingPackageLookupFunction()); map.put(SkyFunctions.AST_FILE_LOOKUP, new ASTFileLookupFunction(ruleClassProvider)); map.put( SkyFunctions.SKYLARK_IMPORTS_LOOKUP, newSkylarkImportLookupFunction(ruleClassProvider, pkgFactory)); map.put(SkyFunctions.GLOB, newGlobFunction()); map.put(SkyFunctions.TARGET_PATTERN, new TargetPatternFunction()); map.put(SkyFunctions.PREPARE_DEPS_OF_PATTERNS, new PrepareDepsOfPatternsFunction()); map.put(SkyFunctions.PREPARE_DEPS_OF_PATTERN, new PrepareDepsOfPatternFunction(pkgLocator)); map.put( SkyFunctions.PREPARE_DEPS_OF_TARGETS_UNDER_DIRECTORY, new PrepareDepsOfTargetsUnderDirectoryFunction(directories)); map.put(SkyFunctions.COLLECT_TARGETS_IN_PACKAGE, new CollectTargetsInPackageFunction()); map.put( SkyFunctions.COLLECT_PACKAGES_UNDER_DIRECTORY, new CollectPackagesUnderDirectoryFunction(directories)); map.put(SkyFunctions.BLACKLISTED_PACKAGE_PREFIXES, new BlacklistedPackagePrefixesFunction( hardcodedBlacklistedPackagePrefixes, additionalBlacklistedPackagePrefixesFile)); map.put(SkyFunctions.TESTS_IN_SUITE, new TestsInSuiteFunction()); map.put(SkyFunctions.TEST_SUITE_EXPANSION, new TestSuiteExpansionFunction()); map.put(SkyFunctions.TARGET_PATTERN_PHASE, new TargetPatternPhaseFunction()); map.put( SkyFunctions.PREPARE_ANALYSIS_PHASE, new PrepareAnalysisPhaseFunction(ruleClassProvider, defaultBuildOptions)); map.put(SkyFunctions.RECURSIVE_PKG, new RecursivePkgFunction(directories)); map.put( SkyFunctions.PACKAGE, new PackageFunction( pkgFactory, packageManager, showLoadingProgress, packageFunctionCache, astCache, numPackagesLoaded, skylarkImportLookupFunctionForInlining, packageProgress, actionOnIOExceptionReadingBuildFile, IncrementalityIntent.INCREMENTAL)); map.put(SkyFunctions.PACKAGE_ERROR, new PackageErrorFunction()); map.put(SkyFunctions.PACKAGE_ERROR_MESSAGE, new PackageErrorMessageFunction()); map.put(SkyFunctions.TARGET_MARKER, new TargetMarkerFunction()); map.put(SkyFunctions.TARGET_PATTERN_ERROR, new TargetPatternErrorFunction()); map.put(SkyFunctions.TRANSITIVE_TARGET, new TransitiveTargetFunction(ruleClassProvider)); map.put(Label.TRANSITIVE_TRAVERSAL, new TransitiveTraversalFunction()); map.put( SkyFunctions.CONFIGURED_TARGET, new ConfiguredTargetFunction( new BuildViewProvider(), ruleClassProvider, cpuBoundSemaphore, shouldStoreTransitivePackagesInLoadingAndAnalysis(), shouldUnblockCpuWorkWhenFetchingDeps, defaultBuildOptions)); map.put( SkyFunctions.ASPECT, new AspectFunction( new BuildViewProvider(), ruleClassProvider, skylarkImportLookupFunctionForInlining, shouldStoreTransitivePackagesInLoadingAndAnalysis(), defaultBuildOptions)); map.put( SkyFunctions.LOAD_SKYLARK_ASPECT, new ToplevelSkylarkAspectFunction(skylarkImportLookupFunctionForInlining)); map.put( SkyFunctions.POST_CONFIGURED_TARGET, new PostConfiguredTargetFunction( new BuildViewProvider(), ruleClassProvider, defaultBuildOptions)); map.put( SkyFunctions.BUILD_CONFIGURATION, new BuildConfigurationFunction(directories, ruleClassProvider, defaultBuildOptions)); map.put( SkyFunctions.CONFIGURATION_FRAGMENT, new ConfigurationFragmentFunction(configurationFragments, ruleClassProvider)); map.put(SkyFunctions.WORKSPACE_NAME, new WorkspaceNameFunction()); map.put(SkyFunctions.WORKSPACE_AST, new WorkspaceASTFunction(ruleClassProvider)); map.put( SkyFunctions.WORKSPACE_FILE, new WorkspaceFileFunction(ruleClassProvider, pkgFactory, directories)); map.put(SkyFunctions.EXTERNAL_PACKAGE, new ExternalPackageFunction()); map.put( SkyFunctions.TARGET_COMPLETION, CompletionFunction.targetCompletionFunction(pathResolverFactory)); map.put( SkyFunctions.ASPECT_COMPLETION, CompletionFunction.aspectCompletionFunction(pathResolverFactory)); map.put(SkyFunctions.TEST_COMPLETION, new TestCompletionFunction()); map.put(Artifact.ARTIFACT, new ArtifactFunction()); map.put( SkyFunctions.BUILD_INFO_COLLECTION, new BuildInfoCollectionFunction( actionKeyContext, artifactFactory::get, buildInfoFactories)); map.put(SkyFunctions.BUILD_INFO, new WorkspaceStatusFunction(this::makeWorkspaceStatusAction)); map.put(SkyFunctions.COVERAGE_REPORT, new CoverageReportFunction(actionKeyContext)); ActionExecutionFunction actionExecutionFunction = new ActionExecutionFunction(skyframeActionExecutor, directories, tsgm); map.put(SkyFunctions.ACTION_EXECUTION, actionExecutionFunction); this.actionExecutionFunction = actionExecutionFunction; map.put(SkyFunctions.RECURSIVE_FILESYSTEM_TRAVERSAL, new RecursiveFilesystemTraversalFunction()); map.put(SkyFunctions.FILESET_ENTRY, new FilesetEntryFunction()); map.put( SkyFunctions.ACTION_TEMPLATE_EXPANSION, new ActionTemplateExpansionFunction(actionKeyContext)); map.put(SkyFunctions.LOCAL_REPOSITORY_LOOKUP, new LocalRepositoryLookupFunction()); map.put( SkyFunctions.REGISTERED_EXECUTION_PLATFORMS, new RegisteredExecutionPlatformsFunction()); map.put(SkyFunctions.REGISTERED_TOOLCHAINS, new RegisteredToolchainsFunction()); map.put(SkyFunctions.TOOLCHAIN_RESOLUTION, new ToolchainResolutionFunction()); map.put(SkyFunctions.REPOSITORY_MAPPING, new RepositoryMappingFunction()); map.put(SkyFunctions.RESOLVED_HASH_VALUES, new ResolvedHashesFunction()); map.putAll(extraSkyFunctions); return map.build(); } protected SkyFunction newGlobFunction() { return new GlobFunction(/*alwaysUseDirListing=*/false); } @Nullable protected SkylarkImportLookupFunction getSkylarkImportLookupFunctionForInlining() { return null; } protected SkyFunction newSkylarkImportLookupFunction( RuleClassProvider ruleClassProvider, PackageFactory pkgFactory) { return new SkylarkImportLookupFunction(ruleClassProvider, this.pkgFactory); } protected PerBuildSyscallCache newPerBuildSyscallCache(int concurrencyLevel) { return PerBuildSyscallCache.newBuilder().setConcurrencyLevel(concurrencyLevel).build(); } /** * Gets a (possibly cached) syscalls cache, re-initialized each build. * *

We cache the syscalls cache if possible because construction of the cache is surprisingly * expensive, and is on the critical path of null builds. */ protected final PerBuildSyscallCache getPerBuildSyscallCache(int concurrencyLevel) { if (perBuildSyscallCache != null && lastConcurrencyLevel == concurrencyLevel) { perBuildSyscallCache.clear(); return perBuildSyscallCache; } lastConcurrencyLevel = concurrencyLevel; perBuildSyscallCache = newPerBuildSyscallCache(concurrencyLevel); return perBuildSyscallCache; } @ThreadCompatible public void setActive(boolean active) { this.active = active; } protected void checkActive() { Preconditions.checkState(active); } public void configureActionExecutor( MetadataProvider fileCache, ActionInputPrefetcher actionInputPrefetcher) { this.skyframeActionExecutor.configure(fileCache, actionInputPrefetcher); } public void dump(boolean summarize, PrintStream out) { memoizingEvaluator.dump(summarize, out); } public abstract void dumpPackages(PrintStream out); public void setOutputService(OutputService outputService) { this.outputService = outputService; } /** Inform this SkyframeExecutor that a new command is starting. */ public void noteCommandStart() {} /** * Notify listeners about changed files, and release any associated memory afterwards. */ public void drainChangedFiles() { incrementalBuildMonitor.alertListeners(getEventBus()); incrementalBuildMonitor = null; } @VisibleForTesting public BuildDriver getDriverForTesting() { return buildDriver; } /** * This method exists only to allow a module to make a top-level Skyframe call during the * transition to making it fully Skyframe-compatible. Do not add additional callers! */ public SkyValue evaluateSkyKeyForExecutionSetup( final ExtendedEventHandler eventHandler, final SkyKey key) throws EnvironmentalExecException, InterruptedException { synchronized (valueLookupLock) { // We evaluate in keepGoing mode because in the case that the graph does not store its // edges, nokeepGoing builds are not allowed, whereas keepGoing builds are always // permitted. EvaluationResult result = buildDriver.evaluate( ImmutableList.of(key), true, ResourceUsage.getAvailableProcessors(), eventHandler); if (!result.hasError()) { return Preconditions.checkNotNull(result.get(key), "%s %s", result, key); } ErrorInfo errorInfo = Preconditions.checkNotNull(result.getError(key), "%s %s", key, result); Throwables.propagateIfPossible(errorInfo.getException(), EnvironmentalExecException.class); if (errorInfo.getException() != null) { throw new IllegalStateException(errorInfo.getException()); } throw new IllegalStateException(errorInfo.toString()); } } public abstract ActionGraphContainer getActionGraphContainer( List actionGraphTargets, boolean includeActionCmdLine) throws CommandLineExpansionException; class BuildViewProvider { /** * Returns the current {@link SkyframeBuildView} instance. */ SkyframeBuildView getSkyframeBuildView() { return skyframeBuildView; } } /** * Must be called before the {@link SkyframeExecutor} can be used (should only be called in * factory methods and as an implementation detail of {@link #resetEvaluator}). */ protected void init() { progressReceiver = newSkyframeProgressReceiver(); ImmutableMap skyFunctions = skyFunctions(pkgFactory); memoizingEvaluator = evaluatorSupplier.create( skyFunctions, evaluatorDiffer(), progressReceiver, graphInconsistencyReceiver, DEFAULT_FILTER_WITH_ACTIONS, emittedEventState, tracksStateForIncrementality()); buildDriver = getBuildDriver(); } /** * Use the fact that analysis of a target must occur before execution of that target, and in a * separate Skyframe evaluation, to avoid propagating events from configured target nodes (and * more generally action lookup nodes) to action execution nodes. We take advantage of the fact * that if a node depends on an action lookup node and is not itself an action lookup node, then * it is an execution-phase node: the action lookup nodes are terminal in the analysis phase. */ private static final EventFilter DEFAULT_FILTER_WITH_ACTIONS = new EventFilter() { @Override public boolean storeEventsAndPosts() { return true; } @Override public boolean apply(Event input) { // Use the filtering defined in the default filter: no info/progress messages. return InMemoryMemoizingEvaluator.DEFAULT_STORED_EVENT_FILTER.apply(input); } @Override public Predicate depEdgeFilterForEventsAndPosts(SkyKey primaryKey) { if (primaryKey instanceof ActionLookupValue.ActionLookupKey) { return Predicates.alwaysTrue(); } else { return NO_ACTION_LOOKUP; } } }; private static final Predicate NO_ACTION_LOOKUP = (key) -> !(key instanceof ActionLookupValue.ActionLookupKey); protected SkyframeProgressReceiver newSkyframeProgressReceiver() { return new SkyframeProgressReceiver(); } /** Reinitializes the Skyframe evaluator, dropping all previously computed values. */ public void resetEvaluator() { init(); emittedEventState.clear(); skyframeBuildView.clearLegacyData(); } /** * Notifies the executor that the command is complete. May safely be called multiple times for a * single command, so callers should err on the side of calling it more frequently. Should be * idempotent, so that calls after the first one in the same evaluation should be quick. */ public void notifyCommandComplete() throws InterruptedException { memoizingEvaluator.noteEvaluationsAtSameVersionMayBeFinished(); } protected abstract Differencer evaluatorDiffer(); protected abstract BuildDriver getBuildDriver(); /** Clear any configured target data stored outside Skyframe. */ public void handleConfiguredTargetChange() { skyframeBuildView.clearInvalidatedConfiguredTargets(); skyframeBuildView.clearLegacyData(); } /** Used with dump --rules. */ public static class RuleStat { private final String key; private final String name; private final boolean isRule; private long count; private long actionCount; public RuleStat(String key, String name, boolean isRule) { this.key = key; this.name = name; this.isRule = isRule; } public void addRule(long actionCount) { this.count++; this.actionCount += actionCount; } /** Returns a key that uniquely identifies this rule or aspect. */ public String getKey() { return key; } /** Returns a name for the rule or aspect. */ public String getName() { return name; } /** Returns whether this is a rule or an aspect. */ public boolean isRule() { return isRule; } /** Returns the instance count of this rule or aspect class. */ public long getCount() { return count; } /** Returns the total action count of all instance of this rule or aspect class. */ public long getActionCount() { return actionCount; } } /** Computes statistics on heap-resident rules and aspects. */ public abstract List getRuleStats(ExtendedEventHandler eventHandler); /** Removes ConfigurationFragmentValues from the cache. */ @VisibleForTesting public void resetConfigurationCollectionForTesting() { memoizingEvaluator.delete( SkyFunctionName.functionIsIn(ImmutableSet.of(SkyFunctions.CONFIGURATION_FRAGMENT))); } /** * Decides if graph edges should be stored during this evaluation and checks if the state from the * last evaluation, if any, can be kept. * *

If not, it will mark this state for deletion. The actual cleaning is put off until {@link * #sync}, in case no evaluation was actually called for and the existing state can be kept for * longer. */ public void decideKeepIncrementalState( boolean batch, boolean keepStateAfterBuild, boolean trackIncrementalState, boolean discardAnalysisCache, EventHandler eventHandler) { // Assume incrementality. } /** Whether this executor tracks state for the purpose of improving incremental performance. */ public boolean tracksStateForIncrementality() { return true; } /** * If not null, this is the only source root in the build, corresponding to the single element in * a single-element package path. Such a single-source-root build need not plant the execroot * symlink forest, and can trivially resolve source artifacts from exec paths. As a consequence, * builds where this is not null do not need to track a package -> source root map, and so do not * need to track all loaded packages. */ @Nullable protected Root getForcedSingleSourceRootIfNoExecrootSymlinkCreation() { return null; } private boolean shouldStoreTransitivePackagesInLoadingAndAnalysis() { return getForcedSingleSourceRootIfNoExecrootSymlinkCreation() == null; } @VisibleForTesting protected abstract Injectable injectable(); /** * Saves memory by clearing analysis objects from Skyframe. If using legacy execution, actually * deletes the relevant values. If using Skyframe execution, clears their data without deleting * them (they will be deleted on the next build). */ public abstract void clearAnalysisCache( Collection topLevelTargets, Collection topLevelAspects); /** * Injects the contents of the computed tools/defaults package. */ @VisibleForTesting public void setupDefaultPackage(String defaultsPackageContents) { PrecomputedValue.DEFAULTS_PACKAGE_CONTENTS.set(injectable(), defaultsPackageContents); } private WorkspaceStatusAction makeWorkspaceStatusAction(String workspaceName) { return workspaceStatusActionFactory.createWorkspaceStatusAction( artifactFactory.get(), WorkspaceStatusValue.BUILD_INFO_KEY, workspaceName); } @VisibleForTesting public WorkspaceStatusAction.Factory getWorkspaceStatusActionFactoryForTesting() { return workspaceStatusActionFactory; } @VisibleForTesting public ArtifactResolverSupplier getArtifactResolverSupplierForTesting() { return artifactFactory; } @VisibleForTesting @Nullable public WorkspaceStatusAction getLastWorkspaceStatusAction() throws InterruptedException { WorkspaceStatusValue workspaceStatusValue = (WorkspaceStatusValue) memoizingEvaluator.getExistingValue(WorkspaceStatusValue.BUILD_INFO_KEY); return workspaceStatusValue == null ? null : (WorkspaceStatusAction) workspaceStatusValue.getAction(0); } public void injectCoverageReportData(ImmutableList actions) { PrecomputedValue.COVERAGE_REPORT_KEY.set(injectable(), actions); } private void setDefaultVisibility(RuleVisibility defaultVisibility) { PrecomputedValue.DEFAULT_VISIBILITY.set(injectable(), defaultVisibility); } protected void setSkylarkSemantics(SkylarkSemantics skylarkSemantics) { PrecomputedValue.SKYLARK_SEMANTICS.set(injectable(), skylarkSemantics); } public void injectExtraPrecomputedValues( List extraPrecomputedValues) { for (PrecomputedValue.Injected injected : extraPrecomputedValues) { injected.inject(injectable()); } } protected Cache newPkgFunctionCache() { return CacheBuilder.newBuilder().build(); } protected Cache newAstCache() { return CacheBuilder.newBuilder().build(); } public ImmutableMap getBuildInfoFactories() { return buildInfoFactories; } private void setShowLoadingProgress(boolean showLoadingProgressValue) { showLoadingProgress.set(showLoadingProgressValue); } @VisibleForTesting public void setCommandId(UUID commandId) { PrecomputedValue.BUILD_ID.set(injectable(), commandId); buildId.set(commandId); } /** Returns the build-info.txt and build-changelist.txt artifacts. */ public Collection getWorkspaceStatusArtifacts(ExtendedEventHandler eventHandler) throws InterruptedException { // Should already be present, unless the user didn't request any targets for analysis. EvaluationResult result = buildDriver.evaluate( ImmutableList.of(WorkspaceStatusValue.BUILD_INFO_KEY), /*keepGoing=*/ true, /*numThreads=*/ 1, eventHandler); WorkspaceStatusValue value = Preconditions.checkNotNull(result.get(WorkspaceStatusValue.BUILD_INFO_KEY)); return ImmutableList.of(value.getStableArtifact(), value.getVolatileArtifact()); } public Map getArtifactRootsForFiles( final ExtendedEventHandler eventHandler, Iterable execPaths) throws InterruptedException { return getArtifactRoots(eventHandler, execPaths, true); } public Map getArtifactRoots( final ExtendedEventHandler eventHandler, Iterable execPaths) throws InterruptedException { return getArtifactRoots(eventHandler, execPaths, false); } private Map getArtifactRoots( final ExtendedEventHandler eventHandler, Iterable execPaths, boolean forFiles) throws InterruptedException { final Map packageKeys = new HashMap<>(); for (PathFragment execPath : execPaths) { try { PackageIdentifier pkgIdentifier = PackageIdentifier.discoverFromExecPath(execPath, forFiles); packageKeys.put(execPath, ContainingPackageLookupValue.key(pkgIdentifier)); } catch (LabelSyntaxException e) { continue; } } EvaluationResult result; synchronized (valueLookupLock) { result = buildDriver.evaluate( packageKeys.values(), /*keepGoing=*/ true, /*numThreads=*/ 1, eventHandler); } if (result.hasError()) { return new HashMap<>(); } Map roots = new HashMap<>(); for (PathFragment execPath : execPaths) { ContainingPackageLookupValue value = result.get(packageKeys.get(execPath)); if (value.hasContainingPackage()) { roots.put( execPath, maybeTransformRootForRepository( value.getContainingPackageRoot(), value.getContainingPackageName().getRepository())); } else { roots.put(execPath, null); } } return roots; } // This must always be consistent with Package.getSourceRoot; otherwise computing source roots // from exec paths does not work, which can break the action cache for input-discovering actions. static Root maybeTransformRootForRepository(Root packageRoot, RepositoryName repository) { if (repository.isMain()) { return packageRoot; } else { Path actualRootPath = packageRoot.asPath(); int segmentCount = repository.getSourceRoot().segmentCount(); for (int i = 0; i < segmentCount; i++) { actualRootPath = actualRootPath.getParentDirectory(); } return Root.fromPath(actualRootPath); } } @VisibleForTesting public ToolchainContext getToolchainContextForTesting( Set

MUST be run before every incremental build. */ @VisibleForTesting // productionVisibility = Visibility.PRIVATE public void preparePackageLoading( PathPackageLocator pkgLocator, PackageCacheOptions packageCacheOptions, SkylarkSemanticsOptions skylarkSemanticsOptions, String defaultsPackageContents, UUID commandId, Map clientEnv, TimestampGranularityMonitor tsgm) { Preconditions.checkNotNull(pkgLocator); Preconditions.checkNotNull(tsgm); setActive(true); this.tsgm.set(tsgm); setCommandId(commandId); this.clientEnv.set(clientEnv); setShowLoadingProgress(packageCacheOptions.showLoadingProgress); setDefaultVisibility(packageCacheOptions.defaultVisibility); setSkylarkSemantics(skylarkSemanticsOptions.toSkylarkSemantics()); if (packageCacheOptions.experimentalInMemoryToolsDefaultsPackage) { setupDefaultPackage(defaultsPackageContents); PrecomputedValue.ENABLE_DEFAULTS_PACKAGE.set(injectable(), true); } else { setupDefaultPackage("# //tools/defaults in-memory package is not enabled."); PrecomputedValue.ENABLE_DEFAULTS_PACKAGE.set(injectable(), false); } setPackageLocator(pkgLocator); syscalls.set(getPerBuildSyscallCache(packageCacheOptions.globbingThreads)); this.pkgFactory.setGlobbingThreads(packageCacheOptions.globbingThreads); this.pkgFactory.setMaxDirectoriesToEagerlyVisitInGlobbing( packageCacheOptions.maxDirectoriesToEagerlyVisitInGlobbing); emittedEventState.clear(); // If the PackageFunction was interrupted, there may be stale entries here. packageFunctionCache.invalidateAll(); astCache.invalidateAll(); numPackagesLoaded.set(0); if (packageProgress != null) { packageProgress.reset(); } // Reset the stateful SkyframeCycleReporter, which contains cycles from last run. cyclesReporter.set(createCyclesReporter()); } @SuppressWarnings("unchecked") private void setPackageLocator(PathPackageLocator pkgLocator) { PathPackageLocator oldLocator = this.pkgLocator.getAndSet(pkgLocator); PrecomputedValue.PATH_PACKAGE_LOCATOR.set(injectable(), pkgLocator); if (!pkgLocator.equals(oldLocator)) { // The package path is read not only by SkyFunctions but also by some other code paths. // We need to take additional steps to keep the corresponding data structures in sync. // (Some of the additional steps are carried out by ConfiguredTargetValueInvalidationListener, // and some by BuildView#buildHasIncompatiblePackageRoots and #updateSkyframe.) artifactFactory .get() .setSourceArtifactRoots( createSourceArtifactRootMapOnNewPkgLocator(oldLocator, pkgLocator)); } } protected ImmutableMap createSourceArtifactRootMapOnNewPkgLocator( PathPackageLocator oldLocator, PathPackageLocator pkgLocator) { // TODO(bazel-team): The output base is a legitimate "source root" because external repositories // stage their sources under output_base/external. The root here should really be // output_base/external, but for some reason it isn't. return Stream.concat( pkgLocator.getPathEntries().stream(), Stream.of(Root.absoluteRoot(fileSystem), Root.fromPath(directories.getOutputBase()))) .distinct() .collect( ImmutableMap.toImmutableMap( java.util.function.Function.identity(), ArtifactRoot::asSourceRoot)); } public SkyframeBuildView getSkyframeBuildView() { return skyframeBuildView; } /** * Sets the eventBus to use for posting events. */ public void setEventBus(EventBus eventBus) { this.eventBus.set(eventBus); } public void setClientEnv(Map clientEnv) { this.skyframeActionExecutor.setClientEnv(clientEnv); } /** * Sets the path for action log buffers. */ public void setActionOutputRoot(Path actionOutputRoot) { Preconditions.checkNotNull(actionOutputRoot); this.actionLogBufferPathGenerator = new ActionLogBufferPathGenerator(actionOutputRoot); this.skyframeActionExecutor.setActionLogBufferPathGenerator(actionLogBufferPathGenerator); } /** * Sets the factories for all configuration fragments known to the build. */ public void setConfigurationFragmentFactories( List configurationFragmentFactories) { this.configurationFragments.set(ImmutableList.copyOf(configurationFragmentFactories)); } /** * Asks the Skyframe evaluator to build the value for BuildConfigurationCollection and returns the * result. */ // TODO(ulfjack): Remove this legacy method after switching to the Skyframe-based implementation. public BuildConfigurationCollection createConfigurations( ExtendedEventHandler eventHandler, BuildOptions buildOptions, Set multiCpu, boolean keepGoing) throws InvalidConfigurationException { List topLevelTargetConfigs = getConfigurations( eventHandler, PrepareAnalysisPhaseFunction.getTopLevelBuildOptions(buildOptions, multiCpu), keepGoing); BuildConfiguration firstTargetConfig = topLevelTargetConfigs.get(0); BuildOptions targetOptions = firstTargetConfig.getOptions(); BuildOptions hostOptions = targetOptions.get(BuildConfiguration.Options.class).useDistinctHostConfiguration ? HostTransition.INSTANCE.patch(targetOptions) : targetOptions; BuildConfiguration hostConfig = getConfiguration(eventHandler, hostOptions, keepGoing); // TODO(gregce): cache invalid option errors in BuildConfigurationFunction, then use a dedicated // accessor (i.e. not the event handler) to trigger the exception below. ErrorSensingEventHandler nosyEventHandler = new ErrorSensingEventHandler(eventHandler); topLevelTargetConfigs.forEach(config -> config.reportInvalidOptions(nosyEventHandler)); if (nosyEventHandler.hasErrors()) { throw new InvalidConfigurationException("Build options are invalid"); } return new BuildConfigurationCollection(topLevelTargetConfigs, hostConfig); } /** * Asks the Skyframe evaluator to build the given artifacts and targets, and to test the * given test targets. */ public EvaluationResult buildArtifacts( Reporter reporter, Executor executor, Set artifactsToBuild, Collection targetsToBuild, Collection aspects, Set targetsToTest, boolean exclusiveTesting, boolean keepGoing, boolean explain, boolean finalizeActionsToOutputService, int numJobs, ActionCacheChecker actionCacheChecker, @Nullable EvaluationProgressReceiver executionProgressReceiver, TopLevelArtifactContext topLevelArtifactContext) throws InterruptedException { checkActive(); Preconditions.checkState(actionLogBufferPathGenerator != null); try (SilentCloseable c = Profiler.instance().profile("skyframeActionExecutor.prepareForExecution")) { skyframeActionExecutor.prepareForExecution( reporter, executor, keepGoing, explain, actionCacheChecker, finalizeActionsToOutputService ? outputService : null); } resourceManager.resetResourceUsage(); try { progressReceiver.executionProgressReceiver = executionProgressReceiver; Iterable targetKeys = TargetCompletionValue.keys(targetsToBuild, topLevelArtifactContext, targetsToTest); Iterable aspectKeys = AspectCompletionValue.keys(aspects, topLevelArtifactContext); Iterable testKeys = TestCompletionValue.keys(targetsToTest, topLevelArtifactContext, exclusiveTesting); return buildDriver.evaluate( Iterables.concat(artifactsToBuild, targetKeys, aspectKeys, testKeys), keepGoing, numJobs, reporter); } finally { progressReceiver.executionProgressReceiver = null; // Also releases thread locks. resourceManager.resetResourceUsage(); skyframeActionExecutor.executionOver(); actionExecutionFunction.complete(); } } @VisibleForTesting public void prepareBuildingForTestingOnly(Reporter reporter, Executor executor, boolean keepGoing, boolean explain, ActionCacheChecker checker) { skyframeActionExecutor.prepareForExecution(reporter, executor, keepGoing, explain, checker, outputService); } EvaluationResult targetPatterns( Iterable patternSkyKeys, int numThreads, boolean keepGoing, ExtendedEventHandler eventHandler) throws InterruptedException { checkActive(); return buildDriver.evaluate(patternSkyKeys, keepGoing, numThreads, eventHandler); } @VisibleForTesting public BuildOptions getDefaultBuildOptions() { return defaultBuildOptions; } /** * Returns the {@link ConfiguredTargetAndData}s corresponding to the given keys. * *

For use for legacy support and tests calling through {@code BuildView} only. * *

If a requested configured target is in error, the corresponding value is omitted from the * returned list. */ @ThreadSafety.ThreadSafe public ImmutableList getConfiguredTargetsForTesting( ExtendedEventHandler eventHandler, BuildConfiguration originalConfig, Iterable keys) { return getConfiguredTargetMapForTesting(eventHandler, originalConfig, keys).values().asList(); } /** * Returns the {@link ConfiguredTargetAndData}s corresponding to the given keys. * *

For use for legacy support and tests calling through {@code BuildView} only. * *

If a requested configured target is in error, the corresponding value is omitted from the * returned list. */ @ThreadSafety.ThreadSafe public ImmutableList getConfiguredTargetsForTesting( ExtendedEventHandler eventHandler, BuildConfigurationValue.Key originalConfig, Iterable keys) { return getConfiguredTargetMapForTesting(eventHandler, originalConfig, keys).values().asList(); } /** * Returns a map from {@link Dependency} inputs to the {@link ConfiguredTargetAndData}s * corresponding to those dependencies. * *

For use for legacy support and tests calling through {@code BuildView} only. * *

If a requested configured target is in error, the corresponding value is omitted from the * returned list. */ @ThreadSafety.ThreadSafe public ImmutableMultimap getConfiguredTargetMapForTesting( ExtendedEventHandler eventHandler, BuildConfigurationValue.Key originalConfig, Iterable keys) { return getConfiguredTargetMapForTesting( eventHandler, getConfiguration(eventHandler, originalConfig), keys); } /** * Returns a map from {@link Dependency} inputs to the {@link ConfiguredTargetAndData}s * corresponding to those dependencies. * *

For use for legacy support and tests calling through {@code BuildView} only. * *

If a requested configured target is in error, the corresponding value is omitted from the * returned list. */ @ThreadSafety.ThreadSafe private ImmutableMultimap getConfiguredTargetMapForTesting( ExtendedEventHandler eventHandler, BuildConfiguration originalConfig, Iterable keys) { checkActive(); Multimap configs; if (originalConfig != null) { configs = getConfigurations(eventHandler, originalConfig.getOptions(), keys); } else { configs = ArrayListMultimap.create(); for (Dependency key : keys) { configs.put(key, null); } } final List skyKeys = new ArrayList<>(); for (Dependency key : keys) { if (!configs.containsKey(key)) { // If we couldn't compute a configuration for this target, the target was in error (e.g. // it couldn't be loaded). Exclude it from the results. continue; } for (BuildConfiguration depConfig : configs.get(key)) { skyKeys.add(ConfiguredTargetValue.key(key.getLabel(), depConfig)); for (AspectDescriptor aspectDescriptor : key.getAspects().getAllAspects()) { skyKeys.add( AspectValue.createAspectKey(key.getLabel(), depConfig, aspectDescriptor, depConfig)); } } skyKeys.add(PackageValue.key(key.getLabel().getPackageIdentifier())); } EvaluationResult result = evaluateSkyKeys(eventHandler, skyKeys); for (Map.Entry entry : result.errorMap().entrySet()) { reportCycles(eventHandler, entry.getValue().getCycleInfo(), entry.getKey()); } ImmutableMultimap.Builder cts = ImmutableMultimap.builder(); // Logic copied from ConfiguredTargetFunction#computeDependencies. Set aliasPackagesToFetch = new HashSet<>(); List aliasKeysToRedo = new ArrayList<>(); EvaluationResult aliasPackageValues = null; Iterable keysToProcess = keys; for (int i = 0; i < 2; i++) { DependentNodeLoop: for (Dependency key : keysToProcess) { if (!configs.containsKey(key)) { // If we couldn't compute a configuration for this target, the target was in error (e.g. // it couldn't be loaded). Exclude it from the results. continue; } for (BuildConfiguration depConfig : configs.get(key)) { SkyKey configuredTargetKey = ConfiguredTargetValue.key(key.getLabel(), depConfig); if (result.get(configuredTargetKey) == null) { continue; } ConfiguredTarget configuredTarget = ((ConfiguredTargetValue) result.get(configuredTargetKey)).getConfiguredTarget(); Label label = configuredTarget.getLabel(); SkyKey packageKey = PackageValue.key(label.getPackageIdentifier()); PackageValue packageValue; if (i == 0) { packageValue = (PackageValue) result.get(packageKey); if (packageValue == null) { aliasPackagesToFetch.add(packageKey); aliasKeysToRedo.add(key); continue; } } else { packageValue = (PackageValue) Preconditions.checkNotNull(aliasPackageValues.get(packageKey), packageKey); } List configuredAspects = new ArrayList<>(); for (AspectDescriptor aspectDescriptor : key.getAspects().getAllAspects()) { SkyKey aspectKey = AspectValue.createAspectKey(key.getLabel(), depConfig, aspectDescriptor, depConfig); if (result.get(aspectKey) == null) { continue DependentNodeLoop; } configuredAspects.add(((AspectValue) result.get(aspectKey)).getConfiguredAspect()); } try { ConfiguredTarget mergedTarget = MergedConfiguredTarget.of(configuredTarget, configuredAspects); cts.put( key, new ConfiguredTargetAndData( mergedTarget, packageValue.getPackage().getTarget(configuredTarget.getLabel().getName()), // This is terrible, but our tests' use of configurations is terrible. It's only // by accident that getting a null-configuration ConfiguredTarget works even if // depConfig is not null. mergedTarget.getConfigurationKey() == null ? null : depConfig)); } catch (DuplicateException | NoSuchTargetException e) { throw new IllegalStateException( String.format("Error creating %s", configuredTarget.getLabel()), e); } } } if (aliasKeysToRedo.isEmpty()) { break; } aliasPackageValues = evaluateSkyKeys(eventHandler, aliasPackagesToFetch); keysToProcess = aliasKeysToRedo; } return cts.build(); } /** * Returns the configuration corresponding to the given set of build options. Should not be used * in a world with trimmed configurations. * * @throws InvalidConfigurationException if the build options produces an invalid configuration */ @Deprecated public BuildConfiguration getConfiguration( ExtendedEventHandler eventHandler, BuildOptions options, boolean keepGoing) throws InvalidConfigurationException { return Iterables.getOnlyElement( getConfigurations(eventHandler, ImmutableList.of(options), keepGoing)); } @VisibleForTesting public BuildConfiguration getConfiguration( ExtendedEventHandler eventHandler, BuildConfigurationValue.Key configurationKey) { if (configurationKey == null) { return null; } return ((BuildConfigurationValue) evaluateSkyKeys(eventHandler, ImmutableList.of(configurationKey)).get(configurationKey)) .getConfiguration(); } public Map getConfigurations( ExtendedEventHandler eventHandler, Collection keys) { EvaluationResult evaluationResult = evaluateSkyKeys(eventHandler, keys); return keys.stream() .collect( Collectors.toMap( java.util.function.Function.identity(), (key) -> ((BuildConfigurationValue) evaluationResult.get(key)).getConfiguration())); } /** * Returns the configurations corresponding to the given sets of build options. Output order is * the same as input order. * * @throws InvalidConfigurationException if any build options produces an invalid configuration */ // TODO(ulfjack): Remove this legacy method after switching to the Skyframe-based implementation. public List getConfigurations( ExtendedEventHandler eventHandler, List optionsList, boolean keepGoing) throws InvalidConfigurationException { Preconditions.checkArgument(!Iterables.isEmpty(optionsList)); // Prepare the Skyframe inputs. // TODO(gregce): support trimmed configs. ImmutableSortedSet> allFragments = configurationFragments .get() .stream() .map(factory -> factory.creates()) .collect( ImmutableSortedSet.toImmutableSortedSet(BuildConfiguration.lexicalFragmentSorter)); final ImmutableList configSkyKeys = optionsList .stream() .map( elem -> BuildConfigurationValue.key( allFragments, BuildOptions.diffForReconstruction(defaultBuildOptions, elem))) .collect(ImmutableList.toImmutableList()); // Skyframe-evaluate the configurations and throw errors if any. EvaluationResult evalResult = evaluateSkyKeys(eventHandler, configSkyKeys, keepGoing); if (evalResult.hasError()) { Map.Entry firstError = Iterables.get(evalResult.errorMap().entrySet(), 0); ErrorInfo error = firstError.getValue(); Throwable e = error.getException(); // Wrap loading failed exceptions if (e instanceof NoSuchThingException) { e = new InvalidConfigurationException(e); } else if (e == null && !Iterables.isEmpty(error.getCycleInfo())) { getCyclesReporter().reportCycles(error.getCycleInfo(), firstError.getKey(), eventHandler); e = new InvalidConfigurationException( "cannot load build configuration because of this cycle"); } if (e != null) { Throwables.throwIfInstanceOf(e, InvalidConfigurationException.class); } throw new IllegalStateException( "Unknown error during configuration creation evaluation", e); } // Prepare and return the results. return configSkyKeys .stream() .map(key -> ((BuildConfigurationValue) evalResult.get(key)).getConfiguration()) .collect(ImmutableList.toImmutableList()); } /** * Retrieves the configurations needed for the given deps. If {@link * BuildConfiguration.Options#trimConfigurations()} is true, trims their fragments to only those * needed by their transitive closures. Else unconditionally includes all fragments. * *

Skips targets with loading phase errors. */ // Keep this in sync with {@link PrepareAnalysisPhaseFunction#getConfigurations}. // TODO(ulfjack): Remove this legacy method after switching to the Skyframe-based implementation. public Multimap getConfigurations( ExtendedEventHandler eventHandler, BuildOptions fromOptions, Iterable keys) { Multimap builder = ArrayListMultimap.create(); Set depsToEvaluate = new HashSet<>(); ImmutableSortedSet> allFragments = null; if (useUntrimmedConfigs(fromOptions)) { allFragments = ((ConfiguredRuleClassProvider) ruleClassProvider).getAllFragments(); } // Get the fragments needed for dynamic configuration nodes. final List transitiveFragmentSkyKeys = new ArrayList<>(); Map>> fragmentsMap = new HashMap<>(); Set

May throw an {@link InterruptedException}, which means that no values have been invalidated. */ @VisibleForTesting public abstract void invalidateFilesUnderPathForTesting( ExtendedEventHandler eventHandler, ModifiedFileSet modifiedFileSet, Root pathEntry) throws InterruptedException; /** * Invalidates SkyFrame values that may have failed for transient reasons. */ public abstract void invalidateTransientErrors(); /** Configures a given set of configured targets. */ EvaluationResult configureTargets( ExtendedEventHandler eventHandler, List values, List aspectKeys, boolean keepGoing, int numThreads) throws InterruptedException { checkActive(); List keys = new ArrayList<>(ConfiguredTargetValue.keys(values)); for (AspectValueKey aspectKey : aspectKeys) { keys.add(aspectKey); } EvaluationResult result = buildDriver.evaluate(keys, keepGoing, numThreads, eventHandler); // Get rid of any memory retained by the cache -- all loading is done. perBuildSyscallCache.clear(); return result; } /** * Post-process the targets. Values in the EvaluationResult are known to be transitively * error-free from action conflicts. */ public EvaluationResult postConfigureTargets( ExtendedEventHandler eventHandler, List values, boolean keepGoing, ImmutableMap badActions) throws InterruptedException { checkActive(); PrecomputedValue.BAD_ACTIONS.set(injectable(), badActions); // Make sure to not run too many analysis threads. This can cause memory thrashing. EvaluationResult result = buildDriver.evaluate(PostConfiguredTargetValue.keys(values), keepGoing, ResourceUsage.getAvailableProcessors(), eventHandler); // Remove all post-configured target values immediately for memory efficiency. We are OK with // this mini-phase being non-incremental as the failure mode of action conflict is rare. memoizingEvaluator.delete(SkyFunctionName.functionIs(SkyFunctions.POST_CONFIGURED_TARGET)); return result; } /** * Returns a Skyframe-based {@link SkyframeTransitivePackageLoader} implementation. */ @VisibleForTesting public TransitivePackageLoader pkgLoader() { checkActive(); return new SkyframeLabelVisitor(new SkyframeTransitivePackageLoader(), cyclesReporter); } class SkyframeTransitivePackageLoader { /** Loads the specified {@link TransitiveTargetValue}s. */ EvaluationResult loadTransitiveTargets( ExtendedEventHandler eventHandler, Iterable

The graph update is unconditionally done in keep-going mode, so that the query is guaranteed * a complete graph to work on. */ @Override public EvaluationResult prepareAndGet( Set roots, int numThreads, ExtendedEventHandler eventHandler) throws InterruptedException { EvaluationResult evaluationResult = buildDriver.evaluate(roots, true, numThreads, eventHandler); return evaluationResult; } /** * Get metadata related to the prepareAndGet() lookup. Resulting data is specific to the * underlying evaluation implementation. */ public String prepareAndGetMetadata(Collection patterns, String offset, OptionsClassProvider options) throws AbruptExitException, InterruptedException { return buildDriver.meta(ImmutableList.of(getUniverseKey(patterns, offset)), options); } @Override public SkyKey getUniverseKey(Collection patterns, String offset) { return computeUniverseKey(ImmutableList.copyOf(patterns), offset); } /** Computes the {@link SkyKey} that defines this universe. */ public static SkyKey computeUniverseKey(Collection patterns, String offset) { return PrepareDepsOfPatternsValue.key(ImmutableList.copyOf(patterns), offset); } /** Returns the generating action of a given artifact ({@code null} if it's a source artifact). */ private ActionAnalysisMetadata getGeneratingAction( ExtendedEventHandler eventHandler, Artifact artifact) throws InterruptedException { if (artifact.isSourceArtifact()) { return null; } ArtifactOwner artifactOwner = artifact.getArtifactOwner(); Preconditions.checkState(artifactOwner instanceof ActionLookupValue.ActionLookupKey, "%s %s", artifact, artifactOwner); SkyKey actionLookupKey = (ActionLookupValue.ActionLookupKey) artifactOwner; synchronized (valueLookupLock) { // Note that this will crash (attempting to run a configured target value builder after // analysis) after a failed --nokeep_going analysis in which the configured target that // failed was a (transitive) dependency of the configured target that should generate // this action. We don't expect callers to query generating actions in such cases. EvaluationResult result = buildDriver.evaluate( ImmutableList.of(actionLookupKey), false, ResourceUsage.getAvailableProcessors(), eventHandler); return result.hasError() ? null : result.get(actionLookupKey).getGeneratingActionDangerousReadJavadoc(artifact); } } /** * Returns an action graph. * *

For legacy compatibility only. */ public ActionGraph getActionGraph(final ExtendedEventHandler eventHandler) { return new ActionGraph() { @Override public ActionAnalysisMetadata getGeneratingAction(final Artifact artifact) { try { return callUninterruptibly(new Callable() { @Override public ActionAnalysisMetadata call() throws InterruptedException { return SkyframeExecutor.this.getGeneratingAction(eventHandler, artifact); } }); } catch (Exception e) { throw new IllegalStateException("Error getting generating action: " + artifact.prettyPrint(), e); } } }; } public PackageManager getPackageManager() { return packageManager; } @VisibleForTesting public TargetPatternEvaluator newTargetPatternEvaluator() { return new SkyframeTargetPatternEvaluator(this); } public ActionKeyContext getActionKeyContext() { return actionKeyContext; } class SkyframePackageLoader { /** * Looks up a particular package (mostly used after the loading phase, so packages should * already be present, but occasionally used pre-loading phase). Use should be discouraged, * since this cannot be used inside a Skyframe evaluation, and concurrent calls are * synchronized. * *

Note that this method needs to be synchronized since InMemoryMemoizingEvaluator.evaluate() * method does not support concurrent calls. */ Package getPackage(ExtendedEventHandler eventHandler, PackageIdentifier pkgName) throws InterruptedException, NoSuchPackageException { synchronized (valueLookupLock) { SkyKey key = PackageValue.key(pkgName); // Any call to this method post-loading phase should either be error-free or be in a // keep_going build, since otherwise the build would have failed during loading. Thus // we set keepGoing=true unconditionally. EvaluationResult result = buildDriver.evaluate(ImmutableList.of(key), /*keepGoing=*/true, DEFAULT_THREAD_COUNT, eventHandler); ErrorInfo error = result.getError(key); if (error != null) { if (!Iterables.isEmpty(error.getCycleInfo())) { reportCycles(eventHandler, result.getError().getCycleInfo(), key); // This can only happen if a package is freshly loaded outside of the target parsing // or loading phase throw new BuildFileContainsErrorsException( pkgName, "Cycle encountered while loading package " + pkgName); } Throwable e = error.getException(); // PackageFunction should be catching, swallowing, and rethrowing all transitive // errors as NoSuchPackageExceptions or constructing packages with errors, since we're in // keep_going mode. Throwables.propagateIfInstanceOf(e, NoSuchPackageException.class); throw new IllegalStateException("Unexpected Exception type from PackageValue for '" + pkgName + "'' with root causes: " + Iterables.toString(error.getRootCauses()), e); } return result.get(key).getPackage(); } } /** * Returns whether the given package should be consider deleted and thus should be ignored. */ public boolean isPackageDeleted(PackageIdentifier packageName) { Preconditions.checkState(!packageName.getRepository().isDefault(), "package must be absolute: %s", packageName); return deletedPackages.get().contains(packageName); } } @VisibleForTesting public MemoizingEvaluator getEvaluatorForTesting() { return memoizingEvaluator; } @VisibleForTesting public FileSystem getFileSystemForTesting() { return fileSystem; } @VisibleForTesting public RuleClassProvider getRuleClassProviderForTesting() { return ruleClassProvider; } @VisibleForTesting public PackageFactory getPackageFactoryForTesting() { return pkgFactory; } @VisibleForTesting public Package.Builder.Helper getPackageBuilderHelperForTesting() { return pkgFactory.getPackageBuilderHelperForTesting(); } @VisibleForTesting public BlazeDirectories getBlazeDirectoriesForTesting() { return directories; } /** * Initializes and syncs the graph with the given options, readying it for the next evaluation. */ public void sync( ExtendedEventHandler eventHandler, PackageCacheOptions packageCacheOptions, SkylarkSemanticsOptions skylarkSemanticsOptions, Path outputBase, Path workingDirectory, String defaultsPackageContents, UUID commandId, Map clientEnv, TimestampGranularityMonitor tsgm, OptionsClassProvider options) throws InterruptedException, AbruptExitException { getActionEnvFromOptions(options); syncPackageLoading( eventHandler, packageCacheOptions, skylarkSemanticsOptions, outputBase, workingDirectory, defaultsPackageContents, commandId, clientEnv, tsgm); } private void syncPackageLoading( ExtendedEventHandler eventHandler, PackageCacheOptions packageCacheOptions, SkylarkSemanticsOptions skylarkSemanticsOptions, Path outputBase, Path workingDirectory, String defaultsPackageContents, UUID commandId, Map clientEnv, TimestampGranularityMonitor tsgm) throws AbruptExitException { preparePackageLoading( createPackageLocator( eventHandler, packageCacheOptions.packagePath, outputBase, directories.getWorkspace(), workingDirectory), packageCacheOptions, skylarkSemanticsOptions, defaultsPackageContents, commandId, clientEnv, tsgm); setDeletedPackages(packageCacheOptions.getDeletedPackages()); incrementalBuildMonitor = new SkyframeIncrementalBuildMonitor(); invalidateTransientErrors(); } private void getActionEnvFromOptions(OptionsClassProvider options) { // ImmutableMap does not support null values, so use a LinkedHashMap instead. LinkedHashMap actionEnvironment = new LinkedHashMap<>(); BuildConfiguration.Options opt = options.getOptions(BuildConfiguration.Options.class); if (opt != null) { for (Map.Entry v : opt.actionEnvironment) { actionEnvironment.put(v.getKey(), v.getValue()); } } setActionEnv(actionEnvironment); } @VisibleForTesting public void setActionEnv(Map actionEnv) { PrecomputedValue.ACTION_ENV.set(injectable(), actionEnv); } protected PathPackageLocator createPackageLocator( ExtendedEventHandler eventHandler, List packagePaths, Path outputBase, Path workspace, Path workingDirectory) throws AbruptExitException { return PathPackageLocator.create( outputBase, packagePaths, eventHandler, workspace, workingDirectory, buildFilesByPriority); } private CyclesReporter createCyclesReporter() { return new CyclesReporter( new TransitiveTargetCycleReporter(packageManager), new ActionArtifactCycleReporter(packageManager), // TODO(ulfjack): The SkylarkModuleCycleReporter swallows previously reported cycles // unconditionally! Is that intentional? new ConfiguredTargetCycleReporter(packageManager), new SkylarkModuleCycleReporter()); } CyclesReporter getCyclesReporter() { return cyclesReporter.get(); } /** Convenience method with same semantics as {@link CyclesReporter#reportCycles}. */ public void reportCycles( ExtendedEventHandler eventHandler, Iterable cycles, SkyKey topLevelKey) { getCyclesReporter().reportCycles(cycles, topLevelKey, eventHandler); } public void setActionExecutionProgressReportingObjects(@Nullable ProgressSupplier supplier, @Nullable ActionCompletedReceiver completionReceiver, @Nullable ActionExecutionStatusReporter statusReporter) { skyframeActionExecutor.setActionExecutionProgressReportingObjects(supplier, completionReceiver); this.statusReporterRef.set(statusReporter); } public abstract void detectModifiedOutputFiles( ModifiedFileSet modifiedOutputFiles, @Nullable Range lastExecutionTimeRange) throws AbruptExitException, InterruptedException; /** * Mark dirty values for deletion if they've been dirty for longer than N versions. * *

Specifying a value N means, if the current version is V and a value was dirtied (and * has remained so) in version U, and U + N <= V, then the value will be marked for deletion * and purged in version V+1. */ public abstract void deleteOldNodes(long versionWindowForDirtyGc); public TargetPatternPhaseValue loadTargetPatterns( ExtendedEventHandler eventHandler, List targetPatterns, PathFragment relativeWorkingDirectory, LoadingOptions options, int threadCount, boolean keepGoing, boolean determineTests) throws TargetParsingException, InterruptedException { Stopwatch timer = Stopwatch.createStarted(); SkyKey key = TargetPatternPhaseValue.key( ImmutableList.copyOf(targetPatterns), relativeWorkingDirectory.getPathString(), options.compileOneDependency, options.buildTestsOnly, determineTests, ImmutableList.copyOf(options.buildTagFilterList), options.buildManualTests, options.expandTestSuites, TestFilter.forOptions(options, eventHandler, pkgFactory.getRuleClassNames())); EvaluationResult evalResult; eventHandler.post(new LoadingPhaseStartedEvent(packageProgress)); evalResult = buildDriver.evaluate( ImmutableList.of(key), keepGoing, threadCount, eventHandler); if (evalResult.hasError()) { ErrorInfo errorInfo = evalResult.getError(key); TargetParsingException exc; if (!Iterables.isEmpty(errorInfo.getCycleInfo())) { exc = new TargetParsingException("cycles detected during target parsing"); getCyclesReporter().reportCycles(errorInfo.getCycleInfo(), key, eventHandler); // Fallback: we don't know which patterns failed, specifically, so we report the entire // set as being in error. eventHandler.post(PatternExpandingError.failed(targetPatterns, exc.getMessage())); } else { // TargetPatternPhaseFunction never directly throws. Thus, the only way // evalResult.hasError() && keepGoing can hold is if there are cycles, which is handled // above. Preconditions.checkState(!keepGoing); // Following SkyframeTargetPatternEvaluator, we convert any exception into a // TargetParsingException. Exception e = Preconditions.checkNotNull(errorInfo.getException()); exc = (e instanceof TargetParsingException) ? (TargetParsingException) e : new TargetParsingException(e.getMessage(), e); if (!(e instanceof TargetParsingException)) { // If it's a TargetParsingException, then the TargetPatternPhaseFunction has already // reported the error, so we don't need to report it again. eventHandler.post(PatternExpandingError.failed(targetPatterns, exc.getMessage())); } } throw exc; } long timeMillis = timer.stop().elapsed(TimeUnit.MILLISECONDS); eventHandler.post(new TargetParsingPhaseTimeEvent(timeMillis)); TargetPatternPhaseValue patternParsingValue = evalResult.get(key); return patternParsingValue; } public PrepareAnalysisPhaseValue prepareAnalysisPhase( ExtendedEventHandler eventHandler, BuildOptions buildOptions, Set multiCpu, Collection