Skip to content

Commit 3d7fedb

Browse files
committed
defer
1 parent 94621bc commit 3d7fedb

File tree

3 files changed

+132
-5
lines changed

3 files changed

+132
-5
lines changed

src/utility/defer.hpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
3+
#pragma once
4+
5+
#include <concepts>
6+
#include <functional>
7+
8+
namespace hk {
9+
10+
class defer {
11+
public:
12+
~defer()
13+
{
14+
if (_f) {
15+
_f();
16+
}
17+
}
18+
19+
[[nodiscard]] defer(std::function<void()> && arg) : _f(std::move(arg)) {}
20+
[[nodiscard]] defer(std::function<void()> const& arg) : _f(arg) {}
21+
22+
void cancel()
23+
{
24+
_f = nullptr;
25+
}
26+
27+
private:
28+
std::function<void()> _f;
29+
};
30+
31+
32+
}

src/utility/git.cpp

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
#include "git.hpp"
3+
#include "defer.hpp"
34
#include <git2.h>
45
#include <mutex>
56
#include <format>
@@ -159,13 +160,84 @@ class git_lib {
159160
return r;
160161
}
161162

162-
//[[nodiscard]] std::expected<git_oid, git_error> git_hash(std::string const& url, std::string const& branch)
163-
//{
164-
//
165-
//}
163+
/** Check if one of the remote has the correct branch checked out.
164+
*
165+
* @param repository The repository to check all the remotes
166+
* @param branch The branch to compare.
167+
* @retval true The correct branch was checked out.
168+
* @retval false Another branch was checked out.
169+
* @retval error An error during query.
170+
*/
171+
[[nodiscard]] std::expected<bool, git_error> repository_matches_branch(::git_repository *repository, std::string const& branch)
172+
{
173+
174+
}
175+
176+
/** Check if one of the remote has a url that matches the given url.
177+
*
178+
* @param repository The repository to check all the remotes
179+
* @param url The url to compare.
180+
* @retval true The url is a remote of the @a repository.
181+
* @retval false None of the remotes match.
182+
* @retval error An error during query.
183+
*/
184+
[[nodiscard]] std::expected<bool, git_error> repository_matches_url(::git_repository *repository, std::string const& url)
185+
{
186+
assert(repository != nullptr);
187+
188+
auto remote_names = ::git_strarray{};
189+
if (auto const result = ::git_remote_list(&remote_names, repository); result != GIT_OK) {
190+
return std::unexpected{make_git_error(result)};
191+
}
192+
auto const _ = defer{[&]{ ::git_strarray_dispose(&remote_names); }};
193+
194+
for (auto i = 0uz; i != remote_names.count; ++i) {
195+
::git_remote *remote = nullptr;
196+
if (auto const result = ::git_remote_lookup(&remote, repository, remote_names.strings[i]); result != GIT_OK) {
197+
return std::unexpected{make_git_error(result)};
198+
}
199+
auto const _ = defer{[&]{ ::git_remote_free(remote); }};
200+
201+
auto const remote_url = ::git_remote_url(remote);
202+
if (remote_url and url == remote_url) {
203+
return true;
204+
}
205+
}
206+
207+
return false;
208+
}
209+
210+
[[nodiscard]] git_error git_fetch_and_update(std::string const& url, std::string const& branch, std::filesystem::path path, git_checkout_flags flags)
211+
{
212+
auto const& _ = git_lib_initialize();
213+
214+
auto r = git_error::ok;
215+
216+
::git_repository *repository = nullptr;
217+
if (auto const result = ::git_repository_open(&repository, url.c_str()); result != GIT_OK) {
218+
return make_git_error(result);
219+
}
220+
auto const d1 = defer{[&]{ ::git_repository_free(repository); }};
221+
222+
if (auto result = repository_matches_url(repository, url)) {
223+
if (not *result) {
224+
std::print("The repository at {}, does not have a remote with the url {}", path.string(), url);
225+
return git_error::remote_url_mismatch;
226+
}
227+
} else {
228+
return result.error();
229+
}
230+
231+
if (auto result = repository_matches_branch(repository, branch)) {
232+
233+
}
234+
}
166235

167236
[[nodiscard]] git_error git_clone(std::string const& url, std::string const& branch, std::filesystem::path path)
168237
{
238+
auto const& _ = git_lib_initialize();
239+
240+
169241
auto force_checkout = false;
170242

171243
auto ref_list = git_references{};

src/utility/git.hpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ enum class git_error {
5050
unchanged,
5151
not_supported,
5252
read_only,
53+
54+
/** The repository does have a remote that matches the expected URL.
55+
*/
56+
remote_url_mismatch,
5357
};
5458

5559
enum class git_checkout_flags {
@@ -85,6 +89,16 @@ struct git_reference {
8589
{
8690
return lhs.name <=> rhs.name;
8791
}
92+
93+
[[nodiscard]] constexpr bool is_branch() const noexcept
94+
{
95+
return name.starts_with("refs/heads/");
96+
}
97+
98+
[[nodiscard]] constexpr bool is_tag() const noexcept
99+
{
100+
return name.starts_with("ref/tags/");
101+
}
88102
};
89103

90104
class git_references : public std::vector<git_reference> {
@@ -121,7 +135,16 @@ class git_references : public std::vector<git_reference> {
121135

122136
[[nodiscard]] git_error git_clone(std::string const& url, std::string const& branch, std::filesystem::path path);
123137

124-
[[nodiscard]] git_error git_checkout(std::filesystem::path path);
138+
/** This function will open the repository and update to the latest version.
139+
*
140+
* @param url The remote url, used to check if the repository at the path
141+
* has the same remote url.
142+
* @param branch The branch to checkout. If the repository is of a different
143+
* branch this branch is checked out, and the repository is cleaned.
144+
* @param path The path where the repository is located.
145+
* @param flags Flags for the way the repository should be checked out.
146+
*/
147+
[[nodiscard]] git_error git_fetch_and_update(std::string const& url, std::string const& branch, std::filesystem::path path, git_checkout_flags flags);
125148

126149
/** Checkout or clone the repository.
127150
*

0 commit comments

Comments
 (0)