summaryrefslogtreecommitdiff
path: root/src/buildtool/common/artifact.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/buildtool/common/artifact.hpp')
-rw-r--r--src/buildtool/common/artifact.hpp214
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