diff options
Diffstat (limited to 'src')
21 files changed, 653 insertions, 507 deletions
diff --git a/src/buildtool/file_system/TARGETS b/src/buildtool/file_system/TARGETS index c453ec82..323f6fdc 100644 --- a/src/buildtool/file_system/TARGETS +++ b/src/buildtool/file_system/TARGETS @@ -39,12 +39,7 @@ , "name": ["git_cas"] , "hdrs": ["git_cas.hpp"] , "srcs": ["git_cas.cpp"] - , "deps": - [ "object_type" - , "git_context" - , "git_utils" - , ["@", "gsl-lite", "", "gsl-lite"] - ] + , "deps": ["git_context", "git_utils", ["@", "gsl-lite", "", "gsl-lite"]] , "stage": ["src", "buildtool", "file_system"] , "private-deps": [ ["src/buildtool/logging", "logging"] @@ -98,9 +93,14 @@ , "name": ["git_utils"] , "hdrs": ["git_utils.hpp"] , "srcs": ["git_utils.cpp"] - , "deps": [["@", "gsl-lite", "", "gsl-lite"]] + , "deps": [["@", "gsl-lite", "", "gsl-lite"], "object_type"] , "stage": ["src", "buildtool", "file_system"] - , "private-deps": [["", "libgit2"]] + , "private-deps": + [ ["", "libgit2"] + , ["@", "fmt", "", "fmt"] + , ["src/buildtool/logging", "logging"] + , ["src/utils/cpp", "hex_string"] + ] } , "file_root": { "type": ["@", "rules", "CC", "library"] diff --git a/src/buildtool/file_system/git_cas.cpp b/src/buildtool/file_system/git_cas.cpp index efb464ef..2a4a7142 100644 --- a/src/buildtool/file_system/git_cas.cpp +++ b/src/buildtool/file_system/git_cas.cpp @@ -30,44 +30,6 @@ extern "C" { namespace { -constexpr std::size_t kOIDRawSize{GIT_OID_RAWSZ}; -constexpr std::size_t kOIDHexSize{GIT_OID_HEXSZ}; - -[[nodiscard]] auto GitLastError() noexcept -> std::string { - git_error const* err{nullptr}; - if ((err = git_error_last()) != nullptr and err->message != nullptr) { - return fmt::format("error code {}: {}", err->klass, err->message); - } - return "<unknown error>"; -} - -[[nodiscard]] auto GitObjectID(std::string const& id, - bool is_hex_id = false) noexcept - -> std::optional<git_oid> { - if (id.size() < (is_hex_id ? kOIDHexSize : kOIDRawSize)) { - Logger::Log(LogLevel::Error, - "invalid git object id {}", - is_hex_id ? id : ToHexString(id)); - return std::nullopt; - } - git_oid oid{}; - if (is_hex_id and git_oid_fromstr(&oid, id.c_str()) == 0) { - return oid; - } - if (not is_hex_id and - git_oid_fromraw( - &oid, - reinterpret_cast<unsigned char const*>(id.data()) // NOLINT - ) == 0) { - return oid; - } - Logger::Log(LogLevel::Error, - "parsing git object id {} failed with:\n{}", - is_hex_id ? id : ToHexString(id), - GitLastError()); - return std::nullopt; -} - [[nodiscard]] auto GitTypeToObjectType(git_object_t const& type) noexcept -> std::optional<ObjectType> { switch (type) { diff --git a/src/buildtool/file_system/git_cas.hpp b/src/buildtool/file_system/git_cas.hpp index 58e07616..03b772bc 100644 --- a/src/buildtool/file_system/git_cas.hpp +++ b/src/buildtool/file_system/git_cas.hpp @@ -23,7 +23,6 @@ #include "src/buildtool/file_system/git_context.hpp" #include "src/buildtool/file_system/git_utils.hpp" -#include "src/buildtool/file_system/object_type.hpp" class GitCAS; using GitCASPtr = std::shared_ptr<GitCAS const>; diff --git a/src/buildtool/file_system/git_repo.cpp b/src/buildtool/file_system/git_repo.cpp index d2cec500..baac7cf5 100644 --- a/src/buildtool/file_system/git_repo.cpp +++ b/src/buildtool/file_system/git_repo.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include <src/buildtool/file_system/git_repo.hpp> +#include "src/buildtool/file_system/git_repo.hpp" #include "src/buildtool/logging/logger.hpp" #include "src/utils/cpp/hex_string.hpp" @@ -26,46 +26,6 @@ extern "C" { #ifndef BOOTSTRAP_BUILD_TOOL namespace { -constexpr std::size_t kWaitTime{2}; // time in ms between tries for git locks - -constexpr std::size_t kOIDRawSize{GIT_OID_RAWSZ}; -constexpr std::size_t kOIDHexSize{GIT_OID_HEXSZ}; - -[[nodiscard]] auto GitLastError() noexcept -> std::string { - git_error const* err{nullptr}; - if ((err = git_error_last()) != nullptr and err->message != nullptr) { - return fmt::format("error code {}: {}", err->klass, err->message); - } - return "<unknown error>"; -} - -[[nodiscard]] auto GitObjectID(std::string const& id, - bool is_hex_id = false) noexcept - -> std::optional<git_oid> { - if (id.size() < (is_hex_id ? kOIDHexSize : kOIDRawSize)) { - Logger::Log(LogLevel::Error, - "invalid git object id {}", - is_hex_id ? id : ToHexString(id)); - return std::nullopt; - } - git_oid oid{}; - if (is_hex_id and git_oid_fromstr(&oid, id.c_str()) == 0) { - return oid; - } - if (not is_hex_id and - git_oid_fromraw( - &oid, - reinterpret_cast<unsigned char const*>(id.data()) // NOLINT - ) == 0) { - return oid; - } - Logger::Log(LogLevel::Error, - "parsing git object id {} failed with:\n{}", - is_hex_id ? id : ToHexString(id), - GitLastError()); - return std::nullopt; -} - [[nodiscard]] auto ToHexString(git_oid const& oid) noexcept -> std::optional<std::string> { std::string hex_id(GIT_OID_HEXSZ, '\0'); @@ -278,90 +238,6 @@ void backend_free(git_odb_backend* /*_backend*/) {} // A backend that can be used to read and create tree objects in-memory. auto const kInMemoryODBParent = CreateInMemoryODBParent(); -struct FetchIntoODBBackend { - git_odb_backend parent; - git_odb* target_odb; // the odb where the fetch objects will end up into -}; - -[[nodiscard]] auto fetch_backend_writepack(git_odb_writepack** _writepack, - git_odb_backend* _backend, - [[maybe_unused]] git_odb* odb, - git_indexer_progress_cb progress_cb, - void* progress_payload) -> int { - if (_backend != nullptr) { - auto* b = reinterpret_cast<FetchIntoODBBackend*>(_backend); // NOLINT - return git_odb_write_pack( - _writepack, b->target_odb, progress_cb, progress_payload); - } - return GIT_ERROR; -} - -[[nodiscard]] auto fetch_backend_exists(git_odb_backend* _backend, - const git_oid* oid) -> int { - if (_backend != nullptr) { - auto* b = reinterpret_cast<FetchIntoODBBackend*>(_backend); // NOLINT - return git_odb_exists(b->target_odb, oid); - } - return GIT_ERROR; -} - -void fetch_backend_free(git_odb_backend* /*_backend*/) {} - -[[nodiscard]] auto CreateFetchIntoODBParent() -> git_odb_backend { - git_odb_backend b{}; - b.version = GIT_ODB_BACKEND_VERSION; - // only populate the functions needed - b.writepack = &fetch_backend_writepack; // needed for fetch - b.exists = &fetch_backend_exists; - b.free = &fetch_backend_free; - return b; -} - -// A backend that can be used to fetch from the remote of another repository. -auto const kFetchIntoODBParent = CreateFetchIntoODBParent(); - -// callback to enable SSL certificate check for remote fetch -const auto certificate_check_cb = [](git_cert* /*cert*/, - int /*valid*/, - const char* /*host*/, - void* /*payload*/) -> int { return 1; }; - -// callback to remote fetch without an SSL certificate check -const auto certificate_passthrough_cb = [](git_cert* /*cert*/, - int /*valid*/, - const char* /*host*/, - void* /*payload*/) -> int { - return 0; -}; - -/// \brief Set a custom SSL certificate check callback to honor the existing Git -/// configuration of a repository trying to connect to a remote. -[[nodiscard]] auto SetCustomSSLCertificateCheckCallback(git_repository* repo) - -> git_transport_certificate_check_cb { - // check SSL verification settings, from most to least specific - std::optional<int> check_cert{std::nullopt}; - // check gitconfig; ignore errors - git_config* cfg{nullptr}; - int tmp{}; - if (git_repository_config(&cfg, repo) == 0 and - git_config_get_bool(&tmp, cfg, "http.sslVerify") == 0) { - check_cert = tmp; - } - if (not check_cert) { - // check for GIT_SSL_NO_VERIFY environment variable - const char* ssl_no_verify_var{std::getenv("GIT_SSL_NO_VERIFY")}; - if (ssl_no_verify_var != nullptr and - git_config_parse_bool(&tmp, ssl_no_verify_var) == 0) { - check_cert = tmp; - } - } - // cleanup memory - git_config_free(cfg); - // set callback - return (check_cert and check_cert.value() == 0) ? certificate_passthrough_cb - : certificate_check_cb; -} - } // namespace #endif // BOOTSTRAP_BUILD_TOOL @@ -521,6 +397,20 @@ auto GitRepo::GetGitCAS() const noexcept -> GitCASPtr { return git_cas_; } +auto GitRepo::GetRepoRef() const noexcept + -> std::unique_ptr<git_repository, decltype(&repo_closer)> const& { + return repo_; +} + +auto GitRepo::GetGitPath() const noexcept -> std::filesystem::path const& { + return git_cas_->git_path_; +} + +auto GitRepo::GetGitOdb() const noexcept + -> std::unique_ptr<git_odb, decltype(&odb_closer)> const& { + return git_cas_->odb_; +} + auto GitRepo::StageAndCommitAllAnonymous(std::string const& message, anon_logger_ptr const& logger) noexcept -> std::optional<std::string> { @@ -753,182 +643,6 @@ auto GitRepo::GetHeadCommit(anon_logger_ptr const& logger) noexcept #endif // BOOTSTRAP_BUILD_TOOL } -auto GitRepo::GetCommitFromRemote(std::string const& repo_url, - std::string const& branch, - anon_logger_ptr const& logger) noexcept - -> std::optional<std::string> { -#ifdef BOOTSTRAP_BUILD_TOOL - return std::nullopt; -#else - try { - // only possible for real repository! - if (IsRepoFake()) { - (*logger)("cannot update commit using a fake repository!", - true /*fatal*/); - return std::nullopt; - } - // create remote - git_remote* remote_ptr{nullptr}; - if (git_remote_create_anonymous( - &remote_ptr, repo_.get(), repo_url.c_str()) != 0) { - (*logger)( - fmt::format("creating anonymous remote for git repository {} " - "failed with:\n{}", - GetGitCAS()->git_path_.string(), - GitLastError()), - true /*fatal*/); - git_remote_free(remote_ptr); - return std::nullopt; - } - auto remote = std::unique_ptr<git_remote, decltype(&remote_closer)>( - remote_ptr, remote_closer); - - // connect to remote - git_remote_callbacks callbacks{}; - git_remote_init_callbacks(&callbacks, GIT_REMOTE_CALLBACKS_VERSION); - - // set custom SSL verification callback - callbacks.certificate_check = - SetCustomSSLCertificateCheckCallback(repo_.get()); - - git_proxy_options proxy_opts{}; - git_proxy_options_init(&proxy_opts, GIT_PROXY_OPTIONS_VERSION); - - // set the option to auto-detect proxy settings - proxy_opts.type = GIT_PROXY_AUTO; - - if (git_remote_connect(remote.get(), - GIT_DIRECTION_FETCH, - &callbacks, - &proxy_opts, - nullptr) != 0) { - (*logger)( - fmt::format("connecting to remote {} for git repository {} " - "failed with:\n{}", - repo_url, - GetGitCAS()->git_path_.string(), - GitLastError()), - true /*fatal*/); - return std::nullopt; - } - // get the list of refs from remote - // NOTE: refs will be owned by remote, so we DON'T have to free it! - git_remote_head const** refs = nullptr; - size_t refs_len = 0; - if (git_remote_ls(&refs, &refs_len, remote.get()) != 0) { - (*logger)( - fmt::format("refs retrieval from remote {} failed with:\n{}", - repo_url, - GitLastError()), - true /*fatal*/); - return std::nullopt; - } - // figure out what remote branch the local one is tracking - for (size_t i = 0; i < refs_len; ++i) { - // by treating each read reference string as a path we can easily - // check for the branch name - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - std::filesystem::path ref_name_as_path{refs[i]->name}; - if (ref_name_as_path.filename() == branch) { - // branch found! - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - std::string new_commit_hash{git_oid_tostr_s(&refs[i]->oid)}; - return new_commit_hash; - } - } - (*logger)(fmt::format("could not find branch {} for remote {}", - branch, - repo_url, - GitLastError()), - true /*fatal*/); - return std::nullopt; - } catch (std::exception const& ex) { - Logger::Log(LogLevel::Error, - "get commit from remote failed with:\n{}", - ex.what()); - return std::nullopt; - } -#endif // BOOTSTRAP_BUILD_TOOL -} - -auto GitRepo::FetchFromRemote(std::string const& repo_url, - std::optional<std::string> const& branch, - anon_logger_ptr const& logger) noexcept -> bool { -#ifdef BOOTSTRAP_BUILD_TOOL - return false; -#else - try { - // only possible for real repository! - if (IsRepoFake()) { - (*logger)("cannot fetch commit using a fake repository!", - true /*fatal*/); - return false; - } - // create remote from repo - git_remote* remote_ptr{nullptr}; - if (git_remote_create_anonymous( - &remote_ptr, repo_.get(), repo_url.c_str()) != 0) { - (*logger)(fmt::format("creating remote {} for git repository {} " - "failed with:\n{}", - repo_url, - GetGitCAS()->git_path_.string(), - GitLastError()), - true /*fatal*/); - // cleanup resources - git_remote_free(remote_ptr); - return false; - } - // wrap remote object - auto remote = std::unique_ptr<git_remote, decltype(&remote_closer)>( - remote_ptr, remote_closer); - - // define default fetch options - git_fetch_options fetch_opts{}; - git_fetch_options_init(&fetch_opts, GIT_FETCH_OPTIONS_VERSION); - - // set the option to auto-detect proxy settings - fetch_opts.proxy_opts.type = GIT_PROXY_AUTO; - - // set custom SSL verification callback - fetch_opts.callbacks.certificate_check = - SetCustomSSLCertificateCheckCallback(repo_.get()); - - // disable update of the FETCH_HEAD pointer - fetch_opts.update_fetchhead = 0; - - // setup fetch refspecs array - git_strarray refspecs_array_obj{}; - if (branch) { - // make sure we check for tags as well - std::string tag = fmt::format("+refs/tags/{}", *branch); - std::string head = fmt::format("+refs/heads/{}", *branch); - PopulateStrarray(&refspecs_array_obj, {tag, head}); - } - auto refspecs_array = - std::unique_ptr<git_strarray, decltype(&strarray_deleter)>( - &refspecs_array_obj, strarray_deleter); - - if (git_remote_fetch( - remote.get(), refspecs_array.get(), &fetch_opts, nullptr) != - 0) { - (*logger)( - fmt::format("fetching{} in git repository {} failed " - "with:\n{}", - branch ? fmt::format(" branch {}", *branch) : "", - GetGitCAS()->git_path_.string(), - GitLastError()), - true /*fatal*/); - return false; - } - return true; // success! - } catch (std::exception const& ex) { - Logger::Log( - LogLevel::Error, "fetch from remote failed with:\n{}", ex.what()); - return false; - } -#endif // BOOTSTRAP_BUILD_TOOL -} - auto GitRepo::GetSubtreeFromCommit(std::string const& commit, std::string const& subdir, anon_logger_ptr const& logger) noexcept @@ -1183,89 +897,6 @@ auto GitRepo::CheckCommitExists(std::string const& commit, #endif // BOOTSTRAP_BUILD_TOOL } -auto GitRepo::UpdateCommitViaTmpRepo(std::filesystem::path const& tmp_repo_path, - std::string const& repo_url, - std::string const& branch, - anon_logger_ptr const& logger) - const noexcept -> std::optional<std::string> { -#ifdef BOOTSTRAP_BUILD_TOOL - return std::nullopt; -#else - try { - // preferably with a "fake" repository! - if (not IsRepoFake()) { - (*logger)("WARNING: commit update called on a real repository!\n", - false /*fatal*/); - } - // create the temporary real repository - auto tmp_repo = GitRepo::InitAndOpen(tmp_repo_path, /*is_bare=*/true); - if (tmp_repo == std::nullopt) { - return std::nullopt; - } - // setup wrapped logger - auto wrapped_logger = std::make_shared<anon_logger_t>( - [logger](auto const& msg, bool fatal) { - (*logger)( - fmt::format("While doing commit update via tmp repo:\n{}", - msg), - fatal); - }); - return tmp_repo->GetCommitFromRemote(repo_url, branch, wrapped_logger); - } catch (std::exception const& ex) { - Logger::Log(LogLevel::Error, - "update commit via tmp repo failed with:\n{}", - ex.what()); - return std::nullopt; - } -#endif // BOOTSTRAP_BUILD_TOOL -} - -auto GitRepo::FetchViaTmpRepo(std::filesystem::path const& tmp_repo_path, - std::string const& repo_url, - std::optional<std::string> const& branch, - anon_logger_ptr const& logger) noexcept -> bool { -#ifdef BOOTSTRAP_BUILD_TOOL - return false; -#else - try { - // preferably with a "fake" repository! - if (not IsRepoFake()) { - (*logger)("WARNING: branch fetch called on a real repository!\n", - false /*fatal*/); - } - // create the temporary real repository - // it can be bare, as the refspecs for this fetch will be given - // explicitly. - auto tmp_repo = GitRepo::InitAndOpen(tmp_repo_path, /*is_bare=*/true); - if (tmp_repo == std::nullopt) { - return false; - } - // add backend, with max priority - FetchIntoODBBackend b{kFetchIntoODBParent, git_cas_->odb_.get()}; - if (git_odb_add_backend( - tmp_repo->GetGitCAS()->odb_.get(), - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - reinterpret_cast<git_odb_backend*>(&b), - std::numeric_limits<int>::max()) == 0) { - // setup wrapped logger - auto wrapped_logger = std::make_shared<anon_logger_t>( - [logger](auto const& msg, bool fatal) { - (*logger)( - fmt::format( - "While doing branch fetch via tmp repo:\n{}", msg), - fatal); - }); - return tmp_repo->FetchFromRemote(repo_url, branch, wrapped_logger); - } - return false; - } catch (std::exception const& ex) { - Logger::Log( - LogLevel::Error, "fetch via tmp repo failed with:\n{}", ex.what()); - return false; - } -#endif // BOOTSTRAP_BUILD_TOOL -} - auto GitRepo::GetRepoRootFromPath(std::filesystem::path const& fpath, anon_logger_ptr const& logger) noexcept -> std::optional<std::filesystem::path> { diff --git a/src/buildtool/file_system/git_repo.hpp b/src/buildtool/file_system/git_repo.hpp index 160a67df..a5a8da7a 100644 --- a/src/buildtool/file_system/git_repo.hpp +++ b/src/buildtool/file_system/git_repo.hpp @@ -138,25 +138,6 @@ class GitRepo { [[nodiscard]] auto GetHeadCommit(anon_logger_ptr const& logger) noexcept -> std::optional<std::string>; - /// \brief Retrieve commit hash from remote branch given its name. - /// Only possible with real repository and thus non-thread-safe. - /// Returns the retrieved commit hash, or nullopt if failure. - /// It guarantees the logger is called exactly once with fatal if failure. - [[nodiscard]] auto GetCommitFromRemote( - std::string const& repo_url, - std::string const& branch, - anon_logger_ptr const& logger) noexcept -> std::optional<std::string>; - - /// \brief Fetch from given remote. It can either fetch a given named - /// branch, or it can fetch with base refspecs. - /// Only possible with real repository and thus non-thread-safe. - /// Returns a success flag. - /// It guarantees the logger is called exactly once with fatal if failure. - [[nodiscard]] auto FetchFromRemote(std::string const& repo_url, - std::optional<std::string> const& branch, - anon_logger_ptr const& logger) noexcept - -> bool; - /// \brief Get the tree id of a subtree given the root commit /// Calling it from a fake repository allows thread-safe use. /// Returns the subtree hash, as a string, or nullopt if failure. @@ -195,36 +176,6 @@ class GitRepo { anon_logger_ptr const& logger) noexcept -> std::optional<bool>; - /// \brief Get commit from remote via a temporary repository. - /// Calling it from a fake repository allows thread-safe use. - /// Creates a temporary real repository at the given location and uses it to - /// retrieve from the remote the commit of a branch given its name. - /// Caller needs to make sure the temporary directory exists and that the - /// given path is thread- and process-safe! - /// Returns the commit hash, as a string, or nullopt if failure. - /// It guarantees the logger is called exactly once with fatal if failure. - [[nodiscard]] auto UpdateCommitViaTmpRepo( - std::filesystem::path const& tmp_repo_path, - std::string const& repo_url, - std::string const& branch, - anon_logger_ptr const& logger) const noexcept - -> std::optional<std::string>; - - /// \brief Fetch from a remote via a temporary repository. - /// Calling it from a fake repository allows thread-safe use. - /// Creates a temporary real repository at the given location and uses a - /// custom backend to redirect the fetched objects into the desired odb. - /// Caller needs to make sure the temporary directory exists and that the - /// given path is thread- and process-safe! - /// Uses either a given branch, or fetches using base refspecs. - /// Returns a success flag. - /// It guarantees the logger is called exactly once with fatal if failure. - [[nodiscard]] auto FetchViaTmpRepo( - std::filesystem::path const& tmp_repo_path, - std::string const& repo_url, - std::optional<std::string> const& branch, - anon_logger_ptr const& logger) noexcept -> bool; - /// \brief Try to retrieve the root of the repository containing the /// given path, if the path is actually part of a repository. /// Returns the git folder if path is in a git repo, empty string if path is @@ -244,11 +195,21 @@ class GitRepo { // default to real repo, as that is non-thread-safe bool is_repo_fake_{false}; + protected: /// \brief Open "fake" repository wrapper for existing CAS. explicit GitRepo(GitCASPtr git_cas) noexcept; /// \brief Open real repository at given location. explicit GitRepo(std::filesystem::path const& repo_path) noexcept; + [[nodiscard]] auto GetRepoRef() const noexcept + -> std::unique_ptr<git_repository, decltype(&repo_closer)> const&; + + [[nodiscard]] auto GetGitPath() const noexcept + -> std::filesystem::path const&; + + [[nodiscard]] auto GetGitOdb() const noexcept + -> std::unique_ptr<git_odb, decltype(&odb_closer)> const&; + /// \brief Helper function to allocate and populate the char** pointer of a /// git_strarray from a vector of standard strings. User MUST use /// git_strarray_dispose to deallocate the inner pointer when the strarray diff --git a/src/buildtool/file_system/git_utils.cpp b/src/buildtool/file_system/git_utils.cpp index ec3b5f6d..9fccbd9d 100644 --- a/src/buildtool/file_system/git_utils.cpp +++ b/src/buildtool/file_system/git_utils.cpp @@ -14,10 +14,61 @@ #include "src/buildtool/file_system/git_utils.hpp" +#include "fmt/core.h" +#include "src/buildtool/logging/logger.hpp" +#include "src/utils/cpp/hex_string.hpp" + extern "C" { #include <git2.h> } +#ifndef BOOTSTRAP_BUILD_TOOL +namespace { +constexpr std::size_t kOIDRawSize{GIT_OID_RAWSZ}; +constexpr std::size_t kOIDHexSize{GIT_OID_HEXSZ}; +} // namespace +#endif // BOOTSTRAP_BUILD_TOOL + +auto GitLastError() noexcept -> std::string { +#ifndef BOOTSTRAP_BUILD_TOOL + git_error const* err{nullptr}; + if ((err = git_error_last()) != nullptr and err->message != nullptr) { + return fmt::format("error code {}: {}", err->klass, err->message); + } +#endif // BOOTSTRAP_BUILD_TOOL + return "<unknown error>"; +} + +auto GitObjectID(std::string const& id, bool is_hex_id) noexcept + -> std::optional<git_oid> { +#ifdef BOOTSTRAP_BUILD_TOOL + return std::nullopt; +#else + if (id.size() < (is_hex_id ? kOIDHexSize : kOIDRawSize)) { + Logger::Log(LogLevel::Error, + "invalid git object id {}", + is_hex_id ? id : ToHexString(id)); + return std::nullopt; + } + git_oid oid{}; + if (is_hex_id and git_oid_fromstr(&oid, id.c_str()) == 0) { + return oid; + } + if (not is_hex_id and + git_oid_fromraw( + &oid, + reinterpret_cast<unsigned char const*>(id.data()) // NOLINT + ) == 0) { + return oid; + } + Logger::Log(LogLevel::Error, + "parsing git object id {} failed with:\n{}", + is_hex_id ? id : ToHexString(id), + GitLastError()); + return std::nullopt; +#endif // BOOTSTRAP_BUILD_TOOL +} + void repo_closer(gsl::owner<git_repository*> repo) { #ifndef BOOTSTRAP_BUILD_TOOL git_repository_free(repo); diff --git a/src/buildtool/file_system/git_utils.hpp b/src/buildtool/file_system/git_utils.hpp index 74f21500..d301912a 100644 --- a/src/buildtool/file_system/git_utils.hpp +++ b/src/buildtool/file_system/git_utils.hpp @@ -15,9 +15,13 @@ #ifndef INCLUDED_SRC_BUILDTOOL_FILE_SYSTEM_GIT_UTILS_HPP #define INCLUDED_SRC_BUILDTOOL_FILE_SYSTEM_GIT_UTILS_HPP +#include <optional> + #include "gsl-lite/gsl-lite.hpp" +#include "src/buildtool/file_system/object_type.hpp" extern "C" { +struct git_oid; struct git_odb; struct git_repository; struct git_tree; @@ -31,6 +35,15 @@ struct git_commit; struct git_tree_entry; } +constexpr std::size_t kWaitTime{2}; // time in ms between tries for git locks + +[[nodiscard]] auto GitObjectID(std::string const& id, + bool is_hex_id = false) noexcept + -> std::optional<git_oid>; + +/// \brief Retrieve error message of last libgit2 call. +[[nodiscard]] auto GitLastError() noexcept -> std::string; + void repo_closer(gsl::owner<git_repository*> repo); void odb_closer(gsl::owner<git_odb*> odb); diff --git a/src/other_tools/git_operations/TARGETS b/src/other_tools/git_operations/TARGETS index ac41c117..28e514f0 100644 --- a/src/other_tools/git_operations/TARGETS +++ b/src/other_tools/git_operations/TARGETS @@ -16,8 +16,21 @@ , "stage": ["src", "other_tools", "git_operations"] , "private-deps": [ ["src/buildtool/file_system", "file_system_manager"] - , ["src/buildtool/file_system", "git_repo"] + , "git_repo_remote" , ["src/buildtool/logging", "logging"] ] } +, "git_repo_remote": + { "type": ["@", "rules", "CC", "library"] + , "name": ["git_repo_remote"] + , "hdrs": ["git_repo_remote.hpp"] + , "srcs": ["git_repo_remote.cpp"] + , "deps": [["src/buildtool/file_system", "git_repo"]] + , "stage": ["src", "other_tools", "git_operations"] + , "private-deps": + [ ["src/buildtool/logging", "logging"] + , ["@", "fmt", "", "fmt"] + , ["", "libgit2"] + ] + } } diff --git a/src/other_tools/git_operations/git_operations.cpp b/src/other_tools/git_operations/git_operations.cpp index cdefaef9..b68c54e7 100644 --- a/src/other_tools/git_operations/git_operations.cpp +++ b/src/other_tools/git_operations/git_operations.cpp @@ -17,15 +17,15 @@ #include <vector> #include "src/buildtool/file_system/file_system_manager.hpp" -#include "src/buildtool/file_system/git_repo.hpp" #include "src/buildtool/logging/logger.hpp" +#include "src/other_tools/git_operations/git_repo_remote.hpp" auto CriticalGitOps::GitInitialCommit(GitOpParams const& crit_op_params, AsyncMapConsumerLoggerPtr const& logger) -> GitOpValue { - // Create and open a GitRepo at given target location - auto git_repo = - GitRepo::InitAndOpen(crit_op_params.target_path, /*is_bare=*/false); + // Create and open a GitRepoRemote at given target location + auto git_repo = GitRepoRemote::InitAndOpen(crit_op_params.target_path, + /*is_bare=*/false); if (git_repo == std::nullopt) { (*logger)(fmt::format("could not initialize git repository {}", crit_op_params.target_path.string()), @@ -60,9 +60,9 @@ auto CriticalGitOps::GitEnsureInit(GitOpParams const& crit_op_params, return GitOpValue({nullptr, std::nullopt}); } // Create and open a GitRepo at given target location - auto git_repo = - GitRepo::InitAndOpen(crit_op_params.target_path, - /*is_bare=*/crit_op_params.init_bare.value()); + auto git_repo = GitRepoRemote::InitAndOpen( + crit_op_params.target_path, + /*is_bare=*/crit_op_params.init_bare.value()); if (git_repo == std::nullopt) { (*logger)( fmt::format("could not initialize {} git repository {}", @@ -86,7 +86,7 @@ auto CriticalGitOps::GitKeepTag(GitOpParams const& crit_op_params, return GitOpValue({nullptr, std::nullopt}); } // Open a GitRepo at given location - auto git_repo = GitRepo::Open(crit_op_params.target_path); + auto git_repo = GitRepoRemote::Open(crit_op_params.target_path); if (git_repo == std::nullopt) { (*logger)(fmt::format("could not open git repository {}", crit_op_params.target_path.string()), @@ -120,7 +120,7 @@ auto CriticalGitOps::GitGetHeadId(GitOpParams const& crit_op_params, return GitOpValue({nullptr, std::nullopt}); } // Open a GitRepo at given location - auto git_repo = GitRepo::Open(crit_op_params.target_path); + auto git_repo = GitRepoRemote::Open(crit_op_params.target_path); if (git_repo == std::nullopt) { (*logger)(fmt::format("could not open git repository {}", crit_op_params.target_path.string()), diff --git a/src/other_tools/git_operations/git_repo_remote.cpp b/src/other_tools/git_operations/git_repo_remote.cpp new file mode 100644 index 00000000..177a4301 --- /dev/null +++ b/src/other_tools/git_operations/git_repo_remote.cpp @@ -0,0 +1,405 @@ +// Copyright 2023 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/other_tools/git_operations/git_repo_remote.hpp> + +#include "fmt/core.h" +#include "src/buildtool/logging/logger.hpp" + +extern "C" { +#include <git2.h> +#include <git2/sys/odb_backend.h> +} + +namespace { + +struct FetchIntoODBBackend { + git_odb_backend parent; + git_odb* target_odb; // the odb where the fetch objects will end up into +}; + +[[nodiscard]] auto fetch_backend_writepack(git_odb_writepack** _writepack, + git_odb_backend* _backend, + [[maybe_unused]] git_odb* odb, + git_indexer_progress_cb progress_cb, + void* progress_payload) -> int { + if (_backend != nullptr) { + auto* b = reinterpret_cast<FetchIntoODBBackend*>(_backend); // NOLINT + return git_odb_write_pack( + _writepack, b->target_odb, progress_cb, progress_payload); + } + return GIT_ERROR; +} + +[[nodiscard]] auto fetch_backend_exists(git_odb_backend* _backend, + const git_oid* oid) -> int { + if (_backend != nullptr) { + auto* b = reinterpret_cast<FetchIntoODBBackend*>(_backend); // NOLINT + return git_odb_exists(b->target_odb, oid); + } + return GIT_ERROR; +} + +void fetch_backend_free(git_odb_backend* /*_backend*/) {} + +[[nodiscard]] auto CreateFetchIntoODBParent() -> git_odb_backend { + git_odb_backend b{}; + b.version = GIT_ODB_BACKEND_VERSION; + // only populate the functions needed + b.writepack = &fetch_backend_writepack; // needed for fetch + b.exists = &fetch_backend_exists; + b.free = &fetch_backend_free; + return b; +} + +// A backend that can be used to fetch from the remote of another repository. +auto const kFetchIntoODBParent = CreateFetchIntoODBParent(); + +// callback to enable SSL certificate check for remote fetch +const auto certificate_check_cb = [](git_cert* /*cert*/, + int /*valid*/, + const char* /*host*/, + void* /*payload*/) -> int { return 1; }; + +// callback to remote fetch without an SSL certificate check +const auto certificate_passthrough_cb = [](git_cert* /*cert*/, + int /*valid*/, + const char* /*host*/, + void* /*payload*/) -> int { + return 0; +}; + +/// \brief Set a custom SSL certificate check callback to honor the existing Git +/// configuration of a repository trying to connect to a remote. +[[nodiscard]] auto SetCustomSSLCertificateCheckCallback(git_repository* repo) + -> git_transport_certificate_check_cb { + // check SSL verification settings, from most to least specific + std::optional<int> check_cert{std::nullopt}; + // check gitconfig; ignore errors + git_config* cfg{nullptr}; + int tmp{}; + if (git_repository_config(&cfg, repo) == 0 and + git_config_get_bool(&tmp, cfg, "http.sslVerify") == 0) { + check_cert = tmp; + } + if (not check_cert) { + // check for GIT_SSL_NO_VERIFY environment variable + const char* ssl_no_verify_var{std::getenv("GIT_SSL_NO_VERIFY")}; + if (ssl_no_verify_var != nullptr and + git_config_parse_bool(&tmp, ssl_no_verify_var) == 0) { + check_cert = tmp; + } + } + // cleanup memory + git_config_free(cfg); + // set callback + return (check_cert and check_cert.value() == 0) ? certificate_passthrough_cb + : certificate_check_cb; +} + +} // namespace + +auto GitRepoRemote::Open(GitCASPtr git_cas) noexcept + -> std::optional<GitRepoRemote> { + auto repo = GitRepoRemote(std::move(git_cas)); + if (not repo.GetRepoRef()) { + return std::nullopt; + } + return repo; +} + +auto GitRepoRemote::Open(std::filesystem::path const& repo_path) noexcept + -> std::optional<GitRepoRemote> { + auto repo = GitRepoRemote(repo_path); + if (not repo.GetRepoRef()) { + return std::nullopt; + } + return repo; +} + +GitRepoRemote::GitRepoRemote(GitCASPtr git_cas) noexcept + : GitRepo(std::move(git_cas)) {} + +GitRepoRemote::GitRepoRemote(std::filesystem::path const& repo_path) noexcept + : GitRepo(repo_path) {} + +GitRepoRemote::GitRepoRemote(GitRepo&& other) noexcept + : GitRepo(std::move(other)) {} + +GitRepoRemote::GitRepoRemote(GitRepoRemote&& other) noexcept + : GitRepo(std::move(other)) {} + +auto GitRepoRemote::operator=(GitRepoRemote&& other) noexcept + -> GitRepoRemote& { + GitRepo::operator=(std::move(other)); + return *this; +} + +auto GitRepoRemote::InitAndOpen(std::filesystem::path const& repo_path, + bool is_bare) noexcept + -> std::optional<GitRepoRemote> { + auto res = GitRepo::InitAndOpen(repo_path, is_bare); + if (res) { + return GitRepoRemote(std::move(*res)); + } + return std::nullopt; +} + +auto GitRepoRemote::GetCommitFromRemote(std::string const& repo_url, + std::string const& branch, + anon_logger_ptr const& logger) noexcept + -> std::optional<std::string> { + try { + // only possible for real repository! + if (IsRepoFake()) { + (*logger)("cannot update commit using a fake repository!", + true /*fatal*/); + return std::nullopt; + } + // create remote + git_remote* remote_ptr{nullptr}; + if (git_remote_create_anonymous( + &remote_ptr, GetRepoRef().get(), repo_url.c_str()) != 0) { + (*logger)( + fmt::format("creating anonymous remote for git repository {} " + "failed with:\n{}", + GetGitPath().string(), + GitLastError()), + true /*fatal*/); + git_remote_free(remote_ptr); + return std::nullopt; + } + auto remote = std::unique_ptr<git_remote, decltype(&remote_closer)>( + remote_ptr, remote_closer); + + // connect to remote + git_remote_callbacks callbacks{}; + git_remote_init_callbacks(&callbacks, GIT_REMOTE_CALLBACKS_VERSION); + + // set custom SSL verification callback + callbacks.certificate_check = + SetCustomSSLCertificateCheckCallback(GetRepoRef().get()); + + git_proxy_options proxy_opts{}; + git_proxy_options_init(&proxy_opts, GIT_PROXY_OPTIONS_VERSION); + + // set the option to auto-detect proxy settings + proxy_opts.type = GIT_PROXY_AUTO; + + if (git_remote_connect(remote.get(), + GIT_DIRECTION_FETCH, + &callbacks, + &proxy_opts, + nullptr) != 0) { + (*logger)( + fmt::format("connecting to remote {} for git repository {} " + "failed with:\n{}", + repo_url, + GetGitPath().string(), + GitLastError()), + true /*fatal*/); + return std::nullopt; + } + // get the list of refs from remote + // NOTE: refs will be owned by remote, so we DON'T have to free it! + git_remote_head const** refs = nullptr; + size_t refs_len = 0; + if (git_remote_ls(&refs, &refs_len, remote.get()) != 0) { + (*logger)( + fmt::format("refs retrieval from remote {} failed with:\n{}", + repo_url, + GitLastError()), + true /*fatal*/); + return std::nullopt; + } + // figure out what remote branch the local one is tracking + for (size_t i = 0; i < refs_len; ++i) { + // by treating each read reference string as a path we can easily + // check for the branch name + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + std::filesystem::path ref_name_as_path{refs[i]->name}; + if (ref_name_as_path.filename() == branch) { + // branch found! + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + std::string new_commit_hash{git_oid_tostr_s(&refs[i]->oid)}; + return new_commit_hash; + } + } + (*logger)(fmt::format("could not find branch {} for remote {}", + branch, + repo_url, + GitLastError()), + true /*fatal*/); + return std::nullopt; + } catch (std::exception const& ex) { + Logger::Log(LogLevel::Error, + "get commit from remote failed with:\n{}", + ex.what()); + return std::nullopt; + } +} + +auto GitRepoRemote::FetchFromRemote(std::string const& repo_url, + std::optional<std::string> const& branch, + anon_logger_ptr const& logger) noexcept + -> bool { + try { + // only possible for real repository! + if (IsRepoFake()) { + (*logger)("cannot fetch commit using a fake repository!", + true /*fatal*/); + return false; + } + // create remote from repo + git_remote* remote_ptr{nullptr}; + if (git_remote_create_anonymous( + &remote_ptr, GetRepoRef().get(), repo_url.c_str()) != 0) { + (*logger)(fmt::format("creating remote {} for git repository {} " + "failed with:\n{}", + repo_url, + GetGitPath().string(), + GitLastError()), + true /*fatal*/); + // cleanup resources + git_remote_free(remote_ptr); + return false; + } + // wrap remote object + auto remote = std::unique_ptr<git_remote, decltype(&remote_closer)>( + remote_ptr, remote_closer); + + // define default fetch options + git_fetch_options fetch_opts{}; + git_fetch_options_init(&fetch_opts, GIT_FETCH_OPTIONS_VERSION); + + // set the option to auto-detect proxy settings + fetch_opts.proxy_opts.type = GIT_PROXY_AUTO; + + // set custom SSL verification callback + fetch_opts.callbacks.certificate_check = + SetCustomSSLCertificateCheckCallback(GetRepoRef().get()); + + // disable update of the FETCH_HEAD pointer + fetch_opts.update_fetchhead = 0; + + // setup fetch refspecs array + git_strarray refspecs_array_obj{}; + if (branch) { + // make sure we check for tags as well + std::string tag = fmt::format("+refs/tags/{}", *branch); + std::string head = fmt::format("+refs/heads/{}", *branch); + PopulateStrarray(&refspecs_array_obj, {tag, head}); + } + auto refspecs_array = + std::unique_ptr<git_strarray, decltype(&strarray_deleter)>( + &refspecs_array_obj, strarray_deleter); + + if (git_remote_fetch( + remote.get(), refspecs_array.get(), &fetch_opts, nullptr) != + 0) { + (*logger)( + fmt::format("fetching{} in git repository {} failed " + "with:\n{}", + branch ? fmt::format(" branch {}", *branch) : "", + GetGitPath().string(), + GitLastError()), + true /*fatal*/); + return false; + } + return true; // success! + } catch (std::exception const& ex) { + Logger::Log( + LogLevel::Error, "fetch from remote failed with:\n{}", ex.what()); + return false; + } +} + +auto GitRepoRemote::UpdateCommitViaTmpRepo( + std::filesystem::path const& tmp_repo_path, + std::string const& repo_url, + std::string const& branch, + anon_logger_ptr const& logger) const noexcept + -> std::optional<std::string> { + try { + // preferably with a "fake" repository! + if (not IsRepoFake()) { + (*logger)("WARNING: commit update called on a real repository!\n", + false /*fatal*/); + } + // create the temporary real repository + auto tmp_repo = + GitRepoRemote::InitAndOpen(tmp_repo_path, /*is_bare=*/true); + if (tmp_repo == std::nullopt) { + return std::nullopt; + } + // setup wrapped logger + auto wrapped_logger = std::make_shared<anon_logger_t>( + [logger](auto const& msg, bool fatal) { + (*logger)( + fmt::format("While doing commit update via tmp repo:\n{}", + msg), + fatal); + }); + return tmp_repo->GetCommitFromRemote(repo_url, branch, wrapped_logger); + } catch (std::exception const& ex) { + Logger::Log(LogLevel::Error, + "update commit via tmp repo failed with:\n{}", + ex.what()); + return std::nullopt; + } +} + +auto GitRepoRemote::FetchViaTmpRepo(std::filesystem::path const& tmp_repo_path, + std::string const& repo_url, + std::optional<std::string> const& branch, + anon_logger_ptr const& logger) noexcept + -> bool { + try { + // preferably with a "fake" repository! + if (not IsRepoFake()) { + (*logger)("WARNING: branch fetch called on a real repository!\n", + false /*fatal*/); + } + // create the temporary real repository + // it can be bare, as the refspecs for this fetch will be given + // explicitly. + auto tmp_repo = + GitRepoRemote::InitAndOpen(tmp_repo_path, /*is_bare=*/true); + if (tmp_repo == std::nullopt) { + return false; + } + // add backend, with max priority + FetchIntoODBBackend b{kFetchIntoODBParent, GetGitOdb().get()}; + if (git_odb_add_backend( + tmp_repo->GetGitOdb().get(), + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + reinterpret_cast<git_odb_backend*>(&b), + std::numeric_limits<int>::max()) == 0) { + // setup wrapped logger + auto wrapped_logger = std::make_shared<anon_logger_t>( + [logger](auto const& msg, bool fatal) { + (*logger)( + fmt::format( + "While doing branch fetch via tmp repo:\n{}", msg), + fatal); + }); + return tmp_repo->FetchFromRemote(repo_url, branch, wrapped_logger); + } + return false; + } catch (std::exception const& ex) { + Logger::Log( + LogLevel::Error, "fetch via tmp repo failed with:\n{}", ex.what()); + return false; + } +} diff --git a/src/other_tools/git_operations/git_repo_remote.hpp b/src/other_tools/git_operations/git_repo_remote.hpp new file mode 100644 index 00000000..83099994 --- /dev/null +++ b/src/other_tools/git_operations/git_repo_remote.hpp @@ -0,0 +1,105 @@ +// Copyright 2023 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_OTHER_TOOLS_GIT_OPERATIONS_GIT_REPO_REMOTE_HPP +#define INCLUDED_SRC_OTHER_TOOLS_GIT_OPERATIONS_GIT_REPO_REMOTE_HPP + +#include "src/buildtool/file_system/git_repo.hpp" + +/// \brief Extension to a Git repository, allowing remote Git operations. +class GitRepoRemote : public GitRepo { + public: + GitRepoRemote() = delete; // no default ctor + ~GitRepoRemote() noexcept = default; + + // allow only move, no copy + GitRepoRemote(GitRepoRemote const&) = delete; + GitRepoRemote(GitRepoRemote&&) noexcept; + auto operator=(GitRepoRemote const&) = delete; + auto operator=(GitRepoRemote&& other) noexcept -> GitRepoRemote&; + + /// \brief Factory to wrap existing open CAS in a "fake" repository. + [[nodiscard]] static auto Open(GitCASPtr git_cas) noexcept + -> std::optional<GitRepoRemote>; + + /// \brief Factory to open existing real repository at given location. + [[nodiscard]] static auto Open( + std::filesystem::path const& repo_path) noexcept + -> std::optional<GitRepoRemote>; + + /// \brief Factory to initialize and open new real repository at location. + /// Returns nullopt if repository init fails even after repeated tries. + [[nodiscard]] static auto InitAndOpen( + std::filesystem::path const& repo_path, + bool is_bare) noexcept -> std::optional<GitRepoRemote>; + + /// \brief Retrieve commit hash from remote branch given its name. + /// Only possible with real repository and thus non-thread-safe. + /// Returns the retrieved commit hash, or nullopt if failure. + /// It guarantees the logger is called exactly once with fatal if failure. + [[nodiscard]] auto GetCommitFromRemote( + std::string const& repo_url, + std::string const& branch, + anon_logger_ptr const& logger) noexcept -> std::optional<std::string>; + + /// \brief Fetch from given remote. It can either fetch a given named + /// branch, or it can fetch with base refspecs. + /// Only possible with real repository and thus non-thread-safe. + /// Returns a success flag. + /// It guarantees the logger is called exactly once with fatal if failure. + [[nodiscard]] auto FetchFromRemote(std::string const& repo_url, + std::optional<std::string> const& branch, + anon_logger_ptr const& logger) noexcept + -> bool; + + /// \brief Get commit from remote via a temporary repository. + /// Calling it from a fake repository allows thread-safe use. + /// Creates a temporary real repository at the given location and uses it to + /// retrieve from the remote the commit of a branch given its name. + /// Caller needs to make sure the temporary directory exists and that the + /// given path is thread- and process-safe! + /// Returns the commit hash, as a string, or nullopt if failure. + /// It guarantees the logger is called exactly once with fatal if failure. + [[nodiscard]] auto UpdateCommitViaTmpRepo( + std::filesystem::path const& tmp_repo_path, + std::string const& repo_url, + std::string const& branch, + anon_logger_ptr const& logger) const noexcept + -> std::optional<std::string>; + + /// \brief Fetch from a remote via a temporary repository. + /// Calling it from a fake repository allows thread-safe use. + /// Creates a temporary real repository at the given location and uses a + /// custom backend to redirect the fetched objects into the desired odb. + /// Caller needs to make sure the temporary directory exists and that the + /// given path is thread- and process-safe! + /// Uses either a given branch, or fetches using base refspecs. + /// Returns a success flag. + /// It guarantees the logger is called exactly once with fatal if failure. + [[nodiscard]] auto FetchViaTmpRepo( + std::filesystem::path const& tmp_repo_path, + std::string const& repo_url, + std::optional<std::string> const& branch, + anon_logger_ptr const& logger) noexcept -> bool; + + private: + /// \brief Open "fake" repository wrapper for existing CAS. + explicit GitRepoRemote(GitCASPtr git_cas) noexcept; + /// \brief Open real repository at given location. + explicit GitRepoRemote(std::filesystem::path const& repo_path) noexcept; + /// \brief Construct from inherited class. + explicit GitRepoRemote(GitRepo&&) noexcept; +}; + +#endif // INCLUDED_SRC_OTHER_TOOLS_GIT_OPERATIONS_GIT_REPO_REMOTE_HPP diff --git a/src/other_tools/just_mr/main.cpp b/src/other_tools/just_mr/main.cpp index 08f82f32..62704426 100644 --- a/src/other_tools/just_mr/main.cpp +++ b/src/other_tools/just_mr/main.cpp @@ -839,7 +839,8 @@ void DefaultReachableRepositories( return kExitUpdateError; } // Init and open git repo - auto git_repo = GitRepo::InitAndOpen(tmp_dir->GetPath(), /*is_bare=*/true); + auto git_repo = + GitRepoRemote::InitAndOpen(tmp_dir->GetPath(), /*is_bare=*/true); if (not git_repo) { Logger::Log(LogLevel::Error, "Failed to initialize repository in tmp dir {} for git " diff --git a/src/other_tools/ops_maps/TARGETS b/src/other_tools/ops_maps/TARGETS index bedf8cba..5c99658a 100644 --- a/src/other_tools/ops_maps/TARGETS +++ b/src/other_tools/ops_maps/TARGETS @@ -17,7 +17,7 @@ , "srcs": ["import_to_git_map.cpp"] , "deps": [ "critical_git_op_map" - , ["src/buildtool/file_system", "git_repo"] + , ["src/other_tools/git_operations", "git_repo_remote"] , ["@", "fmt", "", "fmt"] , ["src/utils/cpp", "path"] ] @@ -34,7 +34,7 @@ , "hdrs": ["git_update_map.hpp"] , "srcs": ["git_update_map.cpp"] , "deps": - [ ["src/buildtool/file_system", "git_repo"] + [ ["src/other_tools/git_operations", "git_repo_remote"] , ["src/buildtool/multithreading", "async_map_consumer"] , ["src/utils/cpp", "hash_combine"] , ["@", "fmt", "", "fmt"] diff --git a/src/other_tools/ops_maps/git_update_map.cpp b/src/other_tools/ops_maps/git_update_map.cpp index f2f6c3e5..c68d6f94 100644 --- a/src/other_tools/ops_maps/git_update_map.cpp +++ b/src/other_tools/ops_maps/git_update_map.cpp @@ -27,7 +27,7 @@ auto CreateGitUpdateMap(GitCASPtr const& git_cas, std::size_t jobs) auto /* unused */, auto const& key) { // perform git update commit - auto git_repo = GitRepo::Open(git_cas); // wrap the tmp odb + auto git_repo = GitRepoRemote::Open(git_cas); // wrap the tmp odb if (not git_repo) { (*logger)( fmt::format("Failed to open tmp Git repository for remote {}", diff --git a/src/other_tools/ops_maps/git_update_map.hpp b/src/other_tools/ops_maps/git_update_map.hpp index a69057bf..d4804545 100644 --- a/src/other_tools/ops_maps/git_update_map.hpp +++ b/src/other_tools/ops_maps/git_update_map.hpp @@ -15,8 +15,8 @@ #ifndef INCLUDED_SRC_OTHER_TOOLS_OPS_MAPS_GIT_UPDATE_MAP_HPP #define INCLUDED_SRC_OTHER_TOOLS_OPS_MAPS_GIT_UPDATE_MAP_HPP -#include "src/buildtool/file_system/git_repo.hpp" #include "src/buildtool/multithreading/async_map_consumer.hpp" +#include "src/other_tools/git_operations/git_repo_remote.hpp" #include "src/utils/cpp/hash_combine.hpp" using StringPair = std::pair<std::string, std::string>; diff --git a/src/other_tools/ops_maps/import_to_git_map.cpp b/src/other_tools/ops_maps/import_to_git_map.cpp index 137a719b..aa3faa2e 100644 --- a/src/other_tools/ops_maps/import_to_git_map.cpp +++ b/src/other_tools/ops_maps/import_to_git_map.cpp @@ -81,7 +81,8 @@ auto CreateImportToGitMap( return; } // fetch all into Git cache - auto just_git_repo = GitRepo::Open(op_result.git_cas); + auto just_git_repo = + GitRepoRemote::Open(op_result.git_cas); if (not just_git_repo) { (*logger)(fmt::format("Could not open Git " "repository {}", @@ -188,7 +189,7 @@ void KeepCommitAndSetTree( /*fatal=*/true); return; } - auto git_repo = GitRepo::Open(git_cas); + auto git_repo = GitRepoRemote::Open(git_cas); if (not git_repo) { (*logger)(fmt::format("Could not open Git repository {}", target_path.string()), diff --git a/src/other_tools/ops_maps/import_to_git_map.hpp b/src/other_tools/ops_maps/import_to_git_map.hpp index 32b7b638..5a949189 100644 --- a/src/other_tools/ops_maps/import_to_git_map.hpp +++ b/src/other_tools/ops_maps/import_to_git_map.hpp @@ -18,7 +18,7 @@ #include <filesystem> #include <string> -#include "src/buildtool/file_system/git_repo.hpp" +#include "src/other_tools/git_operations/git_repo_remote.hpp" #include "src/other_tools/ops_maps/critical_git_op_map.hpp" #include "src/utils/cpp/path.hpp" diff --git a/src/other_tools/root_maps/TARGETS b/src/other_tools/root_maps/TARGETS index 0d5c18f9..d609b7d3 100644 --- a/src/other_tools/root_maps/TARGETS +++ b/src/other_tools/root_maps/TARGETS @@ -32,7 +32,9 @@ ] , "stage": ["src", "other_tools", "root_maps"] , "private-deps": - [["src/buildtool/file_system", "git_repo"], ["src/utils/cpp", "tmp_dir"]] + [ ["src/other_tools/git_operations", "git_repo_remote"] + , ["src/utils/cpp", "tmp_dir"] + ] } , "fpath_git_map": { "type": ["@", "rules", "CC", "library"] diff --git a/src/other_tools/root_maps/commit_git_map.cpp b/src/other_tools/root_maps/commit_git_map.cpp index 86ab3447..5d34182b 100644 --- a/src/other_tools/root_maps/commit_git_map.cpp +++ b/src/other_tools/root_maps/commit_git_map.cpp @@ -16,7 +16,7 @@ #include <algorithm> -#include "src/buildtool/file_system/git_repo.hpp" +#include "src/other_tools/git_operations/git_repo_remote.hpp" #include "src/utils/cpp/tmp_dir.hpp" namespace { @@ -111,7 +111,7 @@ void EnsureCommit(GitRepoInfo const& repo_info, CommitGitMap::SetterPtr const& ws_setter, CommitGitMap::LoggerPtr const& logger) { // ensure commit exists, and fetch if needed - auto git_repo = GitRepo::Open(git_cas); // link fake repo to odb + auto git_repo = GitRepoRemote::Open(git_cas); // link fake repo to odb if (not git_repo) { (*logger)( fmt::format("Could not open repository {}", repo_root.string()), @@ -193,7 +193,7 @@ void EnsureCommit(GitRepoInfo const& repo_info, } // ensure commit exists, and fetch if needed auto git_repo = - GitRepo::Open(git_cas); // link fake repo to odb + GitRepoRemote::Open(git_cas); // link fake repo to odb if (not git_repo) { (*logger)(fmt::format("Could not open repository {}", repo_root.string()), diff --git a/src/other_tools/root_maps/content_git_map.cpp b/src/other_tools/root_maps/content_git_map.cpp index 9d1130e5..11adf136 100644 --- a/src/other_tools/root_maps/content_git_map.cpp +++ b/src/other_tools/root_maps/content_git_map.cpp @@ -89,7 +89,7 @@ auto CreateContentGitMap( return; } // open fake repo wrap for GitCAS - auto just_git_repo = GitRepo::Open(op_result.git_cas); + auto just_git_repo = GitRepoRemote::Open(op_result.git_cas); if (not just_git_repo) { (*logger)("Could not open Git cache repository!", /*fatal=*/true); @@ -205,7 +205,8 @@ auto CreateContentGitMap( return; } // fetch all into Git cache - auto just_git_repo = GitRepo::Open(just_git_cas); + auto just_git_repo = + GitRepoRemote::Open(just_git_cas); if (not just_git_repo) { (*logger)( "Could not open Git cache repository!", diff --git a/src/other_tools/root_maps/fpath_git_map.cpp b/src/other_tools/root_maps/fpath_git_map.cpp index 17605ddc..70aff153 100644 --- a/src/other_tools/root_maps/fpath_git_map.cpp +++ b/src/other_tools/root_maps/fpath_git_map.cpp @@ -37,7 +37,7 @@ auto CreateFilePathGitMap( fatal); }); // check if path is a part of a git repo - auto repo_root = GitRepo::GetRepoRootFromPath( + auto repo_root = GitRepoRemote::GetRepoRootFromPath( key, wrapped_logger); // static function if (not repo_root) { return; @@ -51,7 +51,8 @@ auto CreateFilePathGitMap( /*fatal=*/true); return; } - auto git_repo = GitRepo::Open(git_cas); // link fake repo to odb + auto git_repo = + GitRepoRemote::Open(git_cas); // link fake repo to odb if (not git_repo) { (*logger)(fmt::format("Could not open repository {}", repo_root->string()), @@ -81,7 +82,7 @@ auto CreateFilePathGitMap( return; } auto git_repo = - GitRepo::Open(git_cas); // link fake repo to odb + GitRepoRemote::Open(git_cas); // link fake repo to odb if (not git_repo) { (*logger)(fmt::format("Could not open repository {}", repo_root.string()), |