@@ -41,40 +41,62 @@ let dyn_of_kind = function
4141
4242module Dir_map = struct
4343 module Per_dir = struct
44+ let no_dupes =
45+ Option. merge ~f: (fun (loc , _ ) (loc2 , _ ) ->
46+ let main_message = Pp. text " This stanza was already specified at:" in
47+ let annots =
48+ let main = User_message. make ~loc [ main_message ] in
49+ let related =
50+ [ User_message. make ~loc: loc2 [ Pp. text " Already defined here" ] ]
51+ in
52+ User_message.Annots. singleton
53+ Compound_user_error. annot
54+ [ Compound_user_error. make ~main ~related ]
55+ in
56+ User_error. raise
57+ ~loc
58+ ~annots
59+ [ main_message; Pp. verbatim (Loc. to_file_colon_line loc2) ])
60+ ;;
61+
62+ module Files = struct
63+ type t = (Loc .t * Predicate_lang.Glob .t ) option
64+
65+ let default = None
66+
67+ let eval t ~files =
68+ match t with
69+ | None -> files
70+ | Some (_ , glob ) ->
71+ Filename.Set. filter files ~f: (fun filename ->
72+ Predicate_lang.Glob. test glob ~standard: Predicate_lang. true_ filename)
73+ ;;
74+ end
75+
4476 type t =
4577 { sexps : Dune_lang.Ast .t list
4678 ; subdir_status : Source_dir_status.Spec .input
79+ ; files : Files .t
4780 }
4881
49- let to_dyn { sexps; subdir_status = _ } =
82+ let to_dyn { sexps; subdir_status = _ ; files = _ } =
5083 let open Dyn in
5184 record
5285 [ " sexps" , list Dune_lang. to_dyn (List. map ~f: Dune_lang.Ast. remove_locs sexps) ]
5386 ;;
5487
5588 let empty =
56- { sexps = [] ; subdir_status = Source_dir_status.Map. init ~f: (fun _ -> None ) }
89+ { sexps = []
90+ ; subdir_status = Source_dir_status.Map. init ~f: (fun _ -> None )
91+ ; files = None
92+ }
5793 ;;
5894
5995 let merge d1 d2 =
6096 { sexps = d1.sexps @ d2.sexps
6197 ; subdir_status =
62- Source_dir_status.Map. merge d1.subdir_status d2.subdir_status ~f: (fun l r ->
63- Option. merge l r ~f: (fun (loc , _ ) (loc2 , _ ) ->
64- let main_message = Pp. text " This stanza stanza was already specified at:" in
65- let annots =
66- let main = User_message. make ~loc [ main_message ] in
67- let related =
68- [ User_message. make ~loc: loc2 [ Pp. text " Already defined here" ] ]
69- in
70- User_message.Annots. singleton
71- Compound_user_error. annot
72- [ Compound_user_error. make ~main ~related ]
73- in
74- User_error. raise
75- ~loc
76- ~annots
77- [ main_message; Pp. verbatim (Loc. to_file_colon_line loc2) ]))
98+ Source_dir_status.Map. merge d1.subdir_status d2.subdir_status ~f: no_dupes
99+ ; files = no_dupes d1.files d2.files
78100 }
79101 ;;
80102 end
@@ -113,12 +135,15 @@ module Dir_map = struct
113135 let merge_all = List. fold_left ~f: merge ~init: empty
114136end
115137
138+ module Files = Dir_map.Per_dir. Files
139+
116140module Ast = struct
117141 type t =
118142 | Ignored_sub_dirs of Loc .t * Predicate_lang.Glob .t
119143 | Data_only_dirs of Loc .t * Predicate_lang.Glob .t
120144 | Vendored_dirs of Loc .t * Predicate_lang.Glob.Element .t Predicate_lang .t
121145 | Dirs of Loc .t * Predicate_lang.Glob .t
146+ | Files of Loc .t * Predicate_lang.Glob .t
122147 | Subdir of Path.Local .t * t list
123148 | Include of
124149 { loc : Loc .t
@@ -212,6 +237,15 @@ module Ast = struct
212237 Dirs (loc, dirs)
213238 ;;
214239
240+ let files =
241+ let + loc, files =
242+ Dune_lang.Syntax. since Stanza. syntax (3 , 21 )
243+ >>> Predicate_lang.Glob. decode
244+ |> located
245+ in
246+ Files (loc, files)
247+ ;;
248+
215249 let data_only_dirs =
216250 let + loc, glob =
217251 located
@@ -257,6 +291,7 @@ module Ast = struct
257291 @@
258292 let + subdirs = multi_field " subdir" (subdir ~inside_include )
259293 and + dirs = field_o " dirs" dirs
294+ and + files = field_o " files" files
260295 and + ignored_sub_dirs =
261296 multi_field " ignored_subdirs" (ignored_sub_dirs ~inside_subdir )
262297 and + vendored_dirs = field_o " vendored_dirs" vendored_dirs
@@ -266,6 +301,7 @@ module Ast = struct
266301 let ast =
267302 List. concat
268303 [ Option. to_list dirs
304+ ; Option. to_list files
269305 ; Option. to_list vendored_dirs
270306 ; subdirs
271307 ; ignored_sub_dirs
@@ -281,7 +317,7 @@ module Ast = struct
281317 let statically_evaluated_stanzas =
282318 (* This list must be kept in sync with [decode]
283319 [include] is excluded b/c it's also a normal stanza *)
284- [ " data_only_dirs" ; " vendored_dirs" ; " ignored_sub_dirs" ; " subdir" ; " dirs" ]
320+ [ " data_only_dirs" ; " vendored_dirs" ; " ignored_sub_dirs" ; " subdir" ; " dirs" ; " files " ]
285321 ;;
286322
287323 let decode ~inside_subdir ~inside_include =
@@ -340,6 +376,7 @@ module Group = struct
340376 ; data_only_dirs : (Loc .t * Predicate_lang.Glob .t ) option
341377 ; vendored_dirs : (Loc .t * Predicate_lang.Glob.Element .t Predicate_lang .t ) option
342378 ; dirs : (Loc .t * Predicate_lang.Glob .t ) option
379+ ; files : (Loc .t * Predicate_lang.Glob .t ) option
343380 ; leftovers : Dune_lang.Ast .t list
344381 ; subdirs : (Path.Local .t * Ast .t list ) list
345382 }
@@ -349,6 +386,7 @@ module Group = struct
349386 ; data_only_dirs = None
350387 ; vendored_dirs = None
351388 ; dirs = None
389+ ; files = None
352390 ; subdirs = []
353391 ; leftovers = []
354392 }
@@ -385,6 +423,7 @@ module Group = struct
385423 | Vendored_dirs (loc , glob ) ->
386424 { t with vendored_dirs = Some (no_dupes " vendored_dirs" loc t.vendored_dirs glob) }
387425 | Dirs (loc , glob ) -> { t with dirs = Some (no_dupes " dirs" loc t.dirs glob) }
426+ | Files (loc , glob ) -> { t with files = Some (no_dupes " files" loc t.files glob) }
388427 | Subdir (path , stanzas ) -> { t with subdirs = (path, stanzas) :: t.subdirs }
389428 | Leftovers stanzas -> { t with leftovers = List. rev_append stanzas t.leftovers }
390429 | Include _ -> assert false
@@ -412,7 +451,8 @@ let rec to_dir_map ast =
412451 let group = Group. of_ast ast in
413452 let node =
414453 let subdir_status = Group. subdir_status group in
415- Dir_map. singleton { Dir_map.Per_dir. sexps = group.leftovers; subdir_status }
454+ let files = group.files in
455+ Dir_map. singleton { Dir_map.Per_dir. sexps = group.leftovers; subdir_status; files }
416456 in
417457 let subdirs =
418458 List. map group.subdirs ~f: (fun (path , stanzas ) ->
@@ -463,6 +503,7 @@ let get_static_sexp t = (Dir_map.root t.plain).sexps
463503let kind t = t.kind
464504let path t = t.path
465505let sub_dir_status t = Source_dir_status.Spec. create (Dir_map. root t.plain).subdir_status
506+ let files t = (Dir_map. root t.plain).files
466507
467508let load_plain sexps ~file ~from_parent ~project =
468509 let + parsed =
0 commit comments