feat(rule): chain rules and depend on the tool they run

This commit is contained in:
milner committed 2022-08-04 15:59:54 +00:00
1 parent dc2f3f52fb
commit a96db02e25
2 files changed
+34 -23

No files matched your search

+2 -2
View File
@@ -113,8 +113,8 @@ let of_project p =
(fun r -> (fun r ->
let cmd = Array.of_list r.rcmd in let cmd = Array.of_list r.rcmd in
(* a tool the rule runs is an input like any other, so building it first is (* a tool the rule runs is an input like any other, so building it first is
ordering and rebuilding it is invalidation *) ordering and rebuilding it is invalidation; a script is already a file *)
let tools = List.filter_map (fun u -> Option.map (out_of p) (find p u)) r.ruses in let tools = List.map (fun u -> match find p u with Some t -> out_of p t | None -> u) r.ruses in
add add
(Graph.make ~id:!n ~tag:"gen" ~label:r.rdesc ~cmd ~outs:r.routs ~ins:(r.rin @ tools) ())) (Graph.make ~id:!n ~tag:"gen" ~label:r.rdesc ~cmd ~outs:r.routs ~ins:(r.rin @ tools) ()))
p.rules; p.rules;
+32 -21
View File
@@ -42,24 +42,30 @@ let subst table s =
done; done;
Buffer.contents b Buffer.contents b
(* Rules are read in written order, the way checks are, so a later rule can glob
what an earlier one produces and a pipeline can be spelled out in stages. *)
let rules_of blocks = let rules_of blocks =
List.concat_map let generated = ref [] in
(fun ((b : block), base) -> let of_block ((b : block), base) =
if b.kind <> "rule" then [] if b.kind <> "rule" then []
else begin else begin
check_fields b rule_fields; check_fields b rule_fields;
let inputs = texts (get b "inputs") in let inputs = texts (get b "inputs") in
let outputs = texts (get b "outputs") in let outputs = texts (get b "outputs") in
let command = texts (get b "command") in let command = texts (get b "command") in
let descr = Option.value (get1 b "description") ~default:("gen " ^ b.bname) in let descr = Option.value (get1 b "description") ~default:("gen " ^ b.bname) in
if outputs = [] then Diag.error ~span:b.nspan "rule %s declares no outputs" b.bname; if outputs = [] then Diag.error ~span:b.nspan "rule %s declares no outputs" b.bname;
if command = [] then Diag.error ~span:b.nspan "rule %s declares no command" b.bname; if command = [] then Diag.error ~span:b.nspan "rule %s declares no command" b.bname;
let files = let files =
List.concat_map (fun p -> Glob.expand (Eval.under base p)) inputs |> List.sort_uniq compare List.concat_map
in (fun p -> Glob.expand_with ~extra:!generated (Eval.under base p))
if files = [] then inputs
Diag.error ~span:b.nspan ~hint:"the inputs pattern matched nothing" |> List.sort_uniq compare
"rule %s has no inputs" b.bname; in
if files = [] then
Diag.error ~span:b.nspan ~hint:"the inputs pattern matched nothing"
"rule %s has no inputs" b.bname;
let rs =
List.map List.map
(fun f -> (fun f ->
let stem = Filename.remove_extension (Filename.basename f) in let stem = Filename.remove_extension (Filename.basename f) in
@@ -82,8 +88,13 @@ let rules_of blocks =
rspan = b.nspan; rspan = b.nspan;
}) })
files files
end) in
blocks generated := !generated @ List.concat_map (fun r -> r.routs) rs;
rs
end
in
(* fold_left, not map: each block must see what the ones before it generated *)
List.rev (List.fold_left (fun acc bb -> List.rev_append (of_block bb) acc) [] blocks)
let target_of pkgs ((b : block), base) = let target_of pkgs ((b : block), base) =
check_fields b target_fields; check_fields b target_fields;
@@ -235,10 +246,10 @@ let project (env : Eval.env) =
(fun (r : rule) -> (fun (r : rule) ->
List.iter List.iter
(fun u -> (fun u ->
if find p u = None then if find p u = None && not (Sys.file_exists u) then
Diag.error ~span:r.rspan Diag.error ~span:r.rspan
~hint:(Suggest.hint u (List.map (fun (x : target) -> x.name) targets)) ~hint:(Suggest.hint u (List.map (fun (x : target) -> x.name) targets))
"rule %s uses %S, which is not a target" r.rname u) "rule %s uses %S, which is neither a target nor a file" r.rname u)
r.ruses) r.ruses)
p.rules; p.rules;
let seen_runs = Hashtbl.create 4 in let seen_runs = Hashtbl.create 4 in