void WorkProcessor::ProcessWorkRequest()

in tools/worker/work_processor.cc [49:197]


void WorkProcessor::ProcessWorkRequest(
    const blaze::worker::WorkRequest &request,
    blaze::worker::WorkResponse *response) {
  std::vector<std::string> processed_args(universal_args_);

  // Bazel's worker spawning strategy reads the arguments from the params file
  // and inserts them into the proto. This means that if we just try to pass
  // them verbatim to swiftc, we might end up with a command line that's too
  // long. Rather than try to figure out these limits (which is very
  // OS-specific and easy to get wrong), we unconditionally write the processed
  // arguments out to a params file.
  auto params_file = TempFile::Create("swiftc_params.XXXXXX");
  std::ofstream params_file_stream(params_file->GetPath());

  OutputFileMap output_file_map;
  std::string output_file_map_path;
  bool is_wmo = false;
  bool is_dump_ast = false;

  std::string prev_arg;
  for (auto arg : request.arguments()) {
    auto original_arg = arg;
    // Peel off the `-output-file-map` argument, so we can rewrite it if
    // necessary later.
    if (arg == "-output-file-map") {
      arg.clear();
    } else if (arg == "-dump-ast") {
      is_dump_ast = true;
    } else if (prev_arg == "-output-file-map") {
      output_file_map_path = arg;
      arg.clear();
    } else if (ArgumentEnablesWMO(arg)) {
      is_wmo = true;
    }

    if (!arg.empty()) {
      params_file_stream << arg << '\n';
    }

    prev_arg = original_arg;
  }

  bool is_incremental = !is_wmo && !is_dump_ast;

  if (!output_file_map_path.empty()) {
    if (is_incremental) {
      output_file_map.ReadFromPath(output_file_map_path);

      // Rewrite the output file map to use the incremental storage area and
      // pass the compiler the path to the rewritten file.
      auto new_path =
          ReplaceExtension(output_file_map_path, ".incremental.json");
      output_file_map.WriteToPath(new_path);

      params_file_stream << "-output-file-map\n";
      params_file_stream << new_path << '\n';

      // Pass the incremental flags only if WMO is disabled. WMO would overrule
      // incremental mode anyway, but since we control the passing of this flag,
      // there's no reason to pass it when it's a no-op.
      params_file_stream << "-incremental\n";
    } else {
      // If WMO or -dump-ast is forcing us out of incremental mode, just put the
      // original output file map back so the outputs end up where they should.
      params_file_stream << "-output-file-map\n";
      params_file_stream << output_file_map_path << '\n';
    }
  }

  processed_args.push_back("@" + params_file->GetPath());
  params_file_stream.close();

  std::ostringstream stderr_stream;

  if (is_incremental) {
    for (const auto &expected_object_pair :
         output_file_map.incremental_outputs()) {
      // Bazel creates the intermediate directories for the files declared at
      // analysis time, but we need to manually create the ones for the
      // incremental storage area.
      auto dir_path = Dirname(expected_object_pair.second);
      if (!MakeDirs(dir_path, S_IRWXU)) {
        stderr_stream << "swift_worker: Could not create directory " << dir_path
                      << " (errno " << errno << ")\n";
        FinalizeWorkRequest(request, response, EXIT_FAILURE, stderr_stream);
        return;
      }
    }

    // Copy some input files from the incremental storage area to the locations
    // where Bazel will generate them.
    for (const auto &expected_object_pair :
         output_file_map.incremental_inputs()) {
      if (FileExists(expected_object_pair.second)) {
        if (!CopyFile(expected_object_pair.second,
                      expected_object_pair.first)) {
          stderr_stream << "swift_worker: Could not copy "
                        << expected_object_pair.second << " to "
                        << expected_object_pair.first << " (errno " << errno
                        << ")\n";
          FinalizeWorkRequest(request, response, EXIT_FAILURE, stderr_stream);
          return;
        }
      }
    }
  }

  SwiftRunner swift_runner(processed_args, /*force_response_file=*/true);
  int exit_code = swift_runner.Run(&stderr_stream, /*stdout_to_stderr=*/true);

  if (is_incremental) {
    // Copy the output files from the incremental storage area back to the
    // locations where Bazel declared the files.
    for (const auto &expected_object_pair :
         output_file_map.incremental_outputs()) {
      if (!CopyFile(expected_object_pair.second, expected_object_pair.first)) {
        stderr_stream << "swift_worker: Could not copy "
                      << expected_object_pair.second << " to "
                      << expected_object_pair.first << " (errno " << errno
                      << ")\n";
        FinalizeWorkRequest(request, response, EXIT_FAILURE, stderr_stream);
        return;
      }
    }

    // Copy the replaced input files back to the incremental storage for the
    // next run.
    for (const auto &expected_object_pair :
         output_file_map.incremental_inputs()) {
      if (FileExists(expected_object_pair.first)) {
        if (FileExists(expected_object_pair.second)) {
          // CopyFile fails if the file already exists
          RemoveFile(expected_object_pair.second);
        }
        if (!CopyFile(expected_object_pair.first,
                      expected_object_pair.second)) {
          stderr_stream << "swift_worker: Could not copy "
                        << expected_object_pair.first << " to "
                        << expected_object_pair.second << " (errno " << errno
                        << ")\n";
          FinalizeWorkRequest(request, response, EXIT_FAILURE, stderr_stream);
          return;
        }
      }
    }
  }

  FinalizeWorkRequest(request, response, exit_code, stderr_stream);
}