1212
1313namespace hk {
1414
15- repository::repository (std::filesystem::path path) : _path (std::move(path))
15+ repository::repository (std::filesystem::path path, repository_url remote ) : remote(remote), path (std::move(path))
1616{
17- assert (std::filesystem::canonical (_path) == _path);
1817}
1918
2019void repository::scan_prologues (repository_flags flags)
2120{
2221 untouch (false );
2322
24- auto first = std::filesystem::recursive_directory_iterator{_path };
23+ auto first = std::filesystem::recursive_directory_iterator{path };
2524 auto last = std::filesystem::recursive_directory_iterator{};
2625
2726 auto visited = vector_set<std::filesystem::path>{};
@@ -71,54 +70,57 @@ void repository::scan_prologues(repository_flags flags)
7170 untouch (true );
7271}
7372
74- error_code repository::recursive_scan_prologues (repository_flags flags)
73+ void repository::recursive_scan_prologues (repository_flags flags)
7574{
76- auto todo = std::map<repository_url, error_location>{};
77- auto done = std::map<repository_url, error_location>{};
75+ auto todo = std::vector<std::pair<repository_url, error_location>>{};
7876
7977 scan_prologues (flags);
8078 for (auto item : remote_repositories ()) {
81- todo.insert (std::move (item));
79+ todo.push_back (std::move (item));
8280 }
8381
84- auto hkdeps_path = _path / " _hkdeps" ;
82+ auto hkdeps_path = path / " _hkdeps" ;
8583
8684 auto ec = std::error_code{};
8785 if (not std::filesystem::create_directory (hkdeps_path, ec) and ec) {
8886 std::println (stderr, " Error: could not create directory '{}': {}." , hkdeps_path.string (), ec.message ());
8987 std::terminate ();
9088 }
9189
90+ // The mark will be used to see if a child repository was already processed.
91+ for (auto &repo : child_repositories ()) {
92+ repo->mark = false ;
93+ }
94+
9295 while (not todo.empty ()) {
93- auto child_repo_url_node = todo.extract (todo.begin ());
94- auto [it, inserted, _] = done.insert (std::move (child_repo_url_node));
95- if (not inserted) {
96+ auto [child_remote, import_errors] = std::move (todo.back ());
97+ todo.pop_back ();
98+
99+ auto child_local_path = hkdeps_path / child_remote.directory ();
100+ auto &child_repo = get_child_repository (child_remote, child_local_path);
101+ if (child_repo.mark ) {
96102 continue ;
97103 }
98104
99- assert (it != done. end ()) ;
100- auto child_repo_path = hkdeps_path / it-> first . directory ();
101- auto &child_repo = get_child_repository (it-> first );
102- if ( not child_repo. repository ) {
103- if ( auto r = git_checkout_or_clone (it-> first , child_repo_path, flags); r != git_error::ok) {
104- auto short_hkdeps = std::format ( " _hkdeps/{} " , it-> first . directory () );
105- return it-> second . add (error::could_not_clone_repository, it-> first . url (), it-> first . rev (), short_hkdeps, r). error () ;
106- }
105+ child_repo. mark = true ;
106+ if ( auto r = git_checkout_or_clone (child_remote, child_local_path, flags); r != git_error::ok) {
107+ auto short_hkdeps = std::format ( " _hkdeps/{} " , child_remote. directory () );
108+ // TODO #1 All failing import statements of a single repository should be marked with an error.
109+ import_errors. add (error::could_not_clone_repository, child_remote. url (), child_remote. rev (), short_hkdeps, r);
110+ erase_child_repository (child_remote );
111+ continue ;
112+ }
107113
108- child_repo.repository = std::make_unique<repository>(child_repo_path);
109- child_repo.repository ->scan_prologues (flags);
110- for (auto item : child_repo.repository ->remote_repositories ()) {
111- todo.insert (std::move (item));
112- }
114+ child_repo.scan_prologues (flags);
115+ for (auto item : child_repo.remote_repositories ()) {
116+ todo.push_back (std::move (item));
113117 }
114118 }
115119
116120 // Remove internal repositories not in 'done'.
117121 std::erase_if (_child_repositories, [&](auto const & item) {
118- return not done. contains ( item. url ) ;
122+ return not item-> mark ;
119123 });
120-
121- return hk::error_code{};
122124}
123125
124126void repository::untouch (bool remove)
@@ -145,7 +147,7 @@ void repository::untouch(bool remove)
145147
146148[[nodiscard]] repository::module_type& repository::get_module (std::filesystem::path const & module_path)
147149{
148- assert (is_subpath (module_path, _path ));
150+ assert (is_subpath (module_path, path ));
149151
150152 auto it = std::lower_bound (_modules.begin (), _modules.end (), module_path, [](auto const & item, auto const & key) {
151153 return item.path < key;
@@ -156,16 +158,28 @@ void repository::untouch(bool remove)
156158 return *it;
157159}
158160
159- [[nodiscard]] repository::child_repository_type & repository::get_child_repository (repository_url const & url )
161+ [[nodiscard]] repository& repository::get_child_repository (repository_url const & remote, std::filesystem::path child_path )
160162{
161163 auto it =
162- std::lower_bound (_child_repositories.begin (), _child_repositories.end (), url , [](auto const & item, auto const & key) {
163- return item. url < key;
164+ std::lower_bound (_child_repositories.begin (), _child_repositories.end (), remote , [](auto const & item, auto const & key) {
165+ return item-> remote < key;
164166 });
165- if (it == _child_repositories.end () or it->url != url) {
166- it = _child_repositories.insert (it, child_repository_type{url});
167+ if (it == _child_repositories.end () or (*it)->remote != remote) {
168+ it = _child_repositories.insert (it, std::make_unique<repository>(child_path, remote));
169+ }
170+ return **it;
171+ }
172+
173+ void repository::erase_child_repository (repository_url const & remote)
174+ {
175+ auto it =
176+ std::lower_bound (_child_repositories.begin (), _child_repositories.end (), remote, [](auto const & item, auto const & key) {
177+ return item->remote < key;
178+ });
179+
180+ if (it != _child_repositories.end () and (*it)->remote == remote) {
181+ _child_repositories.erase (it);
167182 }
168- return *it;
169183}
170184
171185repository::module_type::module_type (std::filesystem::path path) : path(std::move(path))
0 commit comments