/** * Analyzes the specified targets using Skyframe as the driving framework. * * @return the configured targets that should be built along with a WalkableGraph of the analysis. */ public SkyframeAnalysisResult configureTargets( EventHandler eventHandler, List<ConfiguredTargetKey> values, List<AspectValueKey> aspectKeys, EventBus eventBus, boolean keepGoing) throws InterruptedException, ViewCreationFailedException { enableAnalysis(true); EvaluationResult<ActionLookupValue> result; try { result = skyframeExecutor.configureTargets(eventHandler, values, aspectKeys, keepGoing); } finally { enableAnalysis(false); } ImmutableMap<Action, ConflictException> badActions = skyframeExecutor.findArtifactConflicts(); Collection<AspectValue> goodAspects = Lists.newArrayListWithCapacity(values.size()); NestedSetBuilder<Package> packages = NestedSetBuilder.stableOrder(); for (AspectValueKey aspectKey : aspectKeys) { AspectValue value = (AspectValue) result.get(AspectValue.key(aspectKey)); if (value == null) { // Skip aspects that couldn't be applied to targets. continue; } goodAspects.add(value); packages.addTransitive(value.getTransitivePackages()); } // Filter out all CTs that have a bad action and convert to a list of configured targets. This // code ensures that the resulting list of configured targets has the same order as the incoming // list of values, i.e., that the order is deterministic. Collection<ConfiguredTarget> goodCts = Lists.newArrayListWithCapacity(values.size()); for (ConfiguredTargetKey value : values) { ConfiguredTargetValue ctValue = (ConfiguredTargetValue) result.get(ConfiguredTargetValue.key(value)); if (ctValue == null) { continue; } goodCts.add(ctValue.getConfiguredTarget()); packages.addTransitive(ctValue.getTransitivePackages()); } if (!result.hasError() && badActions.isEmpty()) { setDeserializedArtifactOwners(); return new SkyframeAnalysisResult( /*hasLoadingError=*/ false, /*hasAnalysisError=*/ false, ImmutableList.copyOf(goodCts), result.getWalkableGraph(), ImmutableList.copyOf(goodAspects), LoadingPhaseRunner.collectPackageRoots(packages.build().toCollection())); } // --nokeep_going so we fail with an exception for the first error. // TODO(bazel-team): We might want to report the other errors through the event bus but // for keeping this code in parity with legacy we just report the first error for now. if (!keepGoing) { for (Map.Entry<Action, ConflictException> bad : badActions.entrySet()) { ConflictException ex = bad.getValue(); try { ex.rethrowTyped(); } catch (MutableActionGraph.ActionConflictException ace) { ace.reportTo(eventHandler); String errorMsg = "Analysis of target '" + bad.getKey().getOwner().getLabel() + "' failed; build aborted"; throw new ViewCreationFailedException(errorMsg); } catch (ArtifactPrefixConflictException apce) { eventHandler.handle(Event.error(apce.getMessage())); } throw new ViewCreationFailedException(ex.getMessage()); } Map.Entry<SkyKey, ErrorInfo> error = result.errorMap().entrySet().iterator().next(); SkyKey topLevel = error.getKey(); ErrorInfo errorInfo = error.getValue(); assertSaneAnalysisError(errorInfo, topLevel); skyframeExecutor .getCyclesReporter() .reportCycles(errorInfo.getCycleInfo(), topLevel, eventHandler); Throwable cause = errorInfo.getException(); Preconditions.checkState( cause != null || !Iterables.isEmpty(errorInfo.getCycleInfo()), errorInfo); String errorMsg = null; if (topLevel.argument() instanceof ConfiguredTargetKey) { errorMsg = "Analysis of target '" + ConfiguredTargetValue.extractLabel(topLevel) + "' failed; build aborted"; } else if (topLevel.argument() instanceof AspectValueKey) { AspectValueKey aspectKey = (AspectValueKey) topLevel.argument(); errorMsg = "Analysis of aspect '" + aspectKey.getDescription() + "' failed; build aborted"; } else { assert false; } if (cause instanceof ActionConflictException) { ((ActionConflictException) cause).reportTo(eventHandler); } throw new ViewCreationFailedException(errorMsg); } boolean hasLoadingError = false; // --keep_going : We notify the error and return a ConfiguredTargetValue for (Map.Entry<SkyKey, ErrorInfo> errorEntry : result.errorMap().entrySet()) { // Only handle errors of configured targets, not errors of top-level aspects. // TODO(ulfjack): this is quadratic - if there are a lot of CTs, this could be rather slow. if (!values.contains(errorEntry.getKey().argument())) { continue; } SkyKey errorKey = errorEntry.getKey(); ConfiguredTargetKey label = (ConfiguredTargetKey) errorKey.argument(); Label topLevelLabel = label.getLabel(); ErrorInfo errorInfo = errorEntry.getValue(); assertSaneAnalysisError(errorInfo, errorKey); skyframeExecutor .getCyclesReporter() .reportCycles(errorInfo.getCycleInfo(), errorKey, eventHandler); Exception cause = errorInfo.getException(); Label analysisRootCause = null; if (cause instanceof ConfiguredValueCreationException) { ConfiguredValueCreationException ctCause = (ConfiguredValueCreationException) cause; for (Label rootCause : ctCause.getRootCauses()) { hasLoadingError = true; eventBus.post(new LoadingFailureEvent(topLevelLabel, rootCause)); } analysisRootCause = ctCause.getAnalysisRootCause(); } else if (!Iterables.isEmpty(errorInfo.getCycleInfo())) { analysisRootCause = maybeGetConfiguredTargetCycleCulprit(topLevelLabel, errorInfo.getCycleInfo()); } else if (cause instanceof ActionConflictException) { ((ActionConflictException) cause).reportTo(eventHandler); } eventHandler.handle( Event.warn( "errors encountered while analyzing target '" + topLevelLabel + "': it will not be built")); if (analysisRootCause != null) { eventBus.post( new AnalysisFailureEvent( LabelAndConfiguration.of(topLevelLabel, label.getConfiguration()), analysisRootCause)); } } Collection<Exception> reportedExceptions = Sets.newHashSet(); for (Map.Entry<Action, ConflictException> bad : badActions.entrySet()) { ConflictException ex = bad.getValue(); try { ex.rethrowTyped(); } catch (MutableActionGraph.ActionConflictException ace) { ace.reportTo(eventHandler); eventHandler.handle( Event.warn( "errors encountered while analyzing target '" + bad.getKey().getOwner().getLabel() + "': it will not be built")); } catch (ArtifactPrefixConflictException apce) { if (reportedExceptions.add(apce)) { eventHandler.handle(Event.error(apce.getMessage())); } } } if (!badActions.isEmpty()) { // In order to determine the set of configured targets transitively error free from action // conflict issues, we run a post-processing update() that uses the bad action map. EvaluationResult<PostConfiguredTargetValue> actionConflictResult = skyframeExecutor.postConfigureTargets(eventHandler, values, keepGoing, badActions); goodCts = Lists.newArrayListWithCapacity(values.size()); for (ConfiguredTargetKey value : values) { PostConfiguredTargetValue postCt = actionConflictResult.get(PostConfiguredTargetValue.key(value)); if (postCt != null) { goodCts.add(postCt.getCt()); } } } setDeserializedArtifactOwners(); return new SkyframeAnalysisResult( hasLoadingError, result.hasError() || !badActions.isEmpty(), ImmutableList.copyOf(goodCts), result.getWalkableGraph(), ImmutableList.copyOf(goodAspects), LoadingPhaseRunner.collectPackageRoots(packages.build().toCollection())); }
@Nullable @Override public SkyValue compute(SkyKey skyKey, Environment env) throws AspectFunctionException, InterruptedException { SkyframeBuildView view = buildViewProvider.getSkyframeBuildView(); NestedSetBuilder<Package> transitivePackages = NestedSetBuilder.stableOrder(); NestedSetBuilder<Label> transitiveRootCauses = NestedSetBuilder.stableOrder(); AspectKey key = (AspectKey) skyKey.argument(); ConfiguredAspectFactory aspectFactory; if (key.getAspectClass() instanceof NativeAspectClass<?>) { aspectFactory = (ConfiguredAspectFactory) ((NativeAspectClass<?>) key.getAspectClass()).newInstance(); } else if (key.getAspectClass() instanceof SkylarkAspectClass) { SkylarkAspectClass skylarkAspectClass = (SkylarkAspectClass) key.getAspectClass(); SkylarkAspect skylarkAspect; try { skylarkAspect = loadSkylarkAspect( env, skylarkAspectClass.getExtensionLabel(), skylarkAspectClass.getExportedName()); } catch (AspectCreationException e) { throw new AspectFunctionException(e); } if (skylarkAspect == null) { return null; } aspectFactory = new SkylarkAspectFactory(skylarkAspect.getName(), skylarkAspect); } else { throw new IllegalStateException(); } // Keep this in sync with the same code in ConfiguredTargetFunction. PackageValue packageValue = (PackageValue) env.getValue(PackageValue.key(key.getLabel().getPackageIdentifier())); if (packageValue == null) { return null; } Package pkg = packageValue.getPackage(); if (pkg.containsErrors()) { throw new AspectFunctionException( new BuildFileContainsErrorsException(key.getLabel().getPackageIdentifier())); } Target target; try { target = pkg.getTarget(key.getLabel().getName()); } catch (NoSuchTargetException e) { throw new AspectFunctionException(e); } if (!(target instanceof Rule)) { throw new AspectFunctionException( new AspectCreationException("aspects must be attached to rules")); } final ConfiguredTargetValue configuredTargetValue; try { configuredTargetValue = (ConfiguredTargetValue) env.getValueOrThrow( ConfiguredTargetValue.key(key.getLabel(), key.getConfiguration()), ConfiguredValueCreationException.class); } catch (ConfiguredValueCreationException e) { throw new AspectFunctionException(new AspectCreationException(e.getRootCauses())); } if (configuredTargetValue == null) { // TODO(bazel-team): remove this check when top-level targets also use dynamic configurations. // Right now the key configuration may be dynamic while the original target's configuration // is static, resulting in a Skyframe cache miss even though the original target is, in fact, // precomputed. return null; } RuleConfiguredTarget associatedTarget = (RuleConfiguredTarget) configuredTargetValue.getConfiguredTarget(); if (associatedTarget == null) { return null; } SkyframeDependencyResolver resolver = view.createDependencyResolver(env); TargetAndConfiguration ctgValue = new TargetAndConfiguration(target, key.getConfiguration()); try { // Get the configuration targets that trigger this rule's configurable attributes. Set<ConfigMatchingProvider> configConditions = ConfiguredTargetFunction.getConfigConditions( target, env, resolver, ctgValue, transitivePackages, transitiveRootCauses); if (configConditions == null) { // Those targets haven't yet been resolved. return null; } ListMultimap<Attribute, ConfiguredTarget> depValueMap = ConfiguredTargetFunction.computeDependencies( env, resolver, ctgValue, key.getAspect(), configConditions, ruleClassProvider, view.getHostConfiguration(ctgValue.getConfiguration()), transitivePackages, transitiveRootCauses); if (depValueMap == null) { return null; } if (!transitiveRootCauses.isEmpty()) { throw new AspectFunctionException( new AspectCreationException("Loading failed", transitiveRootCauses.build())); } return createAspect( env, key, aspectFactory, associatedTarget, configConditions, depValueMap, transitivePackages); } catch (DependencyEvaluationException e) { if (e.getCause() instanceof ConfiguredValueCreationException) { ConfiguredValueCreationException cause = (ConfiguredValueCreationException) e.getCause(); throw new AspectFunctionException( new AspectCreationException(cause.getMessage(), cause.getAnalysisRootCause())); } else { // Cast to InvalidConfigurationException as a consistency check. If you add any // DependencyEvaluationException constructors, you may need to change this code, too. InvalidConfigurationException cause = (InvalidConfigurationException) e.getCause(); throw new AspectFunctionException(new AspectCreationException(cause.getMessage())); } } catch (AspectCreationException e) { throw new AspectFunctionException(e); } }