Skip to content

Commit 08114d5

Browse files
committed
Create bash to unify directory targets unique
1 parent 0cc9679 commit 08114d5

File tree

1 file changed

+98
-40
lines changed

1 file changed

+98
-40
lines changed

src/dune_rules/odoc.ml

Lines changed: 98 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -905,10 +905,15 @@ let out_files ctx (output : Output_format.t) odocs =
905905
;;
906906

907907
let add_format_alias_deps ctx format target odocs =
908-
let paths = out_files ctx format odocs in
909-
Rules.Produce.Alias.add_deps
910-
(Dep.format_alias format ctx target)
911-
(Action_builder.paths paths)
908+
match (format : Output_format.t) with
909+
| Markdown ->
910+
(* For markdown, skip intermediate aliases since package directories are directory targets *)
911+
Memo.return ()
912+
| Html | Json ->
913+
let paths = out_files ctx format odocs in
914+
Rules.Produce.Alias.add_deps
915+
(Dep.format_alias format ctx target)
916+
(Action_builder.paths paths)
912917
;;
913918

914919
let setup_lib_html_rules_def =
@@ -1010,7 +1015,15 @@ let setup_pkg_html_rules sctx ~pkg : unit Memo.t =
10101015
let setup_lib_markdown_rules sctx lib =
10111016
let target = Lib lib in
10121017
let* odocs = odoc_artefacts sctx target in
1013-
let* () = Memo.parallel_iter odocs ~f:(fun odoc -> setup_generate_markdown sctx odoc) in
1018+
(* For libraries WITH a package, generation happens in the package-level rule.
1019+
Only generate for libraries WITHOUT a package. *)
1020+
let* () =
1021+
match Lib_info.package (Lib.Local.info lib) with
1022+
| Some _ -> Memo.return () (* Package-level rule handles it *)
1023+
| None ->
1024+
(* No package, so we need individual rules *)
1025+
Memo.parallel_iter odocs ~f:(fun odoc -> setup_generate_markdown sctx odoc)
1026+
in
10141027
Memo.With_implicit_output.exec setup_lib_markdown_rules_def (sctx, lib)
10151028
;;
10161029

