Skip to content

Commit 0f81622

Browse files
committed
More comments and tests
Signed-off-by: Andrey Mokhov <[email protected]>
1 parent 6a017a3 commit 0f81622

File tree

10 files changed

+104
-36
lines changed

10 files changed

+104
-36
lines changed

bin/target.ml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ let target_hint (_setup : Dune_rules.Main.build_system) path =
2121
assert (Path.is_managed path);
2222
let open Memo.Build.O in
2323
let sub_dir = Option.value ~default:path (Path.parent path) in
24+
(* CR-someday amokhov: There are two issues with the code below.
25+
26+
(1) We first get *all* targets but then filter out only those that are
27+
defined in the [sub_dir]. It would be better to just get the targets for
28+
the [sub_dir] directly (the API supports this).
29+
30+
(2) We currently provide the same hint for all targets. It would be nice to
31+
indicate whether a hint corresponds to a file or to a directory target. *)
2432
let+ candidates = Build_system.all_targets () >>| Path.Build.Set.to_list in
2533
let candidates =
2634
if Path.is_in_build_dir path then

src/dune_engine/build_system.ml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1571,9 +1571,13 @@ end = struct
15711571
let action =
15721572
match sandbox with
15731573
| None ->
1574+
(* CR-someday amokhov: It may be possible to support directory targets
1575+
without sandboxing. We just need to make sure we clean up all stale
1576+
directory targets before running the rule and then we can discover
1577+
all created files right in the build directory. *)
15741578
if has_directory_targets then
15751579
User_error.raise ~loc
1576-
[ Pp.text "Rules with directory targets must be sandboxed" ];
1580+
[ Pp.text "Rules with directory targets must be sandboxed." ];
15771581
action
15781582
| Some sandbox -> Action.sandbox action sandbox
15791583
in

src/dune_engine/rule.ml

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -101,28 +101,27 @@ let make ?(sandbox = Sandbox_config.default) ?(mode = Mode.Standard) ~context
101101
(action, deps))
102102
})
103103
in
104+
let report_error ?(extra_pp = []) message =
105+
match info with
106+
| From_dune_file loc ->
107+
let pp = [ Pp.text message ] @ extra_pp in
108+
User_error.raise ~loc pp
109+
| Internal
110+
| Source_file_copy _ ->
111+
Code_error.raise message
112+
[ ("info", Info.to_dyn info); ("targets", Targets.to_dyn targets) ]
113+
in
104114
let dir =
105115
match Targets.validate targets with
106116
| Valid { parent_dir } -> parent_dir
107-
| No_targets -> (
108-
match info with
109-
| From_dune_file loc ->
110-
User_error.raise ~loc [ Pp.text "Rule has no targets specified" ]
111-
| Internal
112-
| Source_file_copy _ ->
113-
Code_error.raise "Rule.Targets: An internal rule with no targets" [])
114-
| Inconsistent_parent_dir -> (
115-
match info with
116-
| From_dune_file loc ->
117-
User_error.raise ~loc
118-
[ Pp.text "Rule has targets in different directories.\nTargets:"
119-
; Targets.pp targets
120-
]
121-
| Internal
122-
| Source_file_copy _ ->
123-
Code_error.raise
124-
"Rule.Targets: An internal rule has targets in different directories"
125-
[ ("targets", Targets.to_dyn targets) ])
117+
| No_targets -> report_error "Rule has no targets specified"
118+
| Inconsistent_parent_dir ->
119+
report_error "Rule has targets in different directories."
120+
~extra_pp:[ Pp.text "Targets:"; Targets.pp targets ]
121+
| File_and_directory_target_with_the_same_name path ->
122+
report_error
123+
(sprintf "%S is declared as both a file and a directory target."
124+
(Dpath.describe_target path))
126125
in
127126
let loc =
128127
match info with

src/dune_engine/rule.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ val hash : t -> int
7676

7777
val to_dyn : t -> Dyn.t
7878

79+
(** [make] raises an error if the set of [targets] is not well-formed. See the
80+
[Targets.Validation_result] for the list of possible problems. *)
7981
val make :
8082
?sandbox:Sandbox_config.t
8183
-> ?mode:Mode.t

src/dune_engine/sandbox_mode.ml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ module Set = struct
8686
; symlink = x.symlink && y.symlink
8787
; hardlink = x.hardlink && y.hardlink
8888
}
89+
90+
let to_dyn (t : t) =
91+
Dyn.Record
92+
[ ("none", Dyn.Bool t.none)
93+
; ("copy", Dyn.Bool t.copy)
94+
; ("symlink", Dyn.Bool t.symlink)
95+
; ("hardlink", Dyn.Bool t.hardlink)
96+
]
8997
end
9098

9199
(* these should be listed in the default order of preference *)

src/dune_engine/sandbox_mode.mli

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
(** This module describes the method used to sandbox actions. Choices include:
44
5-
- not sandboxing - sandboxing by symlinking dependencies - sandboxing by
6-
copying dependencies *)
5+
- not sandboxing
6+
- sandboxing by symlinking dependencies
7+
- sandboxing by copying dependencies
8+
- sandboxing by hardlinking dependencies *)
79

810
open! Stdune
911

@@ -49,6 +51,8 @@ module Set : sig
4951
val mem : t -> key -> bool
5052

5153
val inter : t -> t -> t
54+
55+
val to_dyn : t -> Dyn.t
5256
end
5357

5458
val all : t list

