summaryrefslogtreecommitdiff
path: root/src/other_tools/git_operations/git_repo_remote.hpp
blob: 614e78224d06e406b45fd97ef370bfe1403a047f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// 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 <filesystem>
#include <memory>
#include <optional>
#include <string>
#include <vector>

#include "src/buildtool/file_system/git_repo.hpp"

extern "C" {
struct git_config;
}

/// \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.
    /// If non-null, use given config snapshot to interact with config entries;
    /// otherwise, use a snapshot from the current repo and share pointer to it.
    /// 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::shared_ptr<git_config> cfg,
        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.
    /// If non-null, use given config snapshot to interact with config entries;
    /// otherwise, use a snapshot from the current repo and share pointer to it.
    /// Returns a success flag. It guarantees the logger is called
    /// exactly once with fatal if failure.
    [[nodiscard]] auto FetchFromRemote(std::shared_ptr<git_config> cfg,
                                       std::string const& repo_url,
                                       std::optional<std::string> const& branch,
                                       anon_logger_ptr const& logger) noexcept
        -> bool;

    /// \brief Get commit from given branch on the remote. If URL is SSH, shells
    /// out to system git to perform an ls-remote call, ensuring correct
    /// handling of the remote connection settings (in particular proxy and
    /// SSH). A temporary directory is needed to pipe the stdout and stderr to.
    /// If URL is non-SSH, uses tmp dir to connect to remote and retrieve the
    /// commit of a branch asynchronously using libgit2.
    /// 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_dir,
        std::string const& repo_url,
        std::string const& branch,
        std::vector<std::string> const& inherit_env,
        std::string const& git_bin,
        std::vector<std::string> const& launcher,
        anon_logger_ptr const& logger) const noexcept
        -> std::optional<std::string>;

    /// \brief Fetch from a remote. If URL is SSH, shells out to system git to
    /// retrieve packs in a safe manner, with the only side-effect being that
    /// there can be some redundancy in the fetched packs. The tmp dir is used
    /// to pipe the stdout and stderr to.
    /// If URL is non-SSH, uses tmp dir to fetch asynchronously using libgit2.
    /// 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 all (with 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_dir,
        std::string const& repo_url,
        std::optional<std::string> const& branch,
        std::vector<std::string> const& inherit_env,
        std::string const& git_bin,
        std::vector<std::string> const& launcher,
        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