-
Notifications
You must be signed in to change notification settings - Fork 411
/
workspace_root.ml
117 lines (109 loc) · 3.22 KB
/
workspace_root.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
open Stdune
open Dune_rules
module Kind = struct
type t =
| Explicit
| Dune_workspace
| Dune_project
| Cwd
let priority = function
| Explicit -> 0
| Dune_workspace -> 1
| Dune_project -> 2
| Cwd -> 3
;;
let lowest_priority = max_int
let of_dir_contents files =
if String.Set.mem files Workspace.filename
then Some Dune_workspace
else if Filename.Set.mem files Dune_project.filename
then Some Dune_project
else None
;;
end
type t =
{ dir : string
; to_cwd : string list
; reach_from_root_prefix : string
; kind : Kind.t
}
module Candidate = struct
type t =
{ dir : string
; to_cwd : string list
; kind : Kind.t
}
end
let find () =
let cwd = Sys.getcwd () in
let rec loop counter ~(candidate : Candidate.t option) ~to_cwd dir : Candidate.t option =
match Sys.readdir dir with
| exception Sys_error msg ->
User_warning.emit
[ Pp.textf
"Unable to read directory %s. Will not look for root in parent directories."
dir
; Pp.textf "Reason: %s" msg
; Pp.text "To remove this warning, set your root explicitly using --root."
];
candidate
| files ->
let files = String.Set.of_list (Array.to_list files) in
let candidate =
let candidate_priority =
match candidate with
| Some c -> Kind.priority c.kind
| None -> Kind.lowest_priority
in
match Kind.of_dir_contents files with
| Some kind when Kind.priority kind <= candidate_priority ->
Some { Candidate.kind; dir; to_cwd }
| _ -> candidate
in
cont counter ~candidate dir ~to_cwd
and cont counter ~candidate ~to_cwd dir =
if counter > String.length cwd
then candidate
else (
let parent = Filename.dirname dir in
if parent = dir
then candidate
else (
let base = Filename.basename dir in
loop (counter + 1) parent ~candidate ~to_cwd:(base :: to_cwd)))
in
loop 0 ~to_cwd:[] cwd ~candidate:None
;;
let create ~default_is_cwd ~specified_by_user =
match
match specified_by_user with
| Some dn -> Some { Candidate.kind = Explicit; dir = dn; to_cwd = [] }
| None ->
let cwd = { Candidate.kind = Cwd; dir = "."; to_cwd = [] } in
if Dune_util.Execution_env.inside_dune
then Some cwd
else (
match find () with
| Some s -> Some s
| None -> if default_is_cwd then Some cwd else None)
with
| Some { Candidate.dir; to_cwd; kind } ->
{ kind
; dir
; to_cwd
; reach_from_root_prefix = String.concat ~sep:"" (List.map to_cwd ~f:(sprintf "%s/"))
}
| None ->
User_error.raise
[ Pp.text "I cannot find the root of the current workspace/project."
; Pp.text "If you would like to create a new dune project, you can type:"
; Pp.nop
; Pp.verbatim " dune init project NAME"
; Pp.nop
; Pp.text
"Otherwise, please make sure to run dune inside an existing project or \
workspace. For more information about how dune identifies the root of the \
current workspace/project, please refer to \
https://dune.readthedocs.io/en/stable/usage.html#finding-the-root"
]
;;