src/dune_engine/targets.ml

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ let to_dyn { files; dirs } =
5151
let pp { files; dirs } =
5252
Pp.enumerate
5353
(Path.Build.Set.to_list files @ Path.Build.Set.to_list dirs)
54-
~f:(fun target -> Pp.text (Dpath.describe_path (Path.build target)))
54+
~f:(fun target -> Pp.text (Dpath.describe_target target))
5555

5656
let exists { files; dirs } ~f =
5757
Path.Build.Set.exists files ~f || Path.Build.Set.exists dirs ~f
@@ -75,15 +75,19 @@ module Validation_result = struct
7575
| Valid of { parent_dir : Path.Build.t }
7676
| No_targets
7777
| Inconsistent_parent_dir
78+
| File_and_directory_target_with_the_same_name of Path.Build.t
7879
end
7980

8081
let validate t =
8182
match is_empty t with
8283
| true -> Validation_result.No_targets
8384
| false -> (
84-
let parent_dir = Path.Build.parent_exn (head_exn t) in
85-
match
86-
exists t ~f:(fun path -> Path.Build.(parent_exn path <> parent_dir))
87-
with
88-
| true -> Inconsistent_parent_dir
89-
| false -> Valid { parent_dir })
85+
match Path.Build.Set.inter t.files t.dirs |> Path.Build.Set.choose with
86+
| Some path -> File_and_directory_target_with_the_same_name path
87+
| None -> (
88+
let parent_dir = Path.Build.parent_exn (head_exn t) in
89+
match
90+
exists t ~f:(fun path -> Path.Build.(parent_exn path <> parent_dir))
91+
with
92+
| true -> Inconsistent_parent_dir
93+
| false -> Valid { parent_dir }))

src/dune_engine/targets.mli

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ module Validation_result : sig
3535
| Valid of { parent_dir : Path.Build.t }
3636
| No_targets
3737
| Inconsistent_parent_dir
38+
| File_and_directory_target_with_the_same_name of Path.Build.t
3839
end
3940

40-
(** Ensure that the set of targets is non-empty and that all targets have the
41-
same parent dir. *)
41+
(** Ensure that the set of targets is well-formed. *)
4242
val validate : t -> Validation_result.t
4343

4444
(** The "head" target if [t] is non-empty. If [t] contains at least one file,

src/dune_rules/simple_rules.ml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,20 @@ end
1818
let interpret_locks ~expander =
1919
Memo.Build.List.map ~f:(Expander.No_deps.expand_path expander)
2020

21-
let check_filename =
21+
let check_filename ~kind =
2222
let not_in_dir ~error_loc s =
2323
User_error.raise ~loc:error_loc
24-
[ Pp.textf "%s does not denote a file in the current directory" s ]
24+
[ (match kind with
25+
| Targets_spec.Kind.File ->
26+
Pp.textf "%S does not denote a file in the current directory." s
27+
| Directory ->
28+
Pp.textf "Directory targets must have exactly one path component.")
29+
]
2530
in
2631
fun ~error_loc ~dir -> function
2732
| Value.String ("." | "..") ->
2833
User_error.raise ~loc:error_loc
29-
[ Pp.text "'.' and '..' are not valid filenames" ]
34+
[ Pp.text "'.' and '..' are not valid targets" ]
3035
| String s ->
3136
if Filename.dirname s <> Filename.current_dir_name then
3237
not_in_dir ~error_loc s;
@@ -84,7 +89,7 @@ let user_rule sctx ?extra_bindings ~dir ~expander (rule : Rule.t) =
8489
[ x ]
8590
| Multiple -> Expander.No_deps.expand expander ~mode:Many target)
8691
>>| List.map ~f:(fun value ->
87-
(check_filename ~dir ~error_loc value, kind)))
92+
(check_filename ~kind ~dir ~error_loc value, kind)))
8893
in
8994
Targets_spec.Static { multiplicity; targets }
9095
in

test/blackbox-tests/test-cases/directory-targets.t/run.t

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Directory targets are not allowed for non-sandboxed rules.
3131
1 | (rule
3232
2 | (targets (dir output))
3333
3 | (action (bash "true")))
34-
Error: Rules with directory targets must be sandboxed
34+
Error: Rules with directory targets must be sandboxed.
3535
[1]
3636

3737
Ensure directory targets are produced.
@@ -388,3 +388,37 @@ Directory target whose name conflicts with an internal directory used by Dune.
388388
an internal directory used by Dune. Please use a different name.
389389
-> required by _build/default/.dune/hello
390390
[1]
391+
392+
Multi-component target directories are not allowed.
393+
394+
$ cat > dune <<EOF
395+
> (rule
396+
> (deps (sandbox always))
397+
> (targets (dir output/subdir))
398+
> (action (bash "mkdir output; echo x > output/x; echo y > output/y")))
399+
> EOF
400+
401+
$ dune build output/x
402+
File "dune", line 3, characters 16-29:
403+
3 | (targets (dir output/subdir))
404+
^^^^^^^^^^^^^
405+
Error: Directory targets must have exactly one path component.
406+
[1]
407+
408+
File and directory target with the same name.
409+
410+
$ cat > dune <<EOF
411+
> (rule
412+
> (deps (sandbox always))
413+
> (targets output (dir output))
414+
> (action (bash "mkdir output; echo x > output/x; echo y > output/y")))
415+
> EOF
416+
417+
$ dune build output/x
418+
File "dune", line 1, characters 0-135:
419+
1 | (rule
420+
2 | (deps (sandbox always))
421+
3 | (targets output (dir output))
422+
4 | (action (bash "mkdir output; echo x > output/x; echo y > output/y")))
423+
Error: "output" is declared as both a file and a directory target.
424+
[1]

0 commit comments

Comments
 (0)