Esempio n. 1
0
 /**
  * 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"));
     }
   }
 }
Esempio n. 2
0
 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
   }
 }
Esempio n. 3
0
  @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);
    }
  }
Esempio n. 4
0
 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);
   }
 }
Esempio n. 5
0
  @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);
    }
  }
Esempio n. 6
0
 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));
 }
Esempio n. 7
0
  /**
   * 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()));
  }
Esempio n. 8
0
  @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);
    }
  }
Esempio n. 9
0
 /**
  * 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));
   }
 }
Esempio n. 10
0
  /**
   * 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));
 }
Esempio n. 12
0
  /**
   * 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();
 }
Esempio n. 14
0
 /** 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));
   }
 }