diff options
Diffstat (limited to 'src/buildtool/common/artifact.hpp')
-rw-r--r-- | src/buildtool/common/artifact.hpp | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/src/buildtool/common/artifact.hpp b/src/buildtool/common/artifact.hpp new file mode 100644 index 00000000..6c97ab24 --- /dev/null +++ b/src/buildtool/common/artifact.hpp @@ -0,0 +1,214 @@ +#ifndef INCLUDED_SRC_BUILDTOOL_COMMON_ARTIFACT_HPP +#define INCLUDED_SRC_BUILDTOOL_COMMON_ARTIFACT_HPP + +#include <filesystem> +#include <optional> +#include <string> +#include <unordered_map> +#include <utility> + +#include "nlohmann/json.hpp" +#include "src/buildtool/common/artifact_digest.hpp" +#include "src/buildtool/common/identifier.hpp" +#include "src/buildtool/file_system/object_type.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() const noexcept -> std::string { + return fmt::format("[{}:{}:{}]{}", + digest.hash(), + digest.size(), + 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 noexcept -> nlohmann::json { + return {{"id", digest.hash()}, + {"size", digest.size()}, + {"file_type", std::string{ToChar(type)}}}; + } + + [[nodiscard]] static auto FromString(std::string const& s) noexcept + -> std::optional<ObjectInfo> { + 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::Error, + "failed parsing object info from string."); + return std::nullopt; + } + try { + std::size_t size = std::stoul(size_str); + return ObjectInfo{ArtifactDigest{id, size}, + FromChar(*type.c_str())}; + } catch (std::out_of_range const& e) { + Logger::Log(LogLevel::Error, + "size raised out_of_range exception."); + } catch (std::invalid_argument const& e) { + Logger::Log(LogLevel::Error, + "size raised invalid_argument exception."); + } + return std::nullopt; + } + + [[nodiscard]] static auto FromJson(nlohmann::json const& j) + -> std::optional<ObjectInfo> { + if (j.is_object() and j["id"].is_string() and + j["size"].is_number() and j["type"].is_string()) { + return ObjectInfo{ + ArtifactDigest{j["id"].get<std::string>(), + j["size"].get<std::size_t>()}, + FromChar(*(j["type"].get<std::string>().c_str()))}; + } + return std::nullopt; + } + }; + + explicit Artifact(ArtifactIdentifier id) noexcept : id_{std::move(id)} {} + + Artifact(Artifact const& other) noexcept + : id_{other.id_}, file_path_{other.file_path_}, repo_{other.repo_} { + object_info_ = other.object_info_; + } + + Artifact(Artifact&&) noexcept = default; + ~Artifact() noexcept = default; + auto operator=(Artifact const&) noexcept -> Artifact& = delete; + auto operator=(Artifact&&) noexcept -> Artifact& = default; + + [[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<std::filesystem::path> { + return file_path_; + } + + [[nodiscard]] auto Repository() const noexcept -> std::string { + return repo_; + } + + [[nodiscard]] auto Digest() const noexcept + -> std::optional<ArtifactDigest> { + return object_info_ ? std::optional{object_info_->digest} + : std::nullopt; + } + + [[nodiscard]] auto Type() const noexcept -> std::optional<ObjectType> { + return object_info_ ? std::optional{object_info_->type} : std::nullopt; + } + + [[nodiscard]] auto Info() const& noexcept + -> std::optional<ObjectInfo> const& { + return object_info_; + } + [[nodiscard]] auto Info() && noexcept -> std::optional<ObjectInfo> { + return std::move(object_info_); + } + + void SetObjectInfo(ObjectInfo const& object_info, + bool fail_info) const noexcept { + if (fail_info) { + object_info_ = + ObjectInfo{object_info.digest, object_info.type, true}; + } + else { + object_info_ = object_info; + } + } + + void SetObjectInfo(ArtifactDigest const& digest, + ObjectType type, + bool failed) const noexcept { + object_info_ = ObjectInfo{digest, type, 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, + std::string const& hash, + std::size_t size, + ObjectType type, + std::optional<std::string> const& repo) noexcept -> Artifact { + return Artifact{id, {hash, size}, type, false, repo}; + } + + [[nodiscard]] static auto CreateActionArtifact( + std::string const& id) noexcept -> Artifact { + return Artifact{id}; + } + + private: + ArtifactIdentifier id_{}; + std::optional<std::filesystem::path> file_path_{}; + std::string repo_{}; + mutable std::optional<ObjectInfo> 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<std::string> repo) noexcept + : id_{std::move(id)} { + SetObjectInfo(digest, type, failed); + if (repo) { + repo_ = std::move(*repo); + } + } +}; + +namespace std { +template <> +struct hash<Artifact::ObjectInfo> { + [[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 |