blob: 677a6c10e3d80e08f2646d6d8ff0a6319dbe54d0 [file]
// 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 "build_event_streamer.h"
#include <cstdarg>
#include "metrics.h"
#include "output_stream.h"
#include "persistent_mode.h"
#include "util.h"
#include "version.h"
// On Windows, a system header #defines DELETE, which conflicts with
// an enum value of the same name in build_event_stream.proto.
// Un-define it as a workaround.
#ifdef DELETE
#undef DELETE
#endif
#include "build_event_stream.pb.h"
static void millis_to_timestamp(int64_t time_millis, bes::google::protobuf::Timestamp* timestamp) {
const ldiv_t t = std::ldiv(time_millis, 1000);
timestamp->set_seconds(t.quot);
timestamp->set_nanos(t.rem * 1e6);
}
BuildEventStreamer::BuildEventStreamer(const char* ninja_command,
const std::string& config_string,
const BuildMetadataMap& metadata,
const std::string& build_id,
int64_t start_time_millis,
OutputStream* out)
: ninja_command_(ninja_command), config_string_(config_string),
metadata_(metadata), build_id_(build_id),
start_time_millis_(start_time_millis), out_(out) {}
BuildEventStreamer::~BuildEventStreamer() = default;
void BuildEventStreamer::EdgeAddedToPlan(const Edge* edge) {
if (out_ == nullptr) return;
}
void BuildEventStreamer::EdgeRemovedFromPlan(const Edge* edge) {
if (out_ == nullptr) return;
}
void BuildEventStreamer::BuildEdgeStarted(const Edge* edge,
int64_t start_time_millis) {
if (out_ == nullptr) return;
}
void BuildEventStreamer::BuildEdgeFinished(
Edge* edge, int64_t start_time_millis, int64_t end_time_millis,
ExitStatus exit_code, const std::string& output) {
if (out_ == nullptr) return;
}
void BuildEventStreamer::BuildStarted() {
if (out_ == nullptr) return;
// Create a BuildStarted event proto.
bes::build_event_stream::BuildEvent event; // crashes on std::string(nullptr)
event.mutable_id()->mutable_started(); // default constructed
bes::build_event_stream::BuildStarted* started = event.mutable_started();
// Populate various fields with information about the build.
if (build_id_ != "") {
started->set_uuid(build_id_);
}
millis_to_timestamp(start_time_millis_, started->mutable_start_time());
started->set_build_tool_version(kNinjaVersion);
started->set_options_description(config_string_);
started->set_command(ninja_command_);
const std::string work_dir(GetCurrentDir());
started->set_working_directory(work_dir);
// ninja doesn't have a notion of workspace directory
// started->set_workspace_directory(...);
const PersistentMode::Status persistent_status =
PersistentMode::GetCurrentProcessStatus();
if (persistent_status == PersistentMode::IsClient) {
started->set_server_pid(PersistentMode::Client().GetServerPidFor(work_dir));
}
// Announce children events.
bes::build_event_stream::BuildEventId metadata_id;
metadata_id.mutable_build_metadata();
event.mutable_children()->push_back(metadata_id);
bes::build_event_stream::BuildEventId finished_id;
finished_id.mutable_build_finished();
event.mutable_children()->push_back(finished_id);
// Post the BuildStarted event.
event.SerializeToOstream(out_);
// Post the children events that are completable at startup time.
// BuildMetadata event:
bes::build_event_stream::BuildEvent metadata_event;
*metadata_event.mutable_id() = metadata_id;
bes::build_event_stream::BuildMetadata* metadata = metadata_event.mutable_build_metadata();
for (const auto& kv : metadata_) {
bes::build_event_stream::BuildMetadata::MetadataEntry md_entry;
md_entry.set_key(kv.first);
md_entry.set_value(kv.second);
metadata->add_metadata(md_entry);
}
metadata_event.SerializeToOstream(out_);
}
void BuildEventStreamer::BuildFinished(ExitStatus exit_status) {
if (out_ == nullptr) return;
// Create a BuildFinished event proto.
bes::build_event_stream::BuildEvent event;
event.mutable_id()->mutable_build_finished(); // default constructed
bes::build_event_stream::BuildFinished* finished = event.mutable_finished();
// Populate various fields with information about the build completion.
finished->set_overall_success(exit_status == ExitSuccess);
// See bazel's lib.ExitCode definitions.
auto* exit_msg = finished->mutable_exit_code();
exit_msg->set_code(int(exit_status));
exit_msg->set_name(exit_status == ExitSuccess ? "SUCCESS" :
exit_status == ExitFailure ? "FAILURE" :
exit_status == ExitInterrupted ? "INTERRUPTED":
"UNKNOWN");
millis_to_timestamp(GetTimeMillis(), finished->mutable_finish_time());
// post it
event.SerializeToOstream(out_);
}
void BuildEventStreamer::SetExplanations(Explanations* explanations) {
if (out_ == nullptr) return;
}
void BuildEventStreamer::WarningV(const char* msg, va_list args) {
if (out_ == nullptr) return;
}
void BuildEventStreamer::ErrorV(const char* msg, va_list args) {
if (out_ == nullptr) return;
}
void BuildEventStreamer::InfoV(const char* msg, va_list args) {
if (out_ == nullptr) return;
}