Skip to content

Commit f2915a0

Browse files
committed
recursive scan work
1 parent 28e3b1a commit f2915a0

File tree

10 files changed

+138
-68
lines changed

10 files changed

+138
-68
lines changed

src/ast/module_node.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
namespace hk::ast {
66

7-
[[nodiscard]] generator<repository_url> module_node::remote_repositories() const
7+
[[nodiscard]] generator<module_node::remote_repository_result> module_node::remote_repositories() const
88
{
99
for (auto const& import : imports) {
1010
if (auto repository_import_ptr = dynamic_cast<import_repository_declaration_node const*>(import.get())) {
11-
co_yield repository_import_ptr->url;
11+
co_yield remote_repository_result{repository_import_ptr->url, fxxxxxxxst, this};
1212
}
1313
}
1414
}

src/ast/module_node.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,13 @@ class module_node : public node {
4949
std::vector<import_declaration_node_ptr> imports;
5050
std::vector<node_ptr> body;
5151

52-
[[nodiscard]] generator<repository_url> remote_repositories() const;
52+
struct remote_repository_result {
53+
repository_url url;
54+
file_location first;
55+
file_location last;
56+
module_node *node;
57+
};
58+
[[nodiscard]] generator<remote_repository_result> remote_repositories() const;
5359

5460
};
5561

src/error/error_item.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ class error_item {
3333
assert(_code.has_value());
3434
}
3535

36+
template<typename... Args>
37+
error_item(error_code code, std::format_string<Args...> fmt, Args&&... args)
38+
: _first(), _last(), _code(code), _message(std::format(std::move(fmt), std::forward<Args>(args)...))
39+
{
40+
assert(_code.has_value());
41+
}
42+
3643
template<typename... Args>
3744
void add_cause(file_location first, file_location last, std::format_string<Args...> fmt, Args&&... args)
3845
{

src/error/error_list.hpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@ class error_list : public std::vector<error_item> {
1616

1717
/** Add an error to the list.
1818
*
19+
* @tparam ErrorCode The error being raised, including the format string.
1920
* @param first The first file location where the error occurred.
2021
* @param last The last file location where the error occurred.
21-
* @param code The error code.
22-
* @param fmt The format string for the error message.
2322
* @param args The arguments to format the error message.
2423
* @return A unexpected error containing the error code.
2524
*/
@@ -31,6 +30,20 @@ class error_list : public std::vector<error_item> {
3130
return std::unexpected{ErrorType::code};
3231
}
3332

33+
/** Add an error to the list.
34+
*
35+
* @tparam ErrorCode The error being raised, including the format string.
36+
* @param args The arguments to format the error message.
37+
* @return A unexpected error containing the error code.
38+
*/
39+
template<typename ErrorType, typename... Args>
40+
std::unexpected<error_code> add(Args&&... args)
41+
{
42+
auto e = error_item{ErrorType::code, ErrorType::fmt, std::forward<Args>(args)...};
43+
this->push_back(std::move(e));
44+
return std::unexpected{ErrorType::code};
45+
}
46+
3447
private:
3548
};
3649

src/repository/repository.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "utility/path.hpp"
44
#include "utility/vector_set.hpp"
55
#include "utility/file_cursor.hpp"
6+
#include "utility/git.hpp"
67
#include "parser/parse_module.hpp"
78
#include <cassert>
89
#include <algorithm>
@@ -14,7 +15,7 @@ repository::repository(std::filesystem::path path) : _path(std::move(path))
1415
assert(std::filesystem::canonical(_path) == _path);
1516
}
1617

17-
void repository::scan_prologues(bool force)
18+
void repository::scan_prologues(repository_flags flags)
1819
{
1920
untouch(false);
2021

@@ -53,7 +54,7 @@ void repository::scan_prologues(bool force)
5354
auto& m = get_module(module_path);
5455
m.touched = true;
5556

56-
if (m.ast and m.time == entry.last_write_time() and not force) {
57+
if (m.ast and m.time == entry.last_write_time() and not to_bool(flags & repository_flags::force_scan)) {
5758
// The prologue for this module has already been scanned.
5859
continue;
5960
}
@@ -68,10 +69,37 @@ void repository::scan_prologues(bool force)
6869
untouch(true);
6970
}
7071

71-
void repository::recursive_scan_prologues(bool force)
72+
void repository::recursive_scan_prologues(repository_flags flags)
7273
{
74+
auto todo = std::set<repository_url>{};
75+
auto done = std::set<repository_url>{};
7376

74-
77+
scan_prologues(flags);
78+
for (auto child_repo_url : remote_repositories()) {
79+
todo.insert(std::move(child_repo_url));
80+
}
81+
82+
auto hkdeps = _path / "_hkdeps";
83+
while (not todo.empty()) {
84+
auto child_repo_url_node = todo.extract(todo.begin());
85+
auto [it, inserted, _] = done.insert(std::move(child_repo_url_node));
86+
if (not inserted) {
87+
continue;
88+
}
89+
90+
assert(it != done.end());
91+
auto child_repo_path = hkdeps / it->directory();
92+
auto &child_repo = get_child_repository(*it);
93+
if (not child_repo.repository) {
94+
if (auto r = git_checkout_or_clone(*it, child_repo_path, flags); r != git_error::ok) {
95+
96+
}
97+
98+
child_repo.repository = std::make_unique<repository>(child_repo_path);
99+
}
100+
}
101+
102+
// Remove internal repositories not in done.
75103
}
76104

77105
void repository::untouch(bool remove)

src/repository/repository.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "ast/module_node.hpp"
55
#include "error/error_list.hpp"
66
#include "utility/repository_url.hpp"
7+
#include "utility/repository_flags.hpp"
78
#include "utility/generator.hpp"
89
#include <filesystem>
910
#include <memory>
@@ -20,13 +21,13 @@ class repository {
2021
*
2122
* @param force Force scanning even on files that were already parsed.
2223
*/
23-
void scan_prologues(bool force);
24+
void scan_prologues(repository_flags flags);
2425

2526
/** Recusively clone and scan repositories.
2627
*
2728
* @param force Force scanning even on files that were already parsed.
2829
*/
29-
void recursive_scan_prologues(bool force);
30+
void recursive_scan_prologues(repository_flags flags);
3031

3132
[[nodiscard]] generator<repository_url> remote_repositories() const;
3233

src/utility/git.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ repository_fetch(::git_repository* repository, std::string const& remote_name =
456456
}
457457

458458
[[nodiscard]] git_error
459-
git_fetch_and_update(std::string const& url, std::string const& rev, std::filesystem::path path, git_checkout_flags flags)
459+
git_fetch_and_update(std::string const& url, std::string const& rev, std::filesystem::path path, repository_flags flags)
460460
{
461461
auto const& _ = git_lib_initialize();
462462

@@ -478,17 +478,17 @@ git_fetch_and_update(std::string const& url, std::string const& rev, std::filesy
478478
return remote_url_o.error();
479479
}
480480

481-
auto fetch = to_bool(flags & git_checkout_flags::force_fetch);
481+
auto fetch = to_bool(flags & repository_flags::force_fetch);
482482
if (auto result = repository_matches_rev(repository, rev)) {
483483
switch (*result) {
484484
case rev_match::rev_not_found:
485-
if (to_bool(flags & git_checkout_flags::fresh_clone)) {
485+
if (to_bool(flags & repository_flags::fresh_clone)) {
486486
return git_error::rev_not_found;
487487
}
488488
[[fallthrough]];
489489
case rev_match::not_checked_out:
490490
case rev_match::checked_out_branch:
491-
fetch |= not to_bool(flags & git_checkout_flags::fresh_clone);
491+
fetch |= not to_bool(flags & repository_flags::fresh_clone);
492492
break;
493493
case rev_match::checked_out:
494494
// Revisions that are tags or commits will not cause a fetch.
@@ -522,9 +522,9 @@ git_fetch_and_update(std::string const& url, std::string const& rev, std::filesy
522522
}
523523

524524
auto clean = checkout;
525-
clean |= to_bool(flags & git_checkout_flags::force_clean);
525+
clean |= to_bool(flags & repository_flags::force_clean);
526526
// A fresh clone does not need to be cleaned.
527-
clean &= not to_bool(flags & git_checkout_flags::fresh_clone);
527+
clean &= not to_bool(flags & repository_flags::fresh_clone);
528528

529529
if (clean) {
530530
if (auto result = repository_clean(repository); result != git_error::ok) {
@@ -584,7 +584,7 @@ git_fetch_and_update(std::string const& url, std::string const& rev, std::filesy
584584
}
585585

586586
[[nodiscard]] git_error git_checkout_or_clone(
587-
std::string const& url, std::string const& rev, std::filesystem::path path, git_checkout_flags flags)
587+
std::string const& url, std::string const& rev, std::filesystem::path path, repository_flags flags)
588588
{
589589
// First try and just update the repository.
590590
switch(git_fetch_and_update(url, rev, path, flags)) {
@@ -614,7 +614,7 @@ git_fetch_and_update(std::string const& url, std::string const& rev, std::filesy
614614
}
615615

616616
// In case rev is a tag or commit, checkout/update the repository.
617-
flags |= git_checkout_flags::fresh_clone;
617+
flags |= repository_flags::fresh_clone;
618618
return git_fetch_and_update(url, rev, path, flags);
619619
}
620620

src/utility/git.hpp

Lines changed: 4 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#pragma once
33

44
#include "repository_url.hpp"
5+
#include "repository_flags.hpp"
56
#include <expected>
67
#include <system_error>
78
#include <memory>
@@ -76,49 +77,7 @@ enum class git_error {
7677
could_not_connect_with_remote,
7778
};
7879

79-
enum class git_checkout_flags {
80-
/** The repository was freshly cloned, not need for a fetch.
81-
*/
82-
fresh_clone = 0x1,
83-
84-
/** Fetch, even when the rev points to a tag or commit.
85-
*/
86-
force_fetch = 0x2,
87-
88-
/** Force the repository to be cleaned, even if no checkout is performed.
89-
*/
90-
force_clean = 0x4
91-
};
92-
93-
[[nodiscard]] constexpr git_checkout_flags operator|(git_checkout_flags lhs, git_checkout_flags rhs) noexcept
94-
{
95-
return static_cast<git_checkout_flags>(std::to_underlying(lhs) | std::to_underlying(rhs));
96-
}
97-
98-
[[nodiscard]] constexpr git_checkout_flags operator&(git_checkout_flags lhs, git_checkout_flags rhs) noexcept
99-
{
100-
return static_cast<git_checkout_flags>(std::to_underlying(lhs) & std::to_underlying(rhs));
101-
}
10280

103-
[[nodiscard]] constexpr git_checkout_flags operator~(git_checkout_flags rhs) noexcept
104-
{
105-
return static_cast<git_checkout_flags>(~std::to_underlying(rhs));
106-
}
107-
108-
constexpr git_checkout_flags& operator|=(git_checkout_flags& lhs, git_checkout_flags rhs) noexcept
109-
{
110-
return lhs = lhs | rhs;
111-
}
112-
113-
constexpr git_checkout_flags& operator&=(git_checkout_flags& lhs, git_checkout_flags rhs) noexcept
114-
{
115-
return lhs = lhs & rhs;
116-
}
117-
118-
[[nodiscard]] constexpr bool to_bool(git_checkout_flags rhs) noexcept
119-
{
120-
return static_cast<bool>(std::to_underlying(rhs));
121-
}
12281

12382
struct git_reference {
12483
std::string name = {};
@@ -200,7 +159,7 @@ class git_references : public std::vector<git_reference> {
200159
std::string const& url,
201160
std::string const& rev,
202161
std::filesystem::path path,
203-
git_checkout_flags flags = git_checkout_flags{});
162+
repository_flags flags = repository_flags{});
204163

205164
/** Checkout or clone the repository.
206165
*
@@ -215,14 +174,14 @@ class git_references : public std::vector<git_reference> {
215174
std::string const& url,
216175
std::string const& rev,
217176
std::filesystem::path path,
218-
git_checkout_flags flags = git_checkout_flags{});
177+
repository_flags flags = repository_flags{});
219178

220179
/** Checkout or clone the repository.
221180
*
222181
* @see git_checkout_or_clone
223182
*/
224183
[[nodiscard]] inline git_error
225-
git_checkout_or_clone(repository_url const& url, std::filesystem::path path, git_checkout_flags flags = git_checkout_flags{})
184+
git_checkout_or_clone(repository_url const& url, std::filesystem::path path, repository_flags flags = repository_flags{})
226185
{
227186
assert(url.kind() == repository_type::git);
228187
return git_checkout_or_clone(url.url(), url.rev(), path, flags);

src/utility/git_tests.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ TEST_CASE(git_clone_fail_wrong_rev_name)
5151
auto const r = hk::git_clone(git_url, git_rev, tmp_dir.path());
5252
REQUIRE(r == hk::git_error::ok);
5353

54-
auto const r2 = hk::git_fetch_and_update(git_url, git_rev, tmp_dir.path(), hk::git_checkout_flags::fresh_clone);
54+
auto const r2 = hk::git_fetch_and_update(git_url, git_rev, tmp_dir.path(), hk::repository_flags::fresh_clone);
5555
REQUIRE(r2 == hk::git_error::rev_not_found);
5656
}
5757

@@ -66,7 +66,7 @@ TEST_CASE(git_clone_fail_wrong_rev_oid)
6666
auto const r = hk::git_clone(git_url, git_rev, tmp_dir.path());
6767
REQUIRE(r == hk::git_error::ok);
6868

69-
auto const r2 = hk::git_fetch_and_update(git_url, git_rev, tmp_dir.path(), hk::git_checkout_flags::fresh_clone);
69+
auto const r2 = hk::git_fetch_and_update(git_url, git_rev, tmp_dir.path(), hk::repository_flags::fresh_clone);
7070
REQUIRE(r2 == hk::git_error::rev_not_found);
7171
}
7272

@@ -83,7 +83,7 @@ TEST_CASE(git_fetch_and_update_tag)
8383
auto const r1 = hk::git_clone(git_url, git_rev, tmp_dir.path());
8484
REQUIRE(r1 == hk::git_error::ok);
8585

86-
auto const r2 = hk::git_fetch_and_update(git_url, git_rev, tmp_dir.path(), hk::git_checkout_flags::fresh_clone);
86+
auto const r2 = hk::git_fetch_and_update(git_url, git_rev, tmp_dir.path(), hk::repository_flags::fresh_clone);
8787
REQUIRE(r2 == hk::git_error::ok);
8888
}
8989

@@ -100,7 +100,7 @@ TEST_CASE(git_fetch_and_update_commit)
100100
auto const r1 = hk::git_clone(git_url, git_rev, tmp_dir.path());
101101
REQUIRE(r1 == hk::git_error::ok);
102102

103-
auto const r2 = hk::git_fetch_and_update(git_url, git_rev, tmp_dir.path(), hk::git_checkout_flags::fresh_clone);
103+
auto const r2 = hk::git_fetch_and_update(git_url, git_rev, tmp_dir.path(), hk::repository_flags::fresh_clone);
104104
REQUIRE(r2 == hk::git_error::ok);
105105
}
106106

0 commit comments

Comments
 (0)