Skip to content

Commit 4161117

Browse files
committed
Merge branch 'main' into melange/private-modules
* main: feature: glob_files to (install (files ...)) (ocaml#6250)
2 parents 4e4a217 + b61bd6a commit 4161117

29 files changed

+676
-63
lines changed

CHANGES.md

+3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ Unreleased
3030
- Prevent crash if absolute paths are used in the install stanza and in
3131
recursive globs. These cases now result in a user error. (#6331, @gridbugs)
3232

33+
- Add `(glob_files <glob>)` and `(glob_files_rec <glob>)` terms to the `files`
34+
field of the `install` stanza (#6250, closes #6018, @gridbugs)
35+
3336
3.5.0 (2022-10-19)
3437
------------------
3538

doc/dune-files.rst

+32
Original file line numberDiff line numberDiff line change
@@ -1450,6 +1450,38 @@ generates a file by listing all the files in a subdirectory ``resources``:
14501450
(with-stdout-to foo.sexp
14511451
(system "echo '(' resources/* ')'"))))
14521452
1453+
Globs in the Install Stanza
1454+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
1455+
1456+
You can use globs to specify files to install by using the terms
1457+
``(glob_files <glob>)`` and ``(glob_files_rec <glob>)`` inside the ``files``
1458+
field of the install stanza (but not inside the ``dirs`` field).
1459+
See the :ref:`glob <glob>` for details of the glob syntax.
1460+
The ``(glob_files <glob>)`` term will expand its argument within a single
1461+
directory, whereas the ``(glob_files_rec <glob>)`` term will recursively expand
1462+
its argument within all subdirectories.
1463+
1464+
For example:
1465+
1466+
.. code:: scheme
1467+
1468+
(install
1469+
(files (glob_files style/*.css) (glob_files_rec content/*.html))
1470+
(section share))
1471+
1472+
This example will install:
1473+
1474+
- all files matching ``*.css`` in the ``style`` directory
1475+
1476+
- all files matching ``*.html`` in the ``content`` directory, or any of its
1477+
descendant subdirectories
1478+
1479+
Note that the paths to files are preserved after installation. Suppose the
1480+
source directory contained the files ``style/foo.css`` and
1481+
``content/bar/baz.html``. The example above will place these files in
1482+
``share/<package>/style/foo.css`` and ``share/<package>/content/bar/baz.html``
1483+
respectively.
1484+
14531485
Handling of the .exe Extension on Windows
14541486
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
14551487

src/dune_rules/artifacts_db.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ let get_installed_binaries ~(context : Context.t) stanzas =
1414
let dir = Path.Build.append_source context.build_dir d.dir in
1515
let binaries_from_install files =
1616
let* unexpanded_file_bindings =
17-
Dune_file.Install_conf.File_entry.expand_include_multi files
17+
Dune_file.Install_conf.File_entry.to_file_bindings_unexpanded files
1818
~expand_str:(expand_str ~dir) ~dir
1919
in
2020
Memo.List.map unexpanded_file_bindings ~f:(fun fb ->

src/dune_rules/dep_conf.ml

+5-7
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@ type t =
55
| File of String_with_vars.t
66
| Alias of String_with_vars.t
77
| Alias_rec of String_with_vars.t
8-
| Glob_files of
9-
{ glob : String_with_vars.t
10-
; recursive : bool
11-
}
8+
| Glob_files of Glob_files.t
129
| Source_tree of String_with_vars.t
1310
| Package of String_with_vars.t
1411
| Universe
@@ -51,11 +48,12 @@ let decode =
5148
; ("alias", sw >>| fun x -> Alias x)
5249
; ("alias_rec", sw >>| fun x -> Alias_rec x)
5350
; ( "glob_files"
54-
, sw >>| fun x -> Glob_files { glob = x; recursive = false } )
51+
, sw >>| fun glob -> Glob_files { Glob_files.glob; recursive = false }
52+
)
5553
; ( "glob_files_rec"
5654
, let+ () = Dune_lang.Syntax.since Stanza.syntax (3, 0)
57-
and+ x = sw in
58-
Glob_files { glob = x; recursive = true } )
55+
and+ glob = sw in
56+
Glob_files { Glob_files.glob; recursive = true } )
5957
; ("package", sw >>| fun x -> Package x)
6058
; ("universe", return Universe)
6159
; ( "files_recursively_in"

src/dune_rules/dep_conf.mli

+1-4
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ type t =
44
| File of String_with_vars.t
55
| Alias of String_with_vars.t
66
| Alias_rec of String_with_vars.t
7-
| Glob_files of
8-
{ glob : String_with_vars.t
9-
; recursive : bool
10-
}
7+
| Glob_files of Glob_files.t
118
| Source_tree of String_with_vars.t
129
| Package of String_with_vars.t
1310
| Universe

src/dune_rules/dep_conf_eval.ml

+8-29
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,6 @@ let package_install ~(context : Build_context.t) ~(pkg : Package.t) =
1515
sprintf ".%s-files" (Package.Name.to_string name)
1616
|> Alias.Name.of_string |> Alias.make ~dir
1717

18-
module Source_tree_map_reduce =
19-
Source_tree.Dir.Make_map_reduce (Action_builder) (Monoid.Union (Path.Set))
20-
21-
let collect_source_files_recursively dir ~f =
22-
let prefix_with, dir = Path.extract_build_context_dir_exn dir in
23-
Action_builder.of_memo (Source_tree.find_dir dir) >>= function
24-
| None -> Action_builder.return Path.Set.empty
25-
| Some dir ->
26-
Source_tree_map_reduce.map_reduce dir ~traverse:Sub_dirs.Status.Set.all
27-
~f:(fun dir ->
28-
f (Path.append_source prefix_with (Source_tree.Dir.path dir)))
29-
3018
type dep_evaluation_result =
3119
| Simple of Path.t list Memo.t
3220
| Other of Path.t list Action_builder.t
@@ -136,24 +124,15 @@ let rec dep expander = function
136124
(let* a = make_alias expander s in
137125
let+ () = dep_on_alias_rec ~loc:(String_with_vars.loc s) a in
138126
[])
139-
| Glob_files { glob = s; recursive } ->
127+
| Glob_files glob_files ->
140128
Other
141-
(let loc = String_with_vars.loc s in
142-
let* path = Expander.expand_path expander s in
143-
if recursive && not (Path.is_managed path) then
144-
User_error.raise ~loc
145-
[ Pp.textf "Absolute paths in recursive globs are not supported." ];
146-
let files_in =
147-
let glob = Path.basename path |> Glob.of_string_exn loc in
148-
fun dir ->
149-
Action_builder.paths_matching ~loc (File_selector.of_glob ~dir glob)
150-
in
151-
let+ files =
152-
let dir = Path.parent_exn path in
153-
if recursive then collect_source_files_recursively dir ~f:files_in
154-
else files_in dir
155-
in
156-
Path.Set.to_list files)
129+
(Glob_files.Expand.action_builder glob_files
130+
~f:(Expander.expand_str expander)
131+
~base_dir:(Expander.dir expander)
132+
>>| List.map ~f:(fun path ->
133+
if Filename.is_relative path then
134+
Path.Build.relative (Expander.dir expander) path |> Path.build
135+
else Path.of_string path))
157136
| Source_tree s ->
158137
Other
159138
(let* path = Expander.expand_path expander s in

src/dune_rules/dune_file.ml

+92-15
Original file line numberDiff line numberDiff line change
@@ -1087,9 +1087,59 @@ module Install_conf = struct
10871087
str)
10881088

10891089
module File_entry = struct
1090+
module Without_include = struct
1091+
type t =
1092+
| File_binding of File_binding.Unexpanded.t
1093+
| Glob_files of Glob_files.t
1094+
1095+
let decode =
1096+
let open Dune_lang.Decoder in
1097+
let file_binding_decode =
1098+
let+ file_binding = File_binding.Unexpanded.decode in
1099+
File_binding file_binding
1100+
in
1101+
let glob_files_decode =
1102+
let version_check = Dune_lang.Syntax.since Stanza.syntax (3, 6) in
1103+
let+ glob_files =
1104+
sum
1105+
[ ( "glob_files"
1106+
, let+ glob = version_check >>> String_with_vars.decode in
1107+
{ Glob_files.glob; recursive = false } )
1108+
; ( "glob_files_rec"
1109+
, let+ glob = version_check >>> String_with_vars.decode in
1110+
{ Glob_files.glob; recursive = true } )
1111+
]
1112+
in
1113+
Glob_files glob_files
1114+
in
1115+
file_binding_decode <|> glob_files_decode
1116+
1117+
let to_file_bindings_unexpanded t ~expand_str ~dir =
1118+
match t with
1119+
| File_binding file_binding -> Memo.return [ file_binding ]
1120+
| Glob_files glob_files ->
1121+
let open Memo.O in
1122+
let+ paths =
1123+
Glob_files.Expand.memo glob_files ~f:expand_str ~base_dir:dir
1124+
in
1125+
let glob_loc = String_with_vars.loc glob_files.glob in
1126+
List.map paths ~f:(fun path ->
1127+
let src = (glob_loc, path) in
1128+
File_binding.Unexpanded.make ~src ~dst:src)
1129+
1130+
let to_file_bindings_expanded t ~expand_str ~dir =
1131+
to_file_bindings_unexpanded t ~expand_str ~dir
1132+
|> Memo.bind
1133+
~f:
1134+
(Memo.List.map
1135+
~f:
1136+
(File_binding.Unexpanded.expand ~dir
1137+
~f:(expand_str_with_check_for_local_path ~expand_str)))
1138+
end
1139+
10901140
include
10911141
Recursive_include.Make
1092-
(File_binding.Unexpanded)
1142+
(Without_include)
10931143
(struct
10941144
let include_keyword = "include"
10951145

@@ -1101,24 +1151,51 @@ module Install_conf = struct
11011151
let expand_include_multi ts ~expand_str ~dir =
11021152
Memo.List.concat_map ts ~f:(expand_include ~expand_str ~dir)
11031153

1104-
let of_file_binding = of_base
1154+
let of_file_binding file_binding =
1155+
of_base (Without_include.File_binding file_binding)
1156+
1157+
let to_file_bindings_unexpanded ts ~expand_str ~dir =
1158+
expand_include_multi ts ~expand_str ~dir
1159+
|> Memo.bind
1160+
~f:
1161+
(Memo.List.concat_map
1162+
~f:
1163+
(Without_include.to_file_bindings_unexpanded ~expand_str ~dir))
1164+
1165+
let to_file_bindings_expanded ts ~expand_str ~dir =
1166+
expand_include_multi ts ~expand_str ~dir
1167+
|> Memo.bind
1168+
~f:
1169+
(Memo.List.concat_map
1170+
~f:(Without_include.to_file_bindings_expanded ~expand_str ~dir))
1171+
end
11051172

1106-
let expand t ~expand_str ~dir =
1107-
let open Memo.O in
1108-
let* unexpanded = expand_include t ~expand_str ~dir in
1109-
Memo.List.map unexpanded
1110-
~f:
1111-
(File_binding.Unexpanded.expand ~dir
1112-
~f:(expand_str_with_check_for_local_path ~expand_str))
1173+
module Dir_entry = struct
1174+
include
1175+
Recursive_include.Make
1176+
(File_binding.Unexpanded)
1177+
(struct
1178+
let include_keyword = "include"
11131179

1114-
let expand_multi ts ~expand_str ~dir =
1115-
Memo.List.concat_map ts ~f:(expand ~expand_str ~dir)
1180+
let include_allowed_in_versions = `Since (3, 5)
1181+
1182+
let non_sexp_behaviour = `User_error
1183+
end)
1184+
1185+
let to_file_bindings_expanded ts ~expand_str ~dir =
1186+
Memo.List.concat_map ts ~f:(expand_include ~expand_str ~dir)
1187+
|> Memo.bind
1188+
~f:
1189+
(Memo.List.map
1190+
~f:
1191+
(File_binding.Unexpanded.expand ~dir
1192+
~f:(expand_str_with_check_for_local_path ~expand_str)))
11161193
end
11171194

11181195
type t =
11191196
{ section : Install.Section_with_site.t
11201197
; files : File_entry.t list
1121-
; dirs : File_entry.t list
1198+
; dirs : Dir_entry.t list
11221199
; package : Package.t
11231200
; enabled_if : Blang.t
11241201
}
@@ -1131,7 +1208,7 @@ module Install_conf = struct
11311208
and+ dirs =
11321209
field_o "dirs"
11331210
(Dune_lang.Syntax.since Stanza.syntax (3, 5)
1134-
>>> repeat File_entry.decode)
1211+
>>> repeat Dir_entry.decode)
11351212
and+ package = Stanza_common.Pkg.field ~stanza:"install"
11361213
and+ enabled_if =
11371214
let allowed_vars = Enabled_if.common_vars ~since:(2, 6) in
@@ -1147,9 +1224,9 @@ module Install_conf = struct
11471224

11481225
{ section; dirs; files; package; enabled_if })
11491226

1150-
let expand_files t = File_entry.expand_multi t.files
1227+
let expand_files t = File_entry.to_file_bindings_expanded t.files
11511228

1152-
let expand_dirs t = File_entry.expand_multi t.dirs
1229+
let expand_dirs t = Dir_entry.to_file_bindings_expanded t.dirs
11531230
end
11541231

11551232
module Executables = struct

src/dune_rules/dune_file.mli

+5-7
Original file line numberDiff line numberDiff line change
@@ -250,23 +250,21 @@ module Install_conf : sig
250250
module File_entry : sig
251251
type t
252252

253-
val expand_include_multi :
253+
val to_file_bindings_unexpanded :
254254
t list
255255
-> expand_str:(String_with_vars.t -> string Memo.t)
256256
-> dir:Path.Build.t
257257
-> File_binding.Unexpanded.t list Memo.t
258+
end
258259

259-
val expand_multi :
260-
t list
261-
-> expand_str:(String_with_vars.t -> string Memo.t)
262-
-> dir:Path.Build.t
263-
-> File_binding.Expanded.t list Memo.t
260+
module Dir_entry : sig
261+
type t
264262
end
265263

266264
type t =
267265
{ section : Install.Section_with_site.t
268266
; files : File_entry.t list
269-
; dirs : File_entry.t list
267+
; dirs : Dir_entry.t list
270268
; package : Package.t
271269
; enabled_if : Blang.t
272270
}

src/dune_rules/file_binding.ml

+14
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ let equal f g { src; dst } t = f src t.src && Option.equal g dst t.dst
1111
module Expanded = struct
1212
type nonrec t = (Loc.t * Path.Build.t, Loc.t * string) t
1313

14+
let to_dyn { src; dst } =
15+
let open Dyn in
16+
record
17+
[ ("src", pair Loc.to_dyn Path.Build.to_dyn src)
18+
; ("dst", option (pair Loc.to_dyn string) dst)
19+
]
20+
1421
let src t = snd t.src
1522

1623
let dst t = Option.map ~f:snd t.dst
@@ -31,6 +38,13 @@ end
3138
module Unexpanded = struct
3239
type nonrec t = (String_with_vars.t, String_with_vars.t) t
3340

41+
let to_dyn { src; dst } =
42+
let open Dyn in
43+
record
44+
[ ("src", String_with_vars.to_dyn src)
45+
; ("dst", option String_with_vars.to_dyn dst)
46+
]
47+
3448
let equal = equal String_with_vars.equal_no_loc String_with_vars.equal_no_loc
3549

3650
let make ~src:(locs, src) ~dst:(locd, dst) =

src/dune_rules/file_binding.mli

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ open Import
33
module Expanded : sig
44
type t
55

6+
val to_dyn : t -> Dyn.t
7+
68
val src : t -> Path.Build.t
79

810
val dst : t -> string option
@@ -15,6 +17,8 @@ end
1517
module Unexpanded : sig
1618
type t
1719

20+
val to_dyn : t -> Dyn.t
21+
1822
val equal : t -> t -> bool
1923

2024
val make : src:Loc.t * string -> dst:Loc.t * string -> t

0 commit comments

Comments
 (0)