/** * If the action might read directories as inputs in a way that is unsound wrt dependency * checking, this method must be called. */ protected void checkInputsForDirectories( EventHandler eventHandler, MetadataHandler metadataHandler) { // Report "directory dependency checking" warning only for non-generated directories (generated // ones will be reported earlier). for (Artifact input : getMandatoryInputs()) { // Assume that if the file did not exist, we would not have gotten here. if (input.isSourceArtifact() && !metadataHandler.isRegularFile(input)) { eventHandler.handle( Event.warn( getOwner().getLocation(), "input '" + input.prettyPrint() + "' to " + getOwner().getLabel() + " is a directory; dependency checking of directories is unsound")); } } }
private static void deserializeEvent(StoredEventHandler eventHandler, Build.Event event) { String message = event.getMessage(); switch (event.getKind()) { case ERROR: eventHandler.handle(Event.error(message)); break; case WARNING: eventHandler.handle(Event.warn(message)); break; case INFO: eventHandler.handle(Event.info(message)); break; case PROGRESS: eventHandler.handle(Event.progress(message)); break; default: break; // Ignore } }
@Override public void buildTransitiveClosure(QueryExpression caller, Set<Target> targets, int maxDepth) throws QueryException { // Everything has already been loaded, so here we just check for errors so that we can // pre-emptively throw/report if needed. Iterable<SkyKey> transitiveTraversalKeys = makeTransitiveTraversalKeys(targets); ImmutableList.Builder<String> errorMessagesBuilder = ImmutableList.builder(); // First, look for errors in the successfully evaluated TransitiveTraversalValues. They may // have encountered errors that they were able to recover from. Set<Entry<SkyKey, SkyValue>> successfulEntries = graph.getSuccessfulValues(transitiveTraversalKeys).entrySet(); Builder<SkyKey> successfulKeysBuilder = ImmutableSet.builder(); for (Entry<SkyKey, SkyValue> successfulEntry : successfulEntries) { successfulKeysBuilder.add(successfulEntry.getKey()); TransitiveTraversalValue value = (TransitiveTraversalValue) successfulEntry.getValue(); String firstErrorMessage = value.getFirstErrorMessage(); if (firstErrorMessage != null) { errorMessagesBuilder.add(firstErrorMessage); } } ImmutableSet<SkyKey> successfulKeys = successfulKeysBuilder.build(); // Next, look for errors from the unsuccessfully evaluated TransitiveTraversal skyfunctions. Iterable<SkyKey> unsuccessfulKeys = Iterables.filter(transitiveTraversalKeys, Predicates.not(Predicates.in(successfulKeys))); Set<Entry<SkyKey, Exception>> errorEntries = graph.getMissingAndExceptions(unsuccessfulKeys).entrySet(); for (Map.Entry<SkyKey, Exception> entry : errorEntries) { if (entry.getValue() == null) { // Targets may be in the graph because they are not in the universe or depend on cycles. eventHandler.handle(Event.warn(entry.getKey().argument() + " does not exist in graph")); } else { errorMessagesBuilder.add(entry.getValue().getMessage()); } } // Lastly, report all found errors. ImmutableList<String> errorMessages = errorMessagesBuilder.build(); for (String errorMessage : errorMessages) { reportBuildFileError(caller, errorMessage); } }
private static String readSecret(String secretFile, Reporter reporter) throws SenderException { if (secretFile.isEmpty()) { return ""; } Path secretPath = new File(secretFile).toPath(); if (!Files.isReadable(secretPath)) { throw new SenderException("Secret file " + secretFile + " doesn't exists or is unreadable"); } try { if (Files.getPosixFilePermissions(secretPath).contains(PosixFilePermission.OTHERS_READ) || Files.getPosixFilePermissions(secretPath).contains(PosixFilePermission.GROUP_READ)) { reporter.handle( Event.warn( "Secret file " + secretFile + " is readable by non-owner. " + "It is recommended to set its permission to 0600 (read-write only by the owner).")); } return new String(Files.readAllBytes(secretPath), StandardCharsets.UTF_8).trim(); } catch (IOException e) { throw new SenderException("Invalid secret file " + secretFile, e); } }
@Override public void editOptions(CommandEnvironment env, OptionsParser optionsParser) throws AbruptExitException { ProjectFileSupport.handleProjectFiles(env, optionsParser, commandName()); TestOutputFormat testOutput = optionsParser.getOptions(ExecutionOptions.class).testOutput; try { if (testOutput == TestStrategy.TestOutputFormat.STREAMED) { env.getReporter() .handle( Event.warn( "Streamed test output requested so all tests will be run locally, without sharding, " + "one at a time")); optionsParser.parse( OptionPriority.SOFTWARE_REQUIREMENT, "streamed output requires locally run tests, without sharding", ImmutableList.of("--test_sharding_strategy=disabled", "--test_strategy=exclusive")); } } catch (OptionsParsingException e) { throw new IllegalStateException("Known options failed to parse", e); } }
public Sender( String url, String secret, CommandEnvironment env, ExecutorService executorService) throws SenderException { this.reporter = env.getReporter(); this.secret = readSecret(secret, reporter); try { this.url = new URL(url); if (!this.secret.isEmpty()) { if (!(this.url.getProtocol().equals("https") || this.url.getHost().equals("localhost") || this.url.getHost().matches("^127.0.0.[0-9]+$"))) { reporter.handle( Event.warn( "Using authentication over unsecure channel, " + "consider using HTTPS.")); } } } catch (MalformedURLException e) { throw new SenderException("Invalid server url " + url, e); } this.buildId = env.getCommandId().toString(); this.executorService = executorService; sendMessage("test", null); // test connecting to the server. reporter.handle(Event.info("Results are being streamed to " + url + "/result/" + buildId)); }
/** * 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())); }
@Override @ThreadCompatible public void execute(ActionExecutionContext actionExecutionContext) throws ActionExecutionException, InterruptedException { Executor executor = actionExecutionContext.getExecutor(); // First, do a normal compilation, to generate the ".d" file. The generated object file is built // to a temporary location (tempOutputFile) and ignored afterwards. LOG.info("Generating " + getDotdFile()); CppCompileActionContext context = executor.getContext(actionContext); CppCompileActionContext.Reply reply = null; try { // We delegate stdout/stderr to nowhere, i.e. same as redirecting to /dev/null. reply = context.execWithReply(this, actionExecutionContext.withFileOutErr(new FileOutErr())); } catch (ExecException e) { // We ignore failures here (other than capturing the Distributor reply). // The compilation may well fail (that's the whole point of negative compilation tests). // We execute it here just for the side effect of generating the ".d" file. reply = context.getReplyFromException(e, this); if (reply == null) { // This can only happen if the ExecException does not come from remote execution. throw e.toActionExecutionException( "Fake C++ Compilation of rule '" + getOwner().getLabel() + "'", executor.getVerboseFailures(), this); } } IncludeScanningContext scanningContext = executor.getContext(IncludeScanningContext.class); NestedSet<Artifact> discoveredInputs = discoverInputsFromDotdFiles( executor.getExecRoot(), scanningContext.getArtifactResolver(), reply); reply = null; // Clear in-memory .d files early. // Even cc_fake_binary rules need to properly declare their dependencies... // In fact, they need to declare their dependencies even more than cc_binary rules do. // CcCommonConfiguredTarget passes in an empty set of declaredIncludeDirs, // so this check below will only allow inclusion of header files that are explicitly // listed in the "srcs" of the cc_fake_binary or in the "srcs" of a cc_library that it // depends on. try { validateInclusions( discoveredInputs, actionExecutionContext.getArtifactExpander(), executor.getEventHandler()); } catch (ActionExecutionException e) { // TODO(bazel-team): (2009) make this into an error, once most of the current warnings // are fixed. executor .getEventHandler() .handle( Event.warn( getOwner().getLocation(), e.getMessage() + ";\n this warning may eventually become an error")); } updateActionInputs(discoveredInputs); // Generate a fake ".o" file containing the command line needed to generate // the real object file. LOG.info("Generating " + outputFile); // A cc_fake_binary rule generates fake .o files and a fake target file, // which merely contain instructions on building the real target. We need to // be careful to use a new set of output file names in the instructions, as // to not overwrite the fake output files when someone tries to follow the // instructions. As the real compilation is executed by the test from its // runfiles directory (where writing is forbidden), we patch the command // line to write to $TEST_TMPDIR instead. final String outputPrefix = "$TEST_TMPDIR/"; String argv = Joiner.on(' ') .join( Iterables.transform( getArgv(outputFile.getExecPath()), new Function<String, String>() { @Override public String apply(String input) { String result = ShellEscaper.escapeString(input); // Once -c and -o options are added into action_config, the argument of // getArgv(outputFile.getExecPath()) won't be used anymore. There will // always be // -c <tempOutputFile>, but here it has to be outputFile, so we replace it. if (input.equals(tempOutputFile.getPathString())) { result = outputPrefix + ShellEscaper.escapeString(outputFile.getExecPathString()); } if (input.equals(outputFile.getExecPathString()) || input.equals(getDotdFile().getSafeExecPath().getPathString())) { result = outputPrefix + ShellEscaper.escapeString(input); } return result; } })); // Write the command needed to build the real .o file to the fake .o file. // Generate a command to ensure that the output directory exists; otherwise // the compilation would fail. try { // Ensure that the .d file and .o file are siblings, so that the "mkdir" below works for // both. Preconditions.checkState( outputFile .getExecPath() .getParentDirectory() .equals(getDotdFile().getSafeExecPath().getParentDirectory())); FileSystemUtils.writeContent( outputFile.getPath(), ISO_8859_1, outputFile.getPath().getBaseName() + ": " + "mkdir -p " + outputPrefix + "$(dirname " + outputFile.getExecPath() + ")" + " && " + argv + "\n"); } catch (IOException e) { throw new ActionExecutionException( "failed to create fake compile command for rule '" + getOwner().getLabel() + ": " + e.getMessage(), this, false); } }
/** * Validates the options for this BuildRequest. * * <p>Issues warnings for the use of deprecated options, and warnings or errors for any option * settings that conflict. */ @VisibleForTesting public void validateOptions(BuildRequest request) throws InvalidConfigurationException { for (String issue : request.validateOptions()) { getReporter().handle(Event.warn(issue)); } }
/** * The crux of the build system. Builds the targets specified in the request using the specified * Executor. * * <p>Performs loading, analysis and execution for the specified set of targets, honoring the * configuration options in the BuildRequest. Returns normally iff successful, throws an exception * otherwise. * * <p>Callers must ensure that {@link #stopRequest} is called after this method, even if it * throws. * * <p>The caller is responsible for setting up and syncing the package cache. * * <p>During this function's execution, the actualTargets and successfulTargets fields of the * request object are set. * * @param request the build request that this build tool is servicing, which specifies various * options; during this method's execution, the actualTargets and successfulTargets fields of * the request object are populated * @param result the build result that is the mutable result of this build * @param validator target validator */ public void buildTargets(BuildRequest request, BuildResult result, TargetValidator validator) throws BuildFailedException, LocalEnvironmentException, InterruptedException, ViewCreationFailedException, TargetParsingException, LoadingFailedException, ExecutorInitException, AbruptExitException, InvalidConfigurationException, TestExecException { validateOptions(request); BuildOptions buildOptions = runtime.createBuildOptions(request); // Sync the package manager before sending the BuildStartingEvent in runLoadingPhase() runtime.setupPackageCache( request.getPackageCacheOptions(), DefaultsPackage.getDefaultsPackageContent(buildOptions)); ExecutionTool executionTool = null; LoadingResult loadingResult = null; BuildConfigurationCollection configurations = null; try { getEventBus().post(new BuildStartingEvent(runtime.getOutputFileSystem(), request)); LOG.info("Build identifier: " + request.getId()); executionTool = new ExecutionTool(runtime, request); if (needsExecutionPhase(request.getBuildOptions())) { // Initialize the execution tool early if we need it. This hides the latency of setting up // the execution backends. executionTool.init(); } // Loading phase. loadingResult = runLoadingPhase(request, validator); // Create the build configurations. if (!request.getMultiCpus().isEmpty()) { getReporter() .handle( Event.warn( "The --experimental_multi_cpu option is _very_ experimental and only intended for " + "internal testing at this time. If you do not work on the build tool, then you " + "should stop now!")); if (!"build".equals(request.getCommandName()) && !"test".equals(request.getCommandName())) { throw new InvalidConfigurationException( "The experimental setting to select multiple CPUs is only supported for 'build' and " + "'test' right now!"); } } configurations = getConfigurations( buildOptions, request.getMultiCpus(), request.getViewOptions().keepGoing); getEventBus().post(new ConfigurationsCreatedEvent(configurations)); runtime.throwPendingException(); if (configurations.getTargetConfigurations().size() == 1) { // TODO(bazel-team): This is not optimal - we retain backwards compatibility in the case // where there's only a single configuration, but we don't send an event in the multi-config // case. Can we do better? [multi-config] getEventBus() .post( new MakeEnvironmentEvent( configurations.getTargetConfigurations().get(0).getMakeEnvironment())); } LOG.info("Configurations created"); // Analysis phase. AnalysisResult analysisResult = runAnalysisPhase(request, loadingResult, configurations); result.setActualTargets(analysisResult.getTargetsToBuild()); result.setTestTargets(analysisResult.getTargetsToTest()); checkTargetEnvironmentRestrictions( analysisResult.getTargetsToBuild(), runtime.getPackageManager()); reportTargets(analysisResult); // Execution phase. if (needsExecutionPhase(request.getBuildOptions())) { runtime.getSkyframeExecutor().injectTopLevelContext(request.getTopLevelArtifactContext()); executionTool.executeBuild( request.getId(), analysisResult, result, runtime.getSkyframeExecutor(), configurations, transformPackageRoots(loadingResult.getPackageRoots())); } String delayedErrorMsg = analysisResult.getError(); if (delayedErrorMsg != null) { throw new BuildFailedException(delayedErrorMsg); } } catch (RuntimeException e) { // Print an error message for unchecked runtime exceptions. This does not concern Error // subclasses such as OutOfMemoryError. request .getOutErr() .printErrLn("Unhandled exception thrown during build; message: " + e.getMessage()); throw e; } finally { // Delete dirty nodes to ensure that they do not accumulate indefinitely. long versionWindow = request.getViewOptions().versionWindowForDirtyNodeGc; if (versionWindow != -1) { runtime.getSkyframeExecutor().deleteOldNodes(versionWindow); } if (executionTool != null) { executionTool.shutdown(); } // The workspace status actions will not run with certain flags, or if an error // occurs early in the build. Tell a lie so that the event is not missing. // If multiple build_info events are sent, only the first is kept, so this does not harm // successful runs (which use the workspace status action). getEventBus() .post( new BuildInfoEvent( runtime.getworkspaceStatusActionFactory().createDummyWorkspaceStatus())); } if (loadingResult != null && loadingResult.hasTargetPatternError()) { throw new BuildFailedException( "execution phase successful, but there were errors " + "parsing the target pattern"); } }
@Override public void warn(String msg) { env.getListener().handle(Event.warn(msg)); }
/** * 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( List<ConfiguredTargetKey> values, List<AspectKey> aspectKeys, EventBus eventBus, boolean keepGoing) throws InterruptedException, ViewCreationFailedException { enableAnalysis(true); EvaluationResult<ActionLookupValue> result; try { result = skyframeExecutor.configureTargets(values, aspectKeys, keepGoing); } finally { enableAnalysis(false); } ImmutableMap<Action, ConflictException> badActions = skyframeExecutor.findArtifactConflicts(); Collection<AspectValue> goodAspects = Lists.newArrayListWithCapacity(values.size()); for (AspectKey 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); } // 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()); } if (!result.hasError() && badActions.isEmpty()) { setDeserializedArtifactOwners(); return new SkyframeAnalysisResult( ImmutableList.copyOf(goodCts), result.getWalkableGraph(), ImmutableList.copyOf(goodAspects)); } // --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(skyframeExecutor.getReporter()); String errorMsg = "Analysis of target '" + bad.getKey().getOwner().getLabel() + "' failed; build aborted"; throw new ViewCreationFailedException(errorMsg); } catch (ArtifactPrefixConflictException apce) { skyframeExecutor.getReporter().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, skyframeExecutor.getReporter()); Throwable cause = errorInfo.getException(); Preconditions.checkState( cause != null || !Iterables.isEmpty(errorInfo.getCycleInfo()), errorInfo); String errorMsg = "Analysis of target '" + ConfiguredTargetValue.extractLabel(topLevel) + "' failed; build aborted"; if (cause instanceof ActionConflictException) { ((ActionConflictException) cause).reportTo(skyframeExecutor.getReporter()); } throw new ViewCreationFailedException(errorMsg); } // --keep_going : We notify the error and return a ConfiguredTargetValue for (Map.Entry<SkyKey, ErrorInfo> errorEntry : result.errorMap().entrySet()) { if (values.contains(errorEntry.getKey().argument())) { SkyKey errorKey = errorEntry.getKey(); ConfiguredTargetKey label = (ConfiguredTargetKey) errorKey.argument(); ErrorInfo errorInfo = errorEntry.getValue(); assertSaneAnalysisError(errorInfo, errorKey); skyframeExecutor .getCyclesReporter() .reportCycles(errorInfo.getCycleInfo(), errorKey, skyframeExecutor.getReporter()); // We try to get the root cause key first from ErrorInfo rootCauses. If we don't have one // we try to use the cycle culprit if the error is a cycle. Otherwise we use the top-level // error key. Label root; if (!Iterables.isEmpty(errorEntry.getValue().getRootCauses())) { SkyKey culprit = Preconditions.checkNotNull( Iterables.getFirst(errorEntry.getValue().getRootCauses(), null)); root = ((ConfiguredTargetKey) culprit.argument()).getLabel(); } else { root = maybeGetConfiguredTargetCycleCulprit(errorInfo.getCycleInfo()); } Exception cause = errorInfo.getException(); if (cause instanceof ActionConflictException) { ((ActionConflictException) cause).reportTo(skyframeExecutor.getReporter()); } skyframeExecutor .getReporter() .handle( Event.warn( "errors encountered while analyzing target '" + label.getLabel() + "': it will not be built")); eventBus.post( new AnalysisFailureEvent( LabelAndConfiguration.of(label.getLabel(), label.getConfiguration()), root)); } } 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(skyframeExecutor.getReporter()); skyframeExecutor .getReporter() .handle( Event.warn( "errors encountered while analyzing target '" + bad.getKey().getOwner().getLabel() + "': it will not be built")); } catch (ArtifactPrefixConflictException apce) { if (reportedExceptions.add(apce)) { skyframeExecutor.getReporter().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(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( ImmutableList.copyOf(goodCts), result.getWalkableGraph(), ImmutableList.copyOf(goodAspects)); }
// Ignore all errors in traversal and return an empty value. private TReturn reportErrorAndReturn( String errorPrefix, Exception e, PathFragment rootRelativePath, EventHandler handler) { handler.handle( Event.warn(errorPrefix + ", for " + rootRelativePath + ", skipping: " + e.getMessage())); return getEmptyReturn(); }
/** Targets may not be in the graph because they are not in the universe or depend on cycles. */ private void warnIfMissingTargets(Iterable<Target> targets, Set<Target> result) { if (Iterables.size(targets) != result.size()) { Set<Target> missingTargets = Sets.difference(ImmutableSet.copyOf(targets), result); eventHandler.handle(Event.warn("Targets were missing from graph: " + missingTargets)); } }