예제 #1
0
  /**
   * Generates a command line to run for the test action, taking into account coverage and {@code
   * --run_under} settings.
   *
   * @param testScript the setup script that invokes the test
   * @param coverageScript a script interjected between setup script and rest of command line to
   *     collect coverage data. If this is an empty string, it is ignored.
   * @param testAction The test action.
   * @return the command line as string list.
   */
  protected List<String> getArgs(
      String testScript, String coverageScript, TestRunnerAction testAction) {
    List<String> args = Lists.newArrayList();
    if (OS.getCurrent() == OS.WINDOWS) {
      args.add(testAction.getShExecutable().getPathString());
      args.add("-c");
      args.add("$0 $*");
    }
    args.add(testScript);
    TestTargetExecutionSettings execSettings = testAction.getExecutionSettings();

    List<String> execArgs = new ArrayList<>();
    if (!coverageScript.isEmpty() && isCoverageMode(testAction)) {
      execArgs.add(coverageScript);
    }

    // Execute the test using the alias in the runfiles tree, as mandated by
    // the Test Encyclopedia.
    execArgs.add(execSettings.getExecutable().getRootRelativePath().getPathString());
    execArgs.addAll(execSettings.getArgs());

    // Insert the command prefix specified by the "--run_under=<command-prefix>" option,
    // if any.
    if (execSettings.getRunUnder() == null) {
      args.addAll(execArgs);
    } else if (execSettings.getRunUnderExecutable() != null) {
      args.add(execSettings.getRunUnderExecutable().getRootRelativePath().getPathString());
      args.addAll(execSettings.getRunUnder().getOptions());
      args.addAll(execArgs);
    } else {
      args.add(testAction.getConfiguration().getShellExecutable().getPathString());
      args.add("-c");

      String runUnderCommand = ShellEscaper.escapeString(execSettings.getRunUnder().getCommand());

      Path fullySpecified =
          SearchPath.which(
              SearchPath.parse(
                  testAction.getTestLog().getPath().getFileSystem(), clientEnv.get("PATH")),
              runUnderCommand);

      if (fullySpecified != null) {
        runUnderCommand = fullySpecified.toString();
      }

      args.add(
          runUnderCommand
              + ' '
              + ShellEscaper.escapeJoinAll(
                  Iterables.concat(execSettings.getRunUnder().getOptions(), execArgs)));
    }
    return args;
  }
예제 #2
0
  private void actuallyClean(
      CommandEnvironment env, Path outputBase, Options cleanOptions, String symlinkPrefix)
      throws IOException, ShutdownBlazeServerException, CommandException, ExecException,
          InterruptedException {
    BlazeRuntime runtime = env.getRuntime();
    if (env.getOutputService() != null) {
      env.getOutputService().clean();
    }
    if (cleanOptions.expunge) {
      LOG.info("Expunging...");
      // Delete the big subdirectories with the important content first--this
      // will take the most time. Then quickly delete the little locks, logs
      // and links right before we exit. Once the lock file is gone there will
      // be a small possibility of a server race if a client is waiting, but
      // all significant files will be gone by then.
      FileSystemUtils.deleteTreesBelow(outputBase);
      FileSystemUtils.deleteTree(outputBase);
    } else if (cleanOptions.expunge_async) {
      LOG.info("Expunging asynchronously...");
      String tempBaseName = outputBase.getBaseName() + "_tmp_" + ProcessUtils.getpid();

      // Keeping tempOutputBase in the same directory ensures it remains in the
      // same file system, and therefore the mv will be atomic and fast.
      Path tempOutputBase = outputBase.getParentDirectory().getChild(tempBaseName);
      outputBase.renameTo(tempOutputBase);
      env.getReporter()
          .handle(Event.info(null, "Output base moved to " + tempOutputBase + " for deletion"));

      // Daemonize the shell and use the double-fork idiom to ensure that the shell
      // exits even while the "rm -rf" command continues.
      String command =
          String.format(
              "exec >&- 2>&- <&- && (/usr/bin/setsid /bin/rm -rf %s &)&",
              ShellEscaper.escapeString(tempOutputBase.getPathString()));

      LOG.info("Executing shell commmand " + ShellEscaper.escapeString(command));

      // Doesn't throw iff command exited and was successful.
      new CommandBuilder()
          .addArg(command)
          .useShell(true)
          .setWorkingDir(tempOutputBase.getParentDirectory())
          .build()
          .execute();
    } else {
      LOG.info("Output cleaning...");
      runtime.clearCaches();
      // In order to be sure that we delete everything, delete the workspace directory both for
      // --deep_execroot and for --nodeep_execroot.
      for (String directory :
          new String[] {runtime.getWorkspaceName(), "execroot/" + runtime.getWorkspaceName()}) {
        Path child = outputBase.getRelative(directory);
        if (child.exists()) {
          LOG.finest("Cleaning " + child);
          FileSystemUtils.deleteTreesBelow(child);
        }
      }
    }
    // remove convenience links
    OutputDirectoryLinksUtils.removeOutputDirectoryLinks(
        runtime.getWorkspaceName(), runtime.getWorkspace(), env.getReporter(), symlinkPrefix);
    // shutdown on expunge cleans
    if (cleanOptions.expunge || cleanOptions.expunge_async) {
      throw new ShutdownBlazeServerException(0);
    }
  }
