Skip to content

Commit d5e3114

Browse files
authoredFeb 1, 2021
Add glob_files_rec (#4176)
Signed-off-by: Jeremie Dimino <jeremie@dimino.org>
1 parent 231ad58 commit d5e3114

File tree

6 files changed

+152
-9
lines changed

6 files changed

+152
-9
lines changed
 

‎CHANGES.md

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Unreleased
1212

1313
- Allow `%{version:pkg}` to work for external packages (#4104, @kit-ty-kate)
1414

15+
- Add `(glob_files_rec <dir>/<glob>)` for globbing files recursively (#4176, @jeremiedimino)
16+
1517
2.8.2 (21/01/2021)
1618
------------------
1719

‎src/dune_rules/dep_conf.ml

+18-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ type t =
77
| File of String_with_vars.t
88
| Alias of String_with_vars.t
99
| Alias_rec of String_with_vars.t
10-
| Glob_files of String_with_vars.t
10+
| Glob_files of
11+
{ glob : String_with_vars.t
12+
; recursive : bool
13+
}
1114
| Source_tree of String_with_vars.t
1215
| Package of String_with_vars.t
1316
| Universe
@@ -18,7 +21,8 @@ let remove_locs = function
1821
| File sw -> File (String_with_vars.remove_locs sw)
1922
| Alias sw -> Alias (String_with_vars.remove_locs sw)
2023
| Alias_rec sw -> Alias_rec (String_with_vars.remove_locs sw)
21-
| Glob_files sw -> Glob_files (String_with_vars.remove_locs sw)
24+
| Glob_files g ->
25+
Glob_files { g with glob = String_with_vars.remove_locs g.glob }
2226
| Source_tree sw -> Source_tree (String_with_vars.remove_locs sw)
2327
| Package sw -> Package (String_with_vars.remove_locs sw)
2428
| Universe -> Universe
@@ -46,7 +50,12 @@ let decode =
4650
[ ("file", sw >>| fun x -> File x)
4751
; ("alias", sw >>| fun x -> Alias x)
4852
; ("alias_rec", sw >>| fun x -> Alias_rec x)
49-
; ("glob_files", sw >>| fun x -> Glob_files x)
53+
; ( "glob_files"
54+
, sw >>| fun x -> Glob_files { glob = x; recursive = false } )
55+
; ( "glob_files_rec"
56+
, let+ () = Dune_lang.Syntax.since Stanza.syntax (2, 9)
57+
and+ x = sw in
58+
Glob_files { glob = x; recursive = true } )
5059
; ("package", sw >>| fun x -> Package x)
5160
; ("universe", return Universe)
5261
; ( "files_recursively_in"
@@ -76,9 +85,13 @@ let encode = function
7685
| Alias_rec t ->
7786
List
7887
[ Dune_lang.unsafe_atom_of_string "alias_rec"; String_with_vars.encode t ]
79-
| Glob_files t ->
88+
| Glob_files { glob = t; recursive } ->
8089
List
81-
[ Dune_lang.unsafe_atom_of_string "glob_files"
90+
[ Dune_lang.unsafe_atom_of_string
91+
( if recursive then
92+
"glob_files_rec"
93+
else
94+
"glob_files" )
8295
; String_with_vars.encode t
8396
]
8497
| Source_tree t ->

‎src/dune_rules/dep_conf.mli

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ type t =
66
| File of String_with_vars.t
77
| Alias of String_with_vars.t
88
| Alias_rec of String_with_vars.t
9-
| Glob_files of String_with_vars.t
9+
| Glob_files of
10+
{ glob : String_with_vars.t
11+
; recursive : bool
12+
}
1013
| Source_tree of String_with_vars.t
1114
| Package of String_with_vars.t
1215
| Universe

‎src/dune_rules/dep_conf_eval.ml

+24-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ let make_alias expander s =
88
Expander.Or_exn.expand_path expander s
99
|> Result.map ~f:(Alias.of_user_written_path ~loc)
1010

11+
let fold_source_dirs dir ~init ~f =
12+
let prefix_with, dir = Path.extract_build_context_dir_exn dir in
13+
match File_tree.find_dir dir with
14+
| None -> init
15+
| Some dir ->
16+
File_tree.Dir.fold dir ~init ~traverse:Sub_dirs.Status.Set.all
17+
~f:(fun dir acc ->
18+
f (Path.append_source prefix_with (File_tree.Dir.path dir)) acc)
19+
1120
let dep expander = function
1221
| File s ->
1322
Expander.Or_exn.expand_path expander s
@@ -26,16 +35,28 @@ let dep expander = function
2635
Build_system.Alias.dep_rec ~loc:(String_with_vars.loc s) a
2736
in
2837
[])
29-
| Glob_files s ->
38+
| Glob_files { glob = s; recursive } ->
3039
let loc = String_with_vars.loc s in
3140
let path = Expander.Or_exn.expand_path expander s in
3241
Result.map path ~f:(fun path ->
3342
let pred =
3443
Glob.of_string_exn loc (Path.basename path) |> Glob.to_pred
3544
in
3645
let dir = Path.parent_exn path in
37-
Action_builder.map ~f:Path.Set.to_list
38-
(File_selector.create ~dir pred |> Action_builder.paths_matching ~loc))
46+
let add_dir dir acc =
47+
let+ paths =
48+
Action_builder.paths_matching ~loc (File_selector.create ~dir pred)
49+
and+ acc = acc in
50+
Path.Set.fold paths ~init:acc ~f:(fun p acc -> p :: acc)
51+
in
52+
let+ files =
53+
let init = Action_builder.return [] in
54+
if recursive then
55+
fold_source_dirs dir ~init ~f:add_dir
56+
else
57+
add_dir dir init
58+
in
59+
List.rev files)
3960
| Source_tree s ->
4061
let path = Expander.Or_exn.expand_path expander s in
4162
Result.map path ~f:(fun path ->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
Tests for (glob_files_rec <dir>/<glob>). This feature is not meat to
2+
be release as it. We plan to replace it by recursive globs for 3.0.0.
3+
4+
$ cat > dune-project <<EOF
5+
> (lang dune 2.9)
6+
> EOF
7+
8+
$ cat > dune <<EOF
9+
> (rule
10+
> (alias x)
11+
> (deps (glob_files_rec foo/*.txt))
12+
> (action (bash "for i in %{deps}; do printf \"\$i\\n\"; done")))
13+
> EOF
14+
15+
$ mkdir -p foo/a/b1/c
16+
$ mkdir -p foo/a/b2/c
17+
$ mkdir -p foo/a/b3/c
18+
19+
$ touch foo/x.txt
20+
$ touch foo/a/x.txt
21+
$ touch foo/a/b1/c/x.txt
22+
$ touch foo/a/b1/c/y.txt
23+
Leave a/b2/c empty to make sure we don't choke on empty dirs.
24+
$ touch foo/a/b3/x.txt
25+
$ touch foo/a/b3/x.other
26+
27+
$ dune build @x
28+
bash alias x
29+
foo/x.txt
30+
foo/a/x.txt
31+
foo/a/b1/c/x.txt
32+
foo/a/b1/c/y.txt
33+
foo/a/b3/x.txt
34+
35+
$ find . -name \*.txt | dune_cmd count-lines
36+
10
37+
$ dune build @x --force 2>&1 | dune_cmd count-lines
38+
6
39+
40+
Check that generated files are taken into account
41+
-------------------------------------------------
42+
43+
$ cat > foo/dune <<EOF
44+
> (rule
45+
> (target gen.txt)
46+
> (action (with-stdout-to %{target} (echo ""))))
47+
> EOF
48+
49+
$ dune build @x --force 2>&1 | grep gen.txt
50+
foo/gen.txt
51+
52+
Check that generated directories are ignored
53+
--------------------------------------------
54+
55+
$ cat > dune <<EOF
56+
> (library
57+
> (name foo))
58+
>
59+
> (rule
60+
> (alias x)
61+
> (deps (glob_files_rec *.cmi))
62+
> (action (bash "for i in %{deps}; do echo \$i; done")))
63+
> EOF
64+
65+
$ touch foo/foo.ml
66+
67+
$ dune build
68+
69+
$ find _build -name \*.cmi
70+
_build/default/.foo.objs/byte/foo.cmi
71+
72+
$ dune build @x
73+

‎test/blackbox-tests/utils/dune_cmd.ml

+31
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,37 @@ module Sanitizer = struct
162162
let () = register name of_args run
163163
end
164164

165+
module Count_lines = struct
166+
type t =
167+
| Stdin
168+
| File of Path.t
169+
170+
let name = "count-lines"
171+
172+
let count_lines ic =
173+
let rec loop n =
174+
match input_line ic with
175+
| exception End_of_file -> n
176+
| _line -> loop (n + 1)
177+
in
178+
loop 0
179+
180+
let of_args = function
181+
| [] -> Stdin
182+
| [ file ] -> File (Path.of_filename_relative_to_initial_cwd file)
183+
| _ -> raise (Arg.Bad "Usage: dune_arg count-lines <file>")
184+
185+
let run t =
186+
let n =
187+
match t with
188+
| Stdin -> count_lines stdin
189+
| File p -> Io.with_file_in p ~binary:false ~f:count_lines
190+
in
191+
Printf.printf "%d\n%!" n
192+
193+
let () = register name of_args run
194+
end
195+
165196
let () =
166197
let name, args =
167198
match Array.to_list Sys.argv with

0 commit comments

Comments
 (0)
Please sign in to comment.