refactor parameterize scan_project_root/scan_subdirectory

Extract the shared recursive directory scanner into scan_directory, parameterized by root path. Both scan_project_root and scan_subdirectory now delegate to it, eliminating ~30 lines of duplicated logic.

Commit
6c059e924240dbaea083735397408a4b9d319086
Author
Claude Sonnet 4 <claude@anthropic.invalid>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
lib/resolvers.ml
index 530f588b..600db148 100644..100644
@@ -136,7 +136,7 @@
136 136 let description_of_layout { git_dir; _ } =
137 137 Filename.concat git_dir "description" |> read_description_file
138 138
139 Removed: let scan_project_root config =
139 Added: let scan_directory root_path =
140 140 let ( let* ) = Result.bind in
141 141 let rec scan dir_path =
142 142 try
@@ -165,8 +165,10 @@
165 165 collect [] names
166 166 with Sys_error message -> Error (Internal message)
167 167 in
168 Removed: scan config.Config.git_project_root
168 Added: scan root_path
169 169
170 Added: let scan_project_root config = scan_directory config.Config.git_project_root
171 Added:
170 172 type repository = {
171 173 name : string;
172 174 store : Store.t;
@@ -776,38 +778,10 @@
776 778 try_candidates readme_candidates
777 779
778 780 let scan_subdirectory config subdir =
779 Removed: let ( let* ) = Result.bind in
780 Removed: let rec scan dir_path =
781 Removed: try
782 Removed: let names =
783 Removed: Sys.readdir dir_path |> Array.to_list |> List.sort String.compare
784 Removed: in
785 Removed: let rec collect acc = function
786 Removed: | [] -> Ok (List.rev acc)
787 Removed: | name :: rest when String.starts_with ~prefix:"." name ->
788 Removed: collect acc rest
789 Removed: | name :: rest -> (
790 Removed: let path = Filename.concat dir_path name in
791 Removed: let* is_dir = is_directory path in
792 Removed: if not is_dir then collect acc rest
793 Removed: else
794 Removed: let* layout = repository_layout path in
795 Removed: match layout with
796 Removed: | Some layout ->
797 Removed: let description = description_of_layout layout in
798 Removed: collect (Repo { repo_name = name; description } :: acc) rest
799 Removed: | None ->
800 Removed: let* children = scan path in
801 Removed: if children = [] then collect acc rest
802 Removed: else collect (Directory (name, children) :: acc) rest)
803 Removed: in
804 Removed: collect [] names
805 Removed: with Sys_error message -> Error (Internal message)
806 Removed: in
807 781 let full_path = Filename.concat config.Config.git_project_root subdir in
808 782 if not (Sys.file_exists full_path && Sys.is_directory full_path) then
809 783 Error (Not_found ("directory not found: " ^ subdir))
810 Removed: else scan full_path
784 Added: else scan_directory full_path
811 785
812 786 let read_subdir_readme config subdir =
813 787 let readme_candidates =