blob: 0cca8ed8426c8d71c397a4db1a55a0192b0c0959 [file] [edit]
// Copyright 2025 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "delayed_commands.h"
#include "build_config.h"
#include "delayed_worker.h"
#include "delayed_worker_fuchsia_bazel.h"
#include "graph.h"
// Set to 1 to enable debug messages (which will break regression tests).
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define LOG(...) fprintf(stderr, __VA_ARGS__)
#else
#define LOG(...) (void)0
#endif
bool DelayedCommands::empty() const {
return delayed_edges_.empty();
}
void DelayedCommands::SetWorker(std::unique_ptr<DelayedWorker> worker) {
worker_ = std::move(worker);
}
void DelayedCommands::SetSubprocessSet(SubprocessSet* subprocess_set) {
LOG("DELAYED COMMANDS: SET SUBPROCESS_SET");
if (subprocess_set) {
tool_runner_ = DelayedWorkerRunner::CreateFrom(*subprocess_set);
} else {
tool_runner_.reset();
}
}
void DelayedCommands::SetRunnerForTests(
std::unique_ptr<DelayedWorkerRunner> tool_runner) {
LOG("DELAYED COMMANDS: SET RUNNER FOR TESTS");
tool_runner_ = std::move(tool_runner);
}
bool DelayedCommands::CheckEdge(const Edge* edge) {
if (!worker_) {
// No worker means no delayed commands.
LOG("NO DELAYED_COMMANDS WORKER\n");
return false;
}
std::string description = edge->GetDescription();
if (worker_->CheckEdge(edge, description)) {
LOG("FOUND DELAYED EDGE: %s\n", edge->GetDescription().c_str());
delayed_edges_.push_back(edge);
return true;
}
return false;
}
DelayedCommands::Result DelayedCommands::BuildEdges() {
if (delayed_edges_.empty()) {
return { ExitSuccess, "", {} };
}
if (!tool_runner_) {
// Dry-run: fake success.
return { ExitSuccess, "", std::move(delayed_edges_) };
}
DelayedWorker::RequestInfo req;
req.request_id = ++next_request_id_;
uint32_t action_id = 0;
for (const Edge* edge : delayed_edges_) {
/// Compute output paths list.
std::vector<std::string> ninja_outputs;
ninja_outputs.reserve(edge->outputs_.size());
for (const auto& output : edge->outputs_) {
ninja_outputs.push_back(output->path());
}
/// Append one action to the request.
req.actions.push_back({ ++action_id, edge->GetBinding("command"),
edge->GetDescription(), std::move(ninja_outputs),
edge->GetUnescapedDepfile() });
}
for (const auto& pair : build_metadata_) {
req.build_metadata.try_emplace(pair.first, pair.second);
}
DelayedWorker::ResponseInfo response =
worker_->BuildEdges(req, *tool_runner_);
if (response.request_id != req.request_id) {
return { ExitFailure,
StringFormat(
"Invalid worker tool response request_id=%u, expected %u",
static_cast<unsigned>(response.request_id),
static_cast<unsigned>(req.request_id)),
std::move(delayed_edges_) };
}
return { static_cast<ExitStatus>(response.status), std::move(response.output),
std::move(delayed_edges_) };
};
DelayedCommands::DelayedCommands(const BuildConfig& config) {
for (const auto& pair : config.build_metadata) {
build_metadata_.try_emplace(pair.first, pair.second);
}
}
DelayedCommands::~DelayedCommands() = default;