@@ -1023,8 +1036,45 @@ let setup_pkg_markdown_rules_def =
10231036
Memo.List.concat_map libs ~f:(fun lib -> odoc_artefacts sctx (Lib lib))
10241037
in
10251038
let all_odocs = pkg_odocs @ lib_odocs in
1039+
(* Generate ALL markdown for this package in ONE rule with directory target.
1040+
Since odoc generates unpredictable files (Belt.md, Belt-Array.md, Belt-List.md, etc.)
1041+
from nested submodules, we must use a directory target and batch all odoc commands. *)
1042+
let* () =
1043+
if List.is_empty all_odocs
1044+
then Memo.return ()
1045+
else
1046+
let pkg_markdown_dir = Paths.markdown ctx (Pkg pkg) in
1047+
let markdown_root = Paths.markdown_root ctx in
1048+
let rule =
1049+
let bash_cmd_args =
1050+
let open Action_builder.O in
1051+
let* odoc_prog = odoc_program sctx (Context.build_dir ctx) in
1052+
let odoc_path = Action.Prog.ok_exn odoc_prog |> Path.to_string in
1053+
let bash_cmd =
1054+
List.map all_odocs ~f:(fun odoc ->
1055+
let odocl_rel = Path.reach (Path.build odoc.odocl_file) ~from:(Path.build markdown_root) in
1056+
Printf.sprintf "%s markdown-generate -o . %s" odoc_path odocl_rel)
1057+
|> String.concat ~sep:" && "
1058+
in
1059+
let* () =
1060+
List.map all_odocs ~f:(fun odoc -> Action_builder.path (Path.build odoc.odocl_file))
1061+
|> Action_builder.all
1062+
>>| ignore
1063+
in
1064+
Action_builder.return (Command.Args.S [ A "-c"; A bash_cmd ])
1065+
in
1066+
let deps = Action_builder.env_var "ODOC_SYNTAX" in
1067+
let open Action_builder.With_targets.O in
1068+
Action_builder.with_no_targets deps
1069+
>>> Command.run
1070+
~dir:(Path.build markdown_root)
1071+
(Ok (Path.of_string "/bin/bash"))
1072+
[ Dyn bash_cmd_args ]
1073+
|> Action_builder.With_targets.add_directories ~directory_targets:[ pkg_markdown_dir ]
1074+
in
1075+
add_rule sctx rule
1076+
in
10261077
let* () = Memo.parallel_iter libs ~f:(setup_lib_markdown_rules sctx) in
1027-
let* () = Memo.parallel_iter pkg_odocs ~f:(setup_generate_markdown sctx) in
10281078
add_format_alias_deps ctx Markdown (Pkg pkg) all_odocs
10291079
in
10301080
setup_pkg_rules_def "setup-package-markdown-rules" f
@@ -1045,11 +1095,24 @@ let setup_package_aliases_format sctx (pkg : Package.t) (output : Output_format.
10451095
let* libs =
10461096
Context.name ctx |> libs_of_pkg ~pkg:name >>| List.map ~f:(fun lib -> Lib lib)
10471097
in
1048-
Pkg name :: libs
1049-
|> List.map ~f:(Dep.format_alias output ctx)
1050-
|> Dune_engine.Dep.Set.of_list_map ~f:(fun f -> Dune_engine.Dep.alias f)
1051-
|> Action_builder.deps
1052-
|> Rules.Produce.Alias.add_deps alias
1098+
let deps =
1099+
match (output : Output_format.t) with
1100+
| Markdown ->
1101+
(* For markdown, depend on:
1102+
1. The package directory target (contains all module .md files)
1103+
2. The toplevel index (so it gets built as part of @doc-markdown) *)
1104+
let pkg_markdown_dir = Paths.markdown ctx (Pkg name) in
1105+
let index_path = Paths.markdown_index ctx in
1106+
let open Action_builder.O in
1107+
let* () = Action_builder.path (Path.build pkg_markdown_dir) in
1108+
Action_builder.path (Path.build index_path)
1109+
| Html | Json ->
1110+
Pkg name :: libs
1111+
|> List.map ~f:(Dep.format_alias output ctx)
1112+
|> Dune_engine.Dep.Set.of_list_map ~f:(fun f -> Dune_engine.Dep.alias f)
1113+
|> Action_builder.deps
1114+
in
1115+
Rules.Produce.Alias.add_deps alias deps
10531116
;;
10541117

10551118
let setup_package_aliases sctx (pkg : Package.t) =
@@ -1185,36 +1248,31 @@ let gen_rules sctx ~dir rest =
11851248
>>> setup_css_rule sctx
11861249
>>> setup_toplevel_index_rule sctx Html
11871250
>>> setup_toplevel_index_rule sctx Json)
1188-
| [ "_markdown" ] -> has_rules (setup_toplevel_index_rule sctx Markdown)
1189-
| [ "_markdown"; lib_unique_name_or_pkg ] ->
1251+
| [ "_markdown" ] ->
1252+
(* Generate all markdown and declare package directories as directory targets *)
1253+
let* packages = Dune_load.packages () in
1254+
let ctx = Super_context.context sctx in
1255+
(* Collect all package directories that will be generated as directory targets *)
1256+
let pkg_dirs =
1257+
Package.Name.Map.to_list packages
1258+
|> List.map ~f:(fun (_, (pkg : Package.t)) ->
1259+
let pkg_name = Package.name pkg in
1260+
Paths.markdown ctx (Pkg pkg_name))
1261+
in
1262+
let directory_targets =
1263+
List.fold_left pkg_dirs ~init:Path.Build.Map.empty ~f:(fun acc dir ->
1264+
Path.Build.Map.set acc dir Loc.none)
1265+
in
11901266
has_rules
1191-
(
1192-
let ctx = Super_context.context sctx in
1193-
let* lib, lib_db = Scope_key.of_string (Context.name ctx) lib_unique_name_or_pkg in
1194-
let* lib =
1195-
let+ lib = Lib.DB.find lib_db lib in
1196-
Option.bind ~f:Lib.Local.of_lib lib
1197-
in
1198-
let+ () =
1199-
match lib with
1200-
| None -> Memo.return ()
1201-
| Some lib ->
1202-
(match Lib_info.package (Lib.Local.info lib) with
1203-
| None ->
1204-
(* lib with no package above it *)
1205-
setup_lib_markdown_rules sctx lib
1206-
| Some pkg -> setup_pkg_markdown_rules sctx ~pkg)
1207-
and+ () =
1208-
let* packages = Dune_load.packages () in
1209-
match
1210-
Package.Name.Map.find packages (Package.Name.of_string lib_unique_name_or_pkg)
1211-
with
1212-
| None -> Memo.return ()
1213-
| Some pkg ->
1214-
let name = Package.name pkg in
1215-
setup_pkg_markdown_rules sctx ~pkg:name
1216-
in
1217-
())
1267+
~directory_targets
1268+
(let* () = setup_toplevel_index_rule sctx Markdown in
1269+
Package.Name.Map.to_seq packages
1270+
|> Memo.parallel_iter_seq ~f:(fun (_, (pkg : Package.t)) ->
1271+
let pkg_name = Package.name pkg in
1272+
setup_pkg_markdown_rules sctx ~pkg:pkg_name))
1273+
| [ "_markdown"; _lib_unique_name_or_pkg ] ->
1274+
(* Package directories are directory targets, no rules here *)
1275+
Memo.return Gen_rules.no_rules
12181276
| [ "_mlds"; pkg ] ->
12191277
with_package pkg ~f:(fun pkg ->
12201278
let pkg = Package.name pkg in

0 commit comments

Comments
 (0)