68 lines
1.4 KiB
OCaml
68 lines
1.4 KiB
OCaml
|
open! Import
|
||
|
|
||
|
module Dir = struct
|
||
|
type t =
|
||
|
{ path : Path.t
|
||
|
; files : String_set.t
|
||
|
; sub_dirs : t String_map.t
|
||
|
}
|
||
|
|
||
|
let path t = t.path
|
||
|
let files t = t.files
|
||
|
let sub_dirs t = t.sub_dirs
|
||
|
|
||
|
let rec fold t ~init ~f =
|
||
|
let init = f t init in
|
||
|
String_map.fold t.sub_dirs ~init ~f:(fun ~key:_ ~data:t acc ->
|
||
|
fold t ~init:acc ~f)
|
||
|
end
|
||
|
|
||
|
type t =
|
||
|
{ root : Dir.t
|
||
|
; dirs : Dir.t Path.Map.t
|
||
|
}
|
||
|
|
||
|
let root t = t.root
|
||
|
|
||
|
let ignore_file = function
|
||
|
| ""
|
||
|
| "_build"
|
||
|
| ".git"
|
||
|
| ".hg"
|
||
|
| "_darcs"
|
||
|
| "." -> true
|
||
|
| fn -> fn.[0] = '.' && fn.[1] = '#'
|
||
|
|
||
|
let load path =
|
||
|
let rec walk path : Dir.t =
|
||
|
let files, sub_dirs =
|
||
|
Path.readdir path
|
||
|
|> List.filter ~f:(fun fn ->
|
||
|
not (ignore_file fn))
|
||
|
|> List.partition_map ~f:(fun fn ->
|
||
|
let path = Path.relative path fn in
|
||
|
if Path.exists path && Path.is_directory path then
|
||
|
Inr (fn, walk path)
|
||
|
else
|
||
|
Inl fn)
|
||
|
in
|
||
|
{ path
|
||
|
; files = String_set.of_list files
|
||
|
; sub_dirs = String_map.of_alist_exn sub_dirs
|
||
|
}
|
||
|
in
|
||
|
let root = walk path in
|
||
|
let dirs =
|
||
|
Dir.fold root ~init:Path.Map.empty ~f:(fun dir acc ->
|
||
|
Path.Map.add acc ~key:dir.path ~data:dir)
|
||
|
in
|
||
|
{ root
|
||
|
; dirs
|
||
|
}
|
||
|
|
||
|
let fold t ~init ~f =
|
||
|
Path.Map.fold t.dirs ~init ~f:(fun ~key:_ ~data:dir acc -> f dir acc)
|
||
|
|
||
|
let find_dir t path =
|
||
|
Path.Map.find path t.dirs
|