blob: f6f860be9f220d910e1efb2abae88f7f5c17f7f5 [file]
#ifndef PRODUCTION_BORG_MGMT_NODE_PROXY_SAFEPOWER_SAFEPOWER_AGENT_PARSE_TEXT_PROTO_H_
#define PRODUCTION_BORG_MGMT_NODE_PROXY_SAFEPOWER_SAFEPOWER_AGENT_PARSE_TEXT_PROTO_H_
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "absl/log/log.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/io/tokenizer.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/text_format.h"
namespace safepower_agent {
namespace internal {
class ErrorCollector : public google::protobuf::io::ErrorCollector {
public:
ErrorCollector() = default;
ErrorCollector(const ErrorCollector&) = delete;
ErrorCollector& operator=(const ErrorCollector&) = delete;
void RecordError(int line, google::protobuf::io::ColumnNumber column,
absl::string_view message) override;
void RecordWarning(int line, google::protobuf::io::ColumnNumber column,
absl::string_view message) override;
std::string message() && { return std::move(message_); }
protected:
virtual std::string ExtractLine(int line) const = 0;
private:
std::string message_;
};
class ErrorCollectorString : public ErrorCollector {
public:
explicit ErrorCollectorString(absl::string_view text_proto)
: text_proto_(text_proto) {}
std::string ExtractLine(int line) const override;
private:
absl::string_view text_proto_;
};
class ErrorCollectorFile : public ErrorCollector {
public:
explicit ErrorCollectorFile(const std::string& path) : path_(path) {}
std::string ExtractLine(int line) const override;
private:
const std::string& path_;
};
} // namespace internal
template <typename Proto>
absl::StatusOr<Proto> ParseTextProto(absl::string_view text_proto) {
google::protobuf::TextFormat::Parser parser;
internal::ErrorCollectorString error_collector(text_proto);
parser.RecordErrorsTo(&error_collector);
Proto proto;
if (!parser.ParseFromString(text_proto, &proto)) {
return absl::InvalidArgumentError(std::move(error_collector).message());
}
return proto;
}
template <typename Proto>
absl::StatusOr<Proto> ParseTextProtoFromFile(const std::string& path) {
google::protobuf::TextFormat::Parser parser;
internal::ErrorCollectorFile error_collector(path);
parser.RecordErrorsTo(&error_collector);
Proto proto;
int fd = open(path.c_str(), O_RDONLY);
if (fd < 0) {
return absl::InvalidArgumentError(
absl::StrCat("Failed to open file: ", path, " :", strerror(errno)));
}
google::protobuf::io::FileInputStream stream(fd);
stream.SetCloseOnDelete(true);
if (!parser.Parse(&stream, &proto)) {
return absl::InvalidArgumentError(std::move(error_collector).message());
}
return proto;
}
class ParseTextProtoOrDieHelper {
public:
explicit ParseTextProtoOrDieHelper(absl::string_view text) : text_(text) {}
template <typename Proto>
operator Proto() && { // NOLINT - intentional, the common usage requires
// this.
auto result = ParseTextProto<Proto>(text_);
if (!result.ok()) {
LOG(FATAL) << "Failed to parse text proto: " << result.status().message();
}
return std::move(*result);
}
private:
absl::string_view text_;
};
inline ParseTextProtoOrDieHelper ParseTextProtoOrDie(absl::string_view text) {
return ParseTextProtoOrDieHelper(text);
}
} // namespace safepower_agent
#endif // PRODUCTION_BORG_MGMT_NODE_PROXY_SAFEPOWER_SAFEPOWER_AGENT_PARSE_TEXT_PROTO_H_