// Copyright 2022 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. #ifndef INCLUDED_SRC_BUILDTOOL_COMMON_ARTIFACT_HPP #define INCLUDED_SRC_BUILDTOOL_COMMON_ARTIFACT_HPP #include #include #include #include #include #include #include #include #include "fmt/core.h" #include "nlohmann/json.hpp" #include "src/buildtool/common/artifact_digest.hpp" #include "src/buildtool/common/artifact_digest_factory.hpp" #include "src/buildtool/common/identifier.hpp" #include "src/buildtool/crypto/hash_function.hpp" #include "src/buildtool/file_system/object_type.hpp" #include "src/buildtool/logging/log_level.hpp" #include "src/buildtool/logging/logger.hpp" #include "src/utils/cpp/expected.hpp" #include "src/utils/cpp/hash_combine.hpp" // Artifacts (source files, libraries, executables...) need to store their // identifier class Artifact { public: struct ObjectInfo { ArtifactDigest digest; ObjectType type{}; bool failed{}; [[nodiscard]] auto operator==(ObjectInfo const& other) const { return (digest == other.digest and type == other.type and failed == other.failed); } [[nodiscard]] auto operator!=(ObjectInfo const& other) const { return not(*this == other); } // Create string of the form '[hash:size:type]' [[nodiscard]] auto ToString(bool size_unknown = false) const noexcept -> std::string { auto size_str = size_unknown ? std::string{} : std::to_string(digest.size()); return fmt::format("[{}:{}:{}]{}", digest.hash(), size_str, ToChar(type), failed ? " FAILED" : ""); } // Create JSON of the form '{"id": "hash", "size": x, "file_type": "f"}' // As the failed property is only internal to a run, discard it. [[nodiscard]] auto ToJson() const -> nlohmann::json { return {{"id", digest.hash()}, {"size", digest.size()}, {"file_type", std::string{ToChar(type)}}}; } [[nodiscard]] static auto FromString(HashFunction::Type hash_type, std::string const& s) noexcept -> std::optional { std::istringstream iss(s); std::string id{}; std::string size_str{}; std::string type{}; if (not(iss.get() == '[') or not std::getline(iss, id, ':') or not std::getline(iss, size_str, ':') or not std::getline(iss, type, ']')) { Logger::Log(LogLevel::Debug, "failed parsing object info from string."); return std::nullopt; } std::size_t size = 0; try { size = std::stoul(size_str); } catch (std::out_of_range const& e) { Logger::Log(LogLevel::Debug, "size raised out_of_range exception."); return std::nullopt; } catch (std::invalid_argument const& e) { Logger::Log(LogLevel::Debug, "size raised invalid_argument exception."); return std::nullopt; } auto const object_type = FromChar(*type.c_str()); auto digest = ArtifactDigestFactory::Create( hash_type, id, size, IsTreeObject(object_type)); if (not digest) { Logger::Log(LogLevel::Debug, "{}", std::move(digest).error()); return std::nullopt; } return ObjectInfo{.digest = *std::move(digest), .type = object_type}; } }; explicit Artifact(ArtifactIdentifier id) noexcept : id_{std::move(id)} {} [[nodiscard]] auto Id() const& noexcept -> ArtifactIdentifier const& { return id_; } [[nodiscard]] auto Id() && noexcept -> ArtifactIdentifier { return std::move(id_); } [[nodiscard]] auto FilePath() const noexcept -> std::optional { return file_path_; } [[nodiscard]] auto Repository() const noexcept -> std::string { return repo_; } [[nodiscard]] auto Digest() const noexcept -> std::optional { return object_info_ ? std::optional{object_info_->digest} : std::nullopt; } [[nodiscard]] auto Type() const noexcept -> std::optional { return object_info_ ? std::optional{object_info_->type} : std::nullopt; } [[nodiscard]] auto Info() const& noexcept -> std::optional const& { return object_info_; } [[nodiscard]] auto Info() && noexcept -> std::optional { return std::move(object_info_); } void SetObjectInfo(ObjectInfo const& object_info, bool fail_info) const noexcept { if (fail_info) { object_info_ = ObjectInfo{.digest = object_info.digest, .type = object_info.type, .failed = true}; } else { object_info_ = object_info; } } void SetObjectInfo(ArtifactDigest const& digest, ObjectType type, bool failed) const noexcept { object_info_ = ObjectInfo{.digest = digest, .type = type, .failed = failed}; } [[nodiscard]] static auto CreateLocalArtifact( std::string const& id, std::filesystem::path const& file_path, std::string const& repo) noexcept -> Artifact { return Artifact{id, file_path, repo}; } [[nodiscard]] static auto CreateKnownArtifact( std::string const& id, ArtifactDigest const& digest, ObjectType type, std::optional const& repo) noexcept -> Artifact { return Artifact{id, digest, type, false, repo}; } [[nodiscard]] static auto CreateActionArtifact( std::string const& id) noexcept -> Artifact { return Artifact{id}; } private: ArtifactIdentifier id_; std::optional file_path_; std::string repo_; mutable std::optional object_info_; Artifact(ArtifactIdentifier id, std::filesystem::path const& file_path, std::string repo) noexcept : id_{std::move(id)}, file_path_{file_path}, repo_{std::move(repo)} {} Artifact(ArtifactIdentifier id, ArtifactDigest const& digest, ObjectType type, bool failed, std::optional repo) noexcept : id_{std::move(id)} { SetObjectInfo(digest, type, failed); if (repo) { repo_ = std::move(*repo); } } }; namespace std { template <> struct hash { [[nodiscard]] auto operator()( Artifact::ObjectInfo const& info) const noexcept -> std::size_t { std::size_t seed{}; hash_combine(&seed, info.digest); hash_combine(&seed, info.type); hash_combine(&seed, info.failed); return seed; } }; } // namespace std #endif // INCLUDED_SRC_BUILDTOOL_COMMON_ARTIFACT_HPP