예제 #3
0
  /**
   * Computes, for each C++ source file in {@link #getLinkstamps}, the command necessary to compile
   * that file such that the output is correctly fed into the link command.
   *
   * <p>As these options (as well as all others) are taken into account when computing the action
   * key, they do not directly contain volatile build information to avoid unnecessary relinking.
   * Instead this information is passed as an additional header generated by {@link
   * com.google.devtools.build.lib.rules.cpp.WriteBuildInfoHeaderAction}.
   *
   * @param outputPrefix prefix to add before the linkstamp outputs' exec paths
   * @return a list of shell-escaped compiler commmands, one for each entry in {@link
   *     #getLinkstamps}
   */
  public List<String> getLinkstampCompileCommands(String outputPrefix) {
    if (linkstamps.isEmpty()) {
      return ImmutableList.of();
    }

    String compilerCommand = cppConfiguration.getCppExecutable().getPathString();
    List<String> commands = Lists.newArrayListWithCapacity(linkstamps.size());

    for (Map.Entry<Artifact, Artifact> linkstamp : linkstamps.entrySet()) {
      List<String> optionList = new ArrayList<>();

      // Defines related to the build info are read from generated headers.
      for (Artifact header : buildInfoHeaderArtifacts) {
        optionList.add("-include");
        optionList.add(header.getExecPathString());
      }

      String labelReplacement =
          Matcher.quoteReplacement(
              isSharedNativeLibrary() ? output.getExecPathString() : Label.print(owner.getLabel()));
      String outputPathReplacement = Matcher.quoteReplacement(output.getExecPathString());
      for (String option : linkstampCompileOptions) {
        optionList.add(
            option
                .replaceAll(Pattern.quote("${LABEL}"), labelReplacement)
                .replaceAll(Pattern.quote("${OUTPUT_PATH}"), outputPathReplacement));
      }

      optionList.add("-DGPLATFORM=\"" + cppConfiguration + "\"");

      // Needed to find headers included from linkstamps.
      optionList.add("-I.");

      // Add sysroot.
      PathFragment sysroot = cppConfiguration.getSysroot();
      if (sysroot != null) {
        optionList.add("--sysroot=" + sysroot.getPathString());
      }

      // Add toolchain compiler options.
      optionList.addAll(cppConfiguration.getCompilerOptions(features));
      optionList.addAll(cppConfiguration.getCOptions());
      optionList.addAll(cppConfiguration.getUnfilteredCompilerOptions(features));
      if (CppFileTypes.CPP_SOURCE.matches(linkstamp.getKey().getExecPath())) {
        optionList.addAll(cppConfiguration.getCxxOptions(features));
      }

      // For dynamic libraries, produce position independent code.
      if (linkTargetType == LinkTargetType.DYNAMIC_LIBRARY
          && cppConfiguration.toolchainNeedsPic()) {
        optionList.add("-fPIC");
      }

      // Stamp FDO builds with FDO subtype string
      if (fdoBuildStamp != null) {
        optionList.add("-D" + CppConfiguration.FDO_STAMP_MACRO + "=\"" + fdoBuildStamp + "\"");
      }

      // Add the compilation target.
      optionList.add("-c");
      optionList.add(linkstamp.getKey().getExecPathString());

      // Assemble the final command, exempting outputPrefix from shell escaping.
      commands.add(
          compilerCommand
              + " "
              + ShellEscaper.escapeJoinAll(optionList)
              + " -o "
              + outputPrefix
              + ShellEscaper.escapeString(linkstamp.getValue().getExecPathString()));
    }

    return commands;
  }