summaryrefslogtreecommitdiff
path: root/src/buildtool/common/artifact_description.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/buildtool/common/artifact_description.cpp')
-rw-r--r--src/buildtool/common/artifact_description.cpp319
1 files changed, 319 insertions, 0 deletions
diff --git a/src/buildtool/common/artifact_description.cpp b/src/buildtool/common/artifact_description.cpp
new file mode 100644
index 00000000..24c34944
--- /dev/null
+++ b/src/buildtool/common/artifact_description.cpp
@@ -0,0 +1,319 @@
+// Copyright 2024 Huawei Cloud Computing Technology Co., Ltd.
+//
+// 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 "src/buildtool/common/artifact_description.hpp"
+
+#include <cstddef>
+
+#include "nlohmann/json.hpp"
+#include "src/buildtool/crypto/hash_function.hpp"
+#include "src/buildtool/logging/log_level.hpp"
+#include "src/buildtool/logging/logger.hpp"
+#include "src/utils/cpp/json.hpp"
+
+namespace {
+[[nodiscard]] auto DescribeLocalArtifact(std::filesystem::path const& src_path,
+ std::string const& repository) noexcept
+ -> nlohmann::json;
+
+[[nodiscard]] auto DescribeKnownArtifact(
+ std::string const& blob_id,
+ std::size_t size,
+ ObjectType type = ObjectType::File) noexcept -> nlohmann::json;
+
+[[nodiscard]] auto DescribeActionArtifact(std::string const& action_id,
+ std::string const& out_path) noexcept
+ -> nlohmann::json;
+
+[[nodiscard]] auto DescribeTreeArtifact(std::string const& tree_id) noexcept
+ -> nlohmann::json;
+
+[[nodiscard]] auto CreateLocalArtifactDescription(nlohmann::json const& data)
+ -> std::optional<ArtifactDescription>;
+
+[[nodiscard]] auto CreateKnownArtifactDescription(nlohmann::json const& data)
+ -> std::optional<ArtifactDescription>;
+
+[[nodiscard]] auto CreateActionArtifactDescription(nlohmann::json const& data)
+ -> std::optional<ArtifactDescription>;
+
+[[nodiscard]] auto CreateTreeArtifactDescription(nlohmann::json const& data)
+ -> std::optional<ArtifactDescription>;
+} // namespace
+
+ArtifactDescription::ArtifactDescription(std::filesystem::path path,
+ std::string repository) noexcept
+ : data_{std::make_pair(std::move(path), std::move(repository))} {}
+
+ArtifactDescription::ArtifactDescription(
+ ArtifactDigest digest,
+ ObjectType file_type,
+ std::optional<std::string> repo) noexcept
+ : data_{std::make_tuple(std::move(digest), file_type, std::move(repo))} {}
+
+ArtifactDescription::ArtifactDescription(std::string action_id,
+ std::filesystem::path path) noexcept
+ : data_{std::make_pair(std::move(action_id), std::move(path))} {}
+
+ArtifactDescription::ArtifactDescription(std::string tree_id) noexcept
+ : data_{std::move(tree_id)} {}
+
+auto ArtifactDescription::FromJson(nlohmann::json const& json) noexcept
+ -> std::optional<ArtifactDescription> {
+ try {
+ auto const type = ExtractValueAs<std::string>(
+ json, "type", [](std::string const& error) {
+ Logger::Log(
+ LogLevel::Error,
+ "{}\ncan not retrieve value for \"type\" from artifact "
+ "description.",
+ error);
+ });
+ auto const data = ExtractValueAs<nlohmann::json>(
+ json, "data", [](std::string const& error) {
+ Logger::Log(
+ LogLevel::Error,
+ "{}\ncan not retrieve value for \"data\" from artifact "
+ "description.",
+ error);
+ });
+
+ if (not(type and data)) {
+ return std::nullopt;
+ }
+
+ if (*type == "LOCAL") {
+ return CreateLocalArtifactDescription(*data);
+ }
+ if (*type == "KNOWN") {
+ return CreateKnownArtifactDescription(*data);
+ }
+ if (*type == "ACTION") {
+ return CreateActionArtifactDescription(*data);
+ }
+ if (*type == "TREE") {
+ return CreateTreeArtifactDescription(*data);
+ }
+ Logger::Log(LogLevel::Error,
+ R"(artifact type must be one of "LOCAL", "KNOWN",
+ "ACTION", or "TREE")");
+ } catch (std::exception const& ex) {
+ Logger::Log(LogLevel::Error,
+ "Failed to parse artifact description from JSON with "
+ "error:\n{}",
+ ex.what());
+ }
+ return std::nullopt;
+}
+
+auto ArtifactDescription::ToJson() const noexcept -> nlohmann::json {
+ try {
+ if (std::holds_alternative<Local>(data_)) {
+ auto const& [path, repo] = std::get<Local>(data_);
+ return DescribeLocalArtifact(path.string(), repo);
+ }
+ if (std::holds_alternative<Known>(data_)) {
+ auto const& [digest, file_type, _] = std::get<Known>(data_);
+ return DescribeKnownArtifact(
+ digest.hash(), digest.size(), file_type);
+ }
+ if (std::holds_alternative<Action>(data_)) {
+ auto const& [action_id, path] = std::get<Action>(data_);
+ return DescribeActionArtifact(action_id, path);
+ }
+ if (std::holds_alternative<Tree>(data_)) {
+ return DescribeTreeArtifact(std::get<Tree>(data_));
+ }
+ Logger::Log(LogLevel::Error, "Internal error, unknown artifact type");
+ } catch (std::exception const& ex) {
+ Logger::Log(LogLevel::Error,
+ "Serializing to JSON failed with error:\n{}",
+ ex.what());
+ }
+ Ensures(false); // unreachable
+ return {};
+}
+
+auto ArtifactDescription::ToArtifact() const noexcept -> Artifact {
+ try {
+ if (std::holds_alternative<Local>(data_)) {
+ auto const& [path, repo] = std::get<Local>(data_);
+ return Artifact::CreateLocalArtifact(id_, path.string(), repo);
+ }
+ if (std::holds_alternative<Known>(data_)) {
+ auto const& [digest, file_type, repo] = std::get<Known>(data_);
+ return Artifact::CreateKnownArtifact(
+ id_, digest.hash(), digest.size(), file_type, repo);
+ }
+ if (std::holds_alternative<Action>(data_) or
+ std::holds_alternative<Tree>(data_)) {
+ return Artifact::CreateActionArtifact(id_);
+ }
+ Logger::Log(LogLevel::Error, "Internal error, unknown artifact type");
+ } catch (std::exception const& ex) {
+ Logger::Log(LogLevel::Error,
+ "Creating artifact failed with error:\n{}",
+ ex.what());
+ }
+ Ensures(false); // unreachable
+ return Artifact{{}};
+}
+
+auto ArtifactDescription::ToString(int indent) const noexcept -> std::string {
+ try {
+ return ToJson().dump(indent);
+ } catch (std::exception const& ex) {
+ Logger::Log(LogLevel::Error,
+ "Serializing artifact failed with error:\n{}",
+ ex.what());
+ }
+ return {};
+}
+
+auto ArtifactDescription::ComputeId(nlohmann::json const& desc) noexcept
+ -> ArtifactIdentifier {
+ try {
+ return HashFunction::ComputeHash(desc.dump()).Bytes();
+ } catch (std::exception const& ex) {
+ Logger::Log(LogLevel::Error,
+ "Computing artifact id failed with error:\n{}",
+ ex.what());
+ }
+ return {};
+}
+
+namespace {
+auto DescribeLocalArtifact(std::filesystem::path const& src_path,
+ std::string const& repository) noexcept
+ -> nlohmann::json {
+ return {
+ {"type", "LOCAL"},
+ {"data", {{"path", src_path.string()}, {"repository", repository}}}};
+}
+
+auto DescribeKnownArtifact(std::string const& blob_id,
+ std::size_t size,
+ ObjectType type) noexcept -> nlohmann::json {
+ std::string const typestr{ToChar(type)};
+ return {
+ {"type", "KNOWN"},
+ {"data", {{"id", blob_id}, {"size", size}, {"file_type", typestr}}}};
+}
+
+auto DescribeActionArtifact(std::string const& action_id,
+ std::string const& out_path) noexcept
+ -> nlohmann::json {
+ return {{"type", "ACTION"},
+ {"data", {{"id", action_id}, {"path", out_path}}}};
+}
+
+auto DescribeTreeArtifact(std::string const& tree_id) noexcept
+ -> nlohmann::json {
+ return {{"type", "TREE"}, {"data", {{"id", tree_id}}}};
+}
+
+auto CreateLocalArtifactDescription(nlohmann::json const& data)
+ -> std::optional<ArtifactDescription> {
+ auto const path =
+ ExtractValueAs<std::string>(data, "path", [](std::string const& error) {
+ Logger::Log(LogLevel::Error,
+ "{}\ncan not retrieve value for \"path\" from "
+ "LOCAL artifact's data.",
+ error);
+ });
+ auto const repository = ExtractValueAs<std::string>(
+ data, "repository", [](std::string const& error) {
+ Logger::Log(LogLevel::Error,
+ "{}\ncan not retrieve value for \"path\" from "
+ "LOCAL artifact's data.",
+ error);
+ });
+ if (path.has_value() and repository.has_value()) {
+ return ArtifactDescription{std::filesystem::path{*path}, *repository};
+ }
+ return std::nullopt;
+}
+
+auto CreateKnownArtifactDescription(nlohmann::json const& data)
+ -> std::optional<ArtifactDescription> {
+ auto const blob_id =
+ ExtractValueAs<std::string>(data, "id", [](std::string const& error) {
+ Logger::Log(LogLevel::Error,
+ "{}\ncan not retrieve value for \"id\" from "
+ "KNOWN artifact's data.",
+ error);
+ });
+ auto const size =
+ ExtractValueAs<std::size_t>(data, "size", [](std::string const& error) {
+ Logger::Log(LogLevel::Error,
+ "{}\ncan not retrieve value for \"size\" from "
+ "KNOWN artifact's data.",
+ error);
+ });
+ auto const file_type = ExtractValueAs<std::string>(
+ data, "file_type", [](std::string const& error) {
+ Logger::Log(LogLevel::Error,
+ "{}\ncan not retrieve value for \"file_type\" from "
+ "KNOWN artifact's data.",
+ error);
+ });
+ if (blob_id.has_value() and size.has_value() and file_type.has_value() and
+ file_type->size() == 1) {
+ auto const& object_type = FromChar((*file_type)[0]);
+ return ArtifactDescription{
+ ArtifactDigest{*blob_id, *size, IsTreeObject(object_type)},
+ object_type};
+ }
+ return std::nullopt;
+}
+
+auto CreateActionArtifactDescription(nlohmann::json const& data)
+ -> std::optional<ArtifactDescription> {
+ auto const action_id =
+ ExtractValueAs<std::string>(data, "id", [](std::string const& error) {
+ Logger::Log(LogLevel::Error,
+ "{}\ncan not retrieve value for \"id\" from "
+ "ACTION artifact's data.",
+ error);
+ });
+
+ auto const path =
+ ExtractValueAs<std::string>(data, "path", [](std::string const& error) {
+ Logger::Log(LogLevel::Error,
+ "{}\ncan not retrieve value for \"path\" from "
+ "ACTION artifact's data.",
+ error);
+ });
+ if (action_id.has_value() and path.has_value()) {
+ return ArtifactDescription{*action_id, std::filesystem::path{*path}};
+ }
+ return std::nullopt;
+}
+
+auto CreateTreeArtifactDescription(nlohmann::json const& data)
+ -> std::optional<ArtifactDescription> {
+ auto const tree_id =
+ ExtractValueAs<std::string>(data, "id", [](std::string const& error) {
+ Logger::Log(LogLevel::Error,
+ "{}\ncan not retrieve value for \"id\" from "
+ "TREE artifact's data.",
+ error);
+ });
+
+ if (tree_id.has_value()) {
+ return ArtifactDescription{*tree_id};
+ }
+ return std::nullopt;
+}
+} // namespace