blob: d08071884b5270480658bdf84a14f90c0be11a18 [file] [log] [blame]
#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;
}
} // namespace safepower_agent
#endif // PRODUCTION_BORG_MGMT_NODE_PROXY_SAFEPOWER_SAFEPOWER_AGENT_PARSE_TEXT_PROTO_H_