diff options
-rw-r--r-- | src/buildtool/common/TARGETS | 21 | ||||
-rw-r--r-- | src/buildtool/common/artifact_digest.hpp | 5 | ||||
-rw-r--r-- | src/buildtool/common/artifact_digest_factory.cpp | 48 | ||||
-rw-r--r-- | src/buildtool/common/artifact_digest_factory.hpp | 89 |
4 files changed, 163 insertions, 0 deletions
diff --git a/src/buildtool/common/TARGETS b/src/buildtool/common/TARGETS index 88364386..e6d4e126 100644 --- a/src/buildtool/common/TARGETS +++ b/src/buildtool/common/TARGETS @@ -55,6 +55,26 @@ , "private-deps": [["src/buildtool/crypto", "hasher"]] , "stage": ["src", "buildtool", "common"] } +, "artifact_digest_factory": + { "type": ["@", "rules", "CC", "library"] + , "name": ["artifact_digest_factory"] + , "hdrs": ["artifact_digest_factory.hpp"] + , "srcs": ["artifact_digest_factory.cpp"] + , "deps": + [ "common" + , ["src/buildtool/crypto", "hash_function"] + , ["src/buildtool/crypto", "hash_info"] + , ["src/buildtool/file_system", "object_type"] + , ["src/utils/cpp", "expected"] + ] + , "private-deps": + [ "bazel_digest_factory" + , "bazel_types" + , ["@", "gsl", "", "gsl"] + , ["src/buildtool/compatibility", "compatibility"] + ] + , "stage": ["src", "buildtool", "common"] + } , "common": { "type": ["@", "rules", "CC", "library"] , "name": ["common"] @@ -68,6 +88,7 @@ , "deps": [ "bazel_types" , ["src/buildtool/crypto", "hash_function"] + , ["src/buildtool/crypto", "hash_info"] , ["src/buildtool/file_system", "object_type"] , ["src/buildtool/compatibility", "compatibility"] , ["src/buildtool/logging", "log_level"] diff --git a/src/buildtool/common/artifact_digest.hpp b/src/buildtool/common/artifact_digest.hpp index 93c41464..ebd01ceb 100644 --- a/src/buildtool/common/artifact_digest.hpp +++ b/src/buildtool/common/artifact_digest.hpp @@ -24,6 +24,7 @@ #include "src/buildtool/common/bazel_types.hpp" #include "src/buildtool/compatibility/native_support.hpp" #include "src/buildtool/crypto/hash_function.hpp" +#include "src/buildtool/crypto/hash_info.hpp" #include "src/buildtool/file_system/object_type.hpp" #include "src/utils/cpp/gsl.hpp" #include "src/utils/cpp/hash_combine.hpp" @@ -36,6 +37,10 @@ class ArtifactDigest final { public: ArtifactDigest() noexcept = default; + explicit ArtifactDigest(HashInfo const& hash_info, + std::size_t size) noexcept + : size_{size}, hash_{hash_info.Hash()}, is_tree_{hash_info.IsTree()} {} + explicit ArtifactDigest(bazel_re::Digest const& digest) noexcept : size_{gsl::narrow<std::size_t>(digest.size_bytes())}, hash_{NativeSupport::Unprefix(digest.hash())}, diff --git a/src/buildtool/common/artifact_digest_factory.cpp b/src/buildtool/common/artifact_digest_factory.cpp new file mode 100644 index 00000000..05bfd031 --- /dev/null +++ b/src/buildtool/common/artifact_digest_factory.cpp @@ -0,0 +1,48 @@ +// 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_digest_factory.hpp" + +#include "gsl/gsl" +#include "src/buildtool/common/bazel_digest_factory.hpp" +#include "src/buildtool/common/bazel_types.hpp" +#include "src/buildtool/compatibility/compatibility.hpp" + +auto ArtifactDigestFactory::FromBazel(HashFunction::Type hash_type, + bazel_re::Digest const& digest) noexcept + -> expected<ArtifactDigest, std::string> { + auto hash_info = BazelDigestFactory::ToHashInfo(hash_type, digest); + if (not hash_info) { + return unexpected{std::move(hash_info).error()}; + } + return ArtifactDigest{*hash_info, + static_cast<std::size_t>(digest.size_bytes())}; +} + +auto ArtifactDigestFactory::ToBazel(ArtifactDigest const& digest) + -> bazel_re::Digest { + static constexpr std::size_t kGitSHA1Length = 40; + // TODO(denisov): The type of the bazel digest produced here doesn't have to + // be the same as Compatibility::IsCompatible returns, since we're + // computing hashes with a predefined type in many places. Once + // ArtifactDigest gets HashInfo as a field, it will be taken from there + // directly, but for now it is 'guessed' based on the length of the hash. + auto const type = digest.hash().size() == kGitSHA1Length + ? HashFunction::Type::GitSHA1 + : HashFunction::Type::PlainSHA256; + auto const hash_info = + HashInfo::Create(type, digest.hash(), digest.IsTree()); + return BazelDigestFactory::Create(*hash_info, + gsl::narrow<std::int64_t>(digest.size())); +} diff --git a/src/buildtool/common/artifact_digest_factory.hpp b/src/buildtool/common/artifact_digest_factory.hpp new file mode 100644 index 00000000..09c0b478 --- /dev/null +++ b/src/buildtool/common/artifact_digest_factory.hpp @@ -0,0 +1,89 @@ +// 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. + +#ifndef INCLUDED_SRC_BUILDTOOL_COMMON_ARTIFACT_DIGEST_FACTORY_HPP +#define INCLUDED_SRC_BUILDTOOL_COMMON_ARTIFACT_DIGEST_FACTORY_HPP + +#include <cstddef> +#include <filesystem> +#include <optional> +#include <string> +#include <utility> + +#include "src/buildtool/common/artifact_digest.hpp" +#include "src/buildtool/crypto/hash_function.hpp" +#include "src/buildtool/crypto/hash_info.hpp" +#include "src/buildtool/file_system/object_type.hpp" +#include "src/utils/cpp/expected.hpp" + +namespace build::bazel::remote::execution::v2 { +class Digest; +} +namespace bazel_re = build::bazel::remote::execution::v2; + +class ArtifactDigestFactory final { + public: + /// \brief Create ArtifactDigest from bazel_re::Digest + /// \param hash_type Type of the hash function that was used for creation of + /// the hash + /// \param digest Digest to be converted + /// \return A valid ArtifactDigest on success or an error message if + /// validation fails. + [[nodiscard]] static auto FromBazel(HashFunction::Type hash_type, + bazel_re::Digest const& digest) noexcept + -> expected<ArtifactDigest, std::string>; + + /// \brief Convert ArtifactDigest to bazel_re::Digest. Throws an exception + /// on a narrow conversion error. + /// \param digest Digest to be converted. + /// \return A valid bazel_re::Digest + [[nodiscard]] static auto ToBazel(ArtifactDigest const& digest) + -> bazel_re::Digest; + + /// \brief Hash content using hash function and return a valid + /// ArtifactDigest + /// \tparam kType Type of the hashing algorithm to be used + /// \param hash_function Hash function to be used for hashing + /// \param content Content to be hashed + /// \return The digest of the content + template <ObjectType kType> + [[nodiscard]] static auto HashDataAs(HashFunction hash_function, + std::string const& content) noexcept + -> ArtifactDigest { + auto const hash_info = + HashInfo::HashData(hash_function, content, IsTreeObject(kType)); + return ArtifactDigest{hash_info, content.size()}; + } + + /// \brief Hash file using hash function and return a valid ArtifactDigest + /// \tparam kType Type of the hashing algorithm to be used + /// \param hash_function Hash function to be used for hashing + /// \param content Content to be hashed + /// \return The digest of the file + template <ObjectType kType> + [[nodiscard]] static auto HashFileAs( + HashFunction hash_function, + std::filesystem::path const& path) noexcept + -> std::optional<ArtifactDigest> { + auto const hash_info = + HashInfo::HashFile(hash_function, path, IsTreeObject(kType)); + if (not hash_info) { + return std::nullopt; + } + return ArtifactDigest{hash_info->first, + static_cast<std::size_t>(hash_info->second)}; + } +}; + +#endif // INCLUDED_SRC_BUILDTOOL_COMMON_ARTIFACT_DIGEST_FACTORY_HPP |