| // 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; |
| } |