Skip to content

Commit 10c4972

Browse files
committed
Clone a branch is tested.
1 parent 8e5dd65 commit 10c4972

File tree

5 files changed

+118
-16
lines changed

5 files changed

+118
-16
lines changed

src/utility/git.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ void git_references::sort() noexcept
3535
return it;
3636
}
3737

38-
if (auto const it = find_ref(std::format("ref/tags/{}", name)); it != end()) {
38+
if (auto const it = find_ref(std::format("refs/tags/{}", name)); it != end()) {
3939
return it;
4040
}
4141

@@ -158,17 +158,18 @@ class git_lib {
158158
if (auto const r = ::git_remote_create_anonymous(&remote, nullptr, url.c_str()); r != GIT_OK) {
159159
return std::unexpected{make_git_error(r)};
160160
}
161+
auto const d1 = defer{[&] {
162+
::git_remote_free(remote);
163+
}};
161164

162165
if (auto const r = ::git_remote_connect(remote, GIT_DIRECTION_FETCH, nullptr, nullptr, nullptr); r != GIT_OK) {
163-
::git_remote_free(remote);
164166
return std::unexpected{make_git_error(r)};
165167
}
166168

167169
::git_remote_head const** list_head = nullptr;
168170
size_t list_size = 0;
169171

170172
if (auto const r = ::git_remote_ls(&list_head, &list_size, remote); r != GIT_OK) {
171-
::git_remote_free(remote);
172173
return std::unexpected{make_git_error(r)};
173174
}
174175

@@ -187,7 +188,6 @@ class git_lib {
187188
r.emplace_back(std::move(name), std::move(oid_str));
188189
}
189190

190-
::git_remote_free(remote);
191191
r.sort();
192192
return r;
193193
}
@@ -315,7 +315,7 @@ repository_fetch(::git_repository* repository, std::string const& remote_name =
315315
if (auto result = ::git_remote_lookup(&remote, repository, remote_name.c_str()); result != GIT_OK) {
316316
return make_git_error(result);
317317
}
318-
defer{[&] {
318+
auto const d1 = defer{[&] {
319319
::git_remote_free(remote);
320320
}};
321321

@@ -532,7 +532,7 @@ git_fetch_and_update(std::string const& url, std::string const& rev, std::filesy
532532
return git_error::ok;
533533
}
534534

535-
[[nodiscard]] git_error git_clone(std::string const& url, std::string const& branch, std::filesystem::path path)
535+
[[nodiscard]] git_error git_clone(std::string const& url, std::string const& git_rev, std::filesystem::path path)
536536
{
537537
auto const& _ = git_lib_initialize();
538538

@@ -550,10 +550,10 @@ git_fetch_and_update(std::string const& url, std::string const& rev, std::filesy
550550
return make_git_error(r);
551551
}
552552

553-
auto branch_it = ref_list.find(branch);
553+
auto branch_it = ref_list.find(git_rev);
554554
if (branch_it != ref_list.end()) {
555555
if (branch_it->is_branch()) {
556-
options.checkout_branch = branch.c_str();
556+
options.checkout_branch = git_rev.c_str();
557557
options.fetch_opts.depth = 1;
558558
force_checkout = true;
559559

@@ -572,6 +572,9 @@ git_fetch_and_update(std::string const& url, std::string const& rev, std::filesy
572572
if (auto r = ::git_clone(&repository, url.c_str(), path.string().c_str(), &options); r != GIT_OK) {
573573
return make_git_error(r);
574574
}
575+
auto d1 = defer{[&] { ::git_repository_free(repository); }};
576+
577+
return git_error::ok;
575578
}
576579

577580
//[[nodiscard]] git_error git_checkout_or_clone(

src/utility/git.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,15 @@ class git_references : public std::vector<git_reference> {
143143
*/
144144
[[nodiscard]] std::expected<git_references, git_error> git_list(std::string const& url);
145145

146-
[[nodiscard]] git_error git_clone(std::string const& url, std::string const& branch, std::filesystem::path path);
146+
/** Clone a repository.
147+
*
148+
* @param url The (remote) location of the repository
149+
* @param git_rev The branch to checkout.
150+
* If git_rev is a branch the checkout is done with depth 1.
151+
* If git_rev is a tag then the default branch is checked with
152+
* full depth.
153+
*/
154+
[[nodiscard]] git_error git_clone(std::string const& url, std::string const& git_rev, std::filesystem::path path);
147155

148156
/** This function will open the repository and update to the latest version.
149157
*

src/utility/git_tests.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11

22
#include "git.hpp"
3+
#include "path.hpp"
34
#include <hikotest/hikotest.hpp>
45

56
TEST_SUITE(git_suite)
67
{
78
TEST_CASE(git_list) {
8-
auto optional_list = hk::git_list("https://github.com/hikogui/hikogui.git");
9+
auto optional_list = hk::git_list("https://github.com/hikogui/hikolang-test-a.git");
910
REQUIRE(static_cast<bool>(optional_list));
1011
auto list = std::move(optional_list).value();
1112
REQUIRE(not list.empty());
1213
auto it = list.find("main");
1314
REQUIRE(it != list.end());
15+
it = list.find("v1.0.0");
16+
REQUIRE(it != list.end());
17+
}
18+
19+
TEST_CASE(git_clone) {
20+
auto const tmp_dir = hk::scoped_temporary_directory("git_clone");
21+
22+
auto const r = hk::git_clone("https://github.com/hikogui/hikolang-test-a.git", "main", tmp_dir.path());
23+
REQUIRE(r == hk::git_error::ok);
1424
}
1525
};

src/utility/path.cpp

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11

22

33
#include "path.hpp"
4+
#include <format>
5+
#include <chrono>
6+
#include <system_error>
7+
#include <print>
48

59
namespace hk {
610

7-
[[nodiscard]] std::expected<std::filesystem::path, std::error_code> absolute_to(
8-
std::filesystem::path const& path, std::filesystem::path const& base)
11+
[[nodiscard]] std::expected<std::filesystem::path, std::error_code>
12+
absolute_to(std::filesystem::path const& path, std::filesystem::path const& base)
913
{
1014
auto ec = std::error_code{};
1115

@@ -36,12 +40,12 @@ namespace hk {
3640
auto ec = std::error_code{};
3741

3842
auto const path_ = std::filesystem::canonical(path, ec);
39-
if (not ec) {
43+
if (ec) {
4044
return false;
4145
}
4246

43-
auto const base_ = std::filesystem::canonical(path, ec);
44-
if (not ec) {
47+
auto const base_ = std::filesystem::canonical(base, ec);
48+
if (ec) {
4549
return false;
4650
}
4751

@@ -60,4 +64,65 @@ namespace hk {
6064
return true;
6165
}
6266

63-
}
67+
scoped_temporary_directory::~scoped_temporary_directory()
68+
{
69+
if (_path.empty()) {
70+
return;
71+
}
72+
73+
auto const base_dir = std::filesystem::temp_directory_path();
74+
75+
if (not is_subpath(_path, base_dir)) {
76+
std::println(
77+
stderr,
78+
"Security error: tried to remove scoped-temporary-directory '{}', while not being a subdirectory of '{}'.",
79+
_path.string(),
80+
base_dir.string());
81+
std::terminate();
82+
}
83+
84+
if (not std::filesystem::exists(_path)) {
85+
return;
86+
}
87+
88+
auto ec = std::error_code{};
89+
if (std::filesystem::remove_all(_path, ec) == static_cast<std::uintmax_t>(-1)) {
90+
std::println(stderr, "Could not remove scoped-temporary-directory '{}': {}", _path.string(), ec.message());
91+
}
92+
}
93+
94+
scoped_temporary_directory::scoped_temporary_directory(std::string prefix)
95+
{
96+
auto const _ = std::unique_lock(_mutex);
97+
98+
if (prefix.empty()) {
99+
prefix = "tmp";
100+
}
101+
102+
auto const base_dir = std::filesystem::temp_directory_path();
103+
auto count = 0uz;
104+
do {
105+
if (count++ > 10) {
106+
throw std::runtime_error("Too many tries to create scoped-temporary-directory");
107+
}
108+
109+
auto const now = std::chrono::system_clock::now();
110+
auto const name = std::format("{0:}-{1:%Y%m%d}-{1:%H%M%S}-{2:}", prefix, now, count);
111+
_path = base_dir / name;
112+
if (std::filesystem::exists(_path)) {
113+
continue;
114+
}
115+
116+
std::error_code ec;
117+
if (not std::filesystem::create_directory(_path, ec)) {
118+
if (ec and ec != std::errc::file_exists) {
119+
throw std::system_error(ec, std::format("Could not create directory: {}", _path.string()));
120+
}
121+
continue;
122+
}
123+
124+
125+
} while (false);
126+
}
127+
128+
} // namespace hk

src/utility/path.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <system_error>
1010
#include <cassert>
1111
#include <expected>
12+
#include <mutex>
1213

1314
namespace hk {
1415

@@ -39,4 +40,19 @@ namespace hk {
3940
*/
4041
[[nodiscard]] bool is_subpath(std::filesystem::path const& path, std::filesystem::path const& base);
4142

43+
class scoped_temporary_directory {
44+
public:
45+
~scoped_temporary_directory();
46+
scoped_temporary_directory(std::string prefix = std::string{"tmp"});
47+
48+
[[nodiscard]] std::filesystem::path const &path() const noexcept
49+
{
50+
return _path;
51+
}
52+
53+
private:
54+
inline static std::mutex _mutex;
55+
std::filesystem::path _path;
56+
};
57+
4258
}

0 commit comments

Comments
 (0)