Skip to content

Commit cf36e22

Browse files
committed
Work on repository scan
1 parent 0d1d5bb commit cf36e22

File tree

4 files changed

+182
-2
lines changed

4 files changed

+182
-2
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ target_sources(hkc PRIVATE
135135
"${CMAKE_CURRENT_SOURCE_DIR}/src/hkc/hkc.cpp"
136136
"${CMAKE_CURRENT_SOURCE_DIR}/src/hkc/options.cpp"
137137
"${CMAKE_CURRENT_SOURCE_DIR}/src/hkc/options.hpp"
138+
"${CMAKE_CURRENT_SOURCE_DIR}/src/hkc/repository.cpp"
139+
"${CMAKE_CURRENT_SOURCE_DIR}/src/hkc/repository.hpp"
138140
)
139141

140142
target_include_directories(hkc PRIVATE "${CMAKE_SOURCE_DIR}/src")

src/hkc/repository.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
2+
#include "repository.hpp"
3+
#include "utility/path.hpp"
4+
#include "utility/vector_set.hpp"
5+
#include "utility/file_cursor.hpp"
6+
#include "parser/parsers.hpp"
7+
#include <cassert>
8+
#include <algorithm>
9+
10+
namespace hk {
11+
12+
repository::repository(std::filesystem::path path) : _path(std::move(path))
13+
{
14+
assert(std::filesystem::canonical(_path) == _path);
15+
}
16+
17+
void repository::scan_prologues(bool force)
18+
{
19+
untouch(false);
20+
21+
auto first = std::filesystem::recursive_directory_iterator{_path};
22+
auto last = std::filesystem::recursive_directory_iterator{};
23+
24+
auto visited = vector_set<std::filesystem::path>{};
25+
for (auto it = first; it != last; ++it) {
26+
auto const& entry = *it;
27+
28+
if (entry.path().filename().string().starts_with(".")) {
29+
// Do not recursively scan hidden directories.
30+
if (entry.is_directory()) {
31+
it.disable_recursion_pending();
32+
}
33+
continue;
34+
}
35+
36+
auto module_path = std::filesystem::canonical(entry.path());
37+
if (not visited.add(module_path)) {
38+
// This directory has already been visited; a potential symlink loop.
39+
if (entry.is_directory()) {
40+
it.disable_recursion_pending();
41+
}
42+
continue;
43+
}
44+
45+
if (not entry.is_regular_file()) {
46+
continue;
47+
}
48+
49+
if (entry.path().extension() != ".hkm") {
50+
continue;
51+
}
52+
53+
auto &m = get_module(module_path);
54+
m.touched = true;
55+
56+
if (m.ast and m.time == entry.last_write_time()) {
57+
// The prologue for this module has already been scanned.
58+
continue;
59+
}
60+
61+
auto cursor = file_cursor(module_path);
62+
m.ast = parse_module(cursor, true);
63+
}
64+
65+
untouch(true);
66+
}
67+
68+
void repository::untouch(bool remove)
69+
{
70+
auto it = _modules.begin();
71+
while (it != _modules.end()) {
72+
if (not it->touched) {
73+
it = _modules.erase(it, it + 1);
74+
} else {
75+
it->touched = false;
76+
++it;
77+
}
78+
}
79+
}
80+
81+
repository::module_type& repository::get_module(std::filesystem::path const& module_path)
82+
{
83+
assert(is_subpath(module_path, _path));
84+
85+
auto it = std::lower_bound(_modules.begin(), _modules.end(), module_path, [](auto const &item, auto const &key) {
86+
return item.path < key;
87+
});
88+
if (it == _modules.end() or it->path != module_path) {
89+
it = _modules.insert(it, module_type{module_path});
90+
}
91+
return *it;
92+
}
93+
94+
repository::module_type::module_type(std::filesystem::path path) : path(std::move(path))
95+
{
96+
assert(std::filesystem::canonical(this->path) == this->path);
97+
}
98+
99+
}

src/hkc/repository.hpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
2+
#pragma once
3+
4+
#include "ast/module_node.hpp"
5+
#include <filesystem>
6+
#include <memory>
7+
#include <chrono>
8+
#include <vector>
9+
10+
namespace hk {
11+
12+
class repository {
13+
public:
14+
repository(std::filesystem::path path);
15+
16+
/** Scan the prologue of each *.hkm in the repository.
17+
*
18+
* @param force Force scanning even on files that were already parsed.
19+
*/
20+
void scan_prologues(bool force);
21+
22+
23+
24+
private:
25+
struct module_type {
26+
std::filesystem::path path;
27+
28+
/** This is the timestamp of the file when it was parsed.
29+
*/
30+
std::filesystem::file_time_type time;
31+
32+
std::unique_ptr<ast::module_node> ast;
33+
34+
/** This flag is used to determine if a module has been removed from
35+
* the filesystem.
36+
*/
37+
bool touched = false;
38+
39+
module_type(std::filesystem::path path);
40+
};
41+
42+
std::filesystem::path _path;
43+
44+
/** modules, sorted by path.
45+
*/
46+
std::vector<module_type> _modules;
47+
48+
/** Unset the touch flag on all modules.
49+
*
50+
* @param remove Remove modules if already not touched.
51+
*/
52+
void untouch(bool remove);
53+
54+
/** Get or make a module based on the path.
55+
*
56+
* @note It is UNDEFINED BEHAVIOR if @a path is not canonical or is not
57+
* inside the repository.
58+
* @param path The path the module.
59+
*/
60+
[[nodiscard]] module_type &get_module(std::filesystem::path const& path);
61+
};
62+
63+
64+
}

src/utility/git.hpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,12 @@ enum class git_checkout_flags {
103103
return static_cast<git_checkout_flags>(~std::to_underlying(rhs));
104104
}
105105

106-
constexpr git_checkout_flags& operator|=(git_checkout_flags &lhs, git_checkout_flags rhs) noexcept
106+
constexpr git_checkout_flags& operator|=(git_checkout_flags& lhs, git_checkout_flags rhs) noexcept
107107
{
108108
return lhs = lhs | rhs;
109109
}
110110

111-
constexpr git_checkout_flags& operator&=(git_checkout_flags &lhs, git_checkout_flags rhs) noexcept
111+
constexpr git_checkout_flags& operator&=(git_checkout_flags& lhs, git_checkout_flags rhs) noexcept
112112
{
113113
return lhs = lhs & rhs;
114114
}
@@ -118,6 +118,11 @@ constexpr git_checkout_flags& operator&=(git_checkout_flags &lhs, git_checkout_f
118118
return static_cast<bool>(std::to_underlying(rhs));
119119
}
120120

121+
struct git_url {
122+
std::string url;
123+
std::string rev;
124+
};
125+
121126
struct git_reference {
122127
std::string name = {};
123128
std::string oid = {};
@@ -215,4 +220,14 @@ class git_references : public std::vector<git_reference> {
215220
std::filesystem::path path,
216221
git_checkout_flags flags = git_checkout_flags{});
217222

223+
/** Checkout or clone the repository.
224+
*
225+
* @see git_checkout_or_clone
226+
*/
227+
[[nodiscard]] git_error
228+
git_checkout_or_clone(git_url const& url, std::filesystem::path path, git_checkout_flags flags = git_checkout_flags{})
229+
{
230+
return git_checkout_or_clone(url.url, url.rev, path, flags);
231+
}
232+
218233
} // namespace hk

0 commit comments

Comments
 (0)