My aggregated monorepo of OCaml code, automaintained
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

day11/doc: extract stateless Doc_build primitives

New module Doc_build with clean, stateless per-package doc operations:
- compile: build layer + dep compile layers → compile layer
- link: compile layer + dep compile layers → HTML
- doc_all: build layer + dep compile layers → compile layer + HTML
- has_documentable_libs: check if a layer has installed libraries

Each function takes explicit inputs (layer paths, tool config, blessed
status) and returns a result. No hashtables, no DAG knowledge, no
shared mutable state. These are building blocks suitable for both the
existing DAG executor and potential OCurrent pipeline integration.

generate.ml's compile_package/link_package/doc_all_package become thin
wrappers that extract state from the DAG context and delegate to
Doc_build. Old helper functions (prepare_package, make_doc_mounts,
doc_prep_upper, doc_cleanup) moved into Doc_build.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+347 -236
+193
day11/doc/doc_build.ml
··· 1 + module Build = Day11_opam_layer.Build 2 + module Installed_files = Day11_opam_layer.Installed_files 3 + 4 + let odoc_bin = "/home/opam/doc-tools/bin/odoc" 5 + let odoc_md_bin = "/home/opam/doc-tools/bin/odoc-md" 6 + 7 + type doc_config = { 8 + driver_tool : Day11_opam_layer.Tool.t; 9 + odoc_tool : Day11_opam_layer.Tool.t; 10 + os_dir : Fpath.t; 11 + blessed : bool; 12 + } 13 + 14 + let has_documentable_libs layer_dir = 15 + Installed_files.scan_libs ~layer_dir <> [] 16 + 17 + (** Create tool binary mounts from driver and odoc tools. *) 18 + let make_tool_mounts ~os_dir ~(driver_tool : Day11_opam_layer.Tool.t) 19 + ~(odoc_tool : Day11_opam_layer.Tool.t) = 20 + let find name builds = 21 + let switch = Day11_opam_build.Types.switch in 22 + match List.find_map (fun (bl : Build.t) -> 23 + let bin = Fpath.(Build.dir ~os_dir bl / "fs" / "home" / "opam" 24 + / ".opam" / switch / "bin" / name) in 25 + if Bos.OS.File.exists bin |> Result.get_ok then Some bin 26 + else None 27 + ) builds with 28 + | Some p -> p 29 + | None -> failwith (Printf.sprintf "Doc tool binary %s not found" name) 30 + in 31 + let mount src dst = Day11_container.Mount.bind_ro 32 + ~src:(Fpath.to_string src) dst in 33 + [ mount (find "odoc" odoc_tool.builds) "/home/opam/doc-tools/bin/odoc"; 34 + mount (find "odoc-md" driver_tool.builds) "/home/opam/doc-tools/bin/odoc-md"; 35 + mount (find "odoc_driver_voodoo" driver_tool.builds) 36 + "/home/opam/doc-tools/bin/odoc_driver_voodoo"; 37 + mount (find "sherlodoc" driver_tool.builds) 38 + "/home/opam/doc-tools/bin/sherlodoc" ] 39 + 40 + (** Pre-mount prep for doc containers: create /home/opam/odoc-out and 41 + /home/opam/html mount points, chown to build user. *) 42 + let doc_prep_upper env ~uid ~gid ~upper ~lowers:_ = 43 + let mkdir path = Bos.OS.Dir.create ~path:true path |> ignore in 44 + let odoc_out = Fpath.(upper / "home" / "opam" / "odoc-out") in 45 + let html = Fpath.(upper / "home" / "opam" / "html") in 46 + mkdir odoc_out; mkdir html; 47 + ignore (Day11_exec.Sudo.run env 48 + Bos.Cmd.(v "chown" % Printf.sprintf "%d:%d" uid gid 49 + % Fpath.to_string odoc_out % Fpath.to_string html)) 50 + 51 + let doc_cleanup _env upper = 52 + ignore (Day11_exec.Sudo.rm_rf _env 53 + Fpath.(upper / "home" / "opam" / "doc-tools")) 54 + 55 + (** Set up the prep structure and mounts for a doc container. 56 + Returns (universe, mounts, prep_dir) or None if the package 57 + has no documentable libs. Caller must clean up prep_dir. *) 58 + let prepare ~(config : doc_config) ~build_layer pkg = 59 + let installed_libs = Installed_files.scan_libs ~layer_dir:build_layer in 60 + if installed_libs = [] then None 61 + else 62 + let installed_docs = Installed_files.scan_docs ~layer_dir:build_layer in 63 + let universe = Command.compute_universe_hash 64 + [ Fpath.basename build_layer ] in 65 + let tool_mounts = make_tool_mounts ~os_dir:config.os_dir 66 + ~driver_tool:config.driver_tool ~odoc_tool:config.odoc_tool in 67 + let prep_dir = Bos.OS.Dir.tmp "day11_doc_%s" |> Result.get_ok in 68 + match Prep.create_with_mounts ~source_layer_dir:build_layer 69 + ~dest_layer_dir:prep_dir ~universe ~pkg 70 + ~installed_libs ~installed_docs with 71 + | Ok (_prep_root, lib_mounts) -> 72 + let prep_mount = Day11_container.Mount.bind_ro 73 + ~src:(Fpath.to_string Fpath.(prep_dir / "prep")) 74 + "/home/opam/prep" in 75 + let mounts = tool_mounts @ [ prep_mount ] @ lib_mounts in 76 + Some (universe, mounts, prep_dir) 77 + | Error _ -> None 78 + 79 + let compile env benv ~(config : doc_config) ~build_layer 80 + ~dep_compile_layers ~hash pkg = 81 + match prepare ~config ~build_layer pkg with 82 + | None -> Error "no documentable libraries" 83 + | Some (universe, mounts, prep_dir) -> 84 + let blessed = config.blessed in 85 + let cmd = 86 + "export PATH=/home/opam/doc-tools/bin:$PATH && eval $(opam env) && " ^ 87 + Command.odoc_driver_voodoo ~pkg ~universe 88 + ~blessed ~actions:"compile-only" ~odoc_bin ~odoc_md_bin in 89 + let compile_node : Build.t = 90 + { hash; pkg; deps = []; 91 + universe = Day11_solution.Universe.dummy } in 92 + let on_extract ~layer_dir ~success:_ = 93 + let dm : Doc_meta.t = { 94 + package = OpamPackage.to_string pkg; 95 + phase = Doc_meta.Compile; 96 + deps = []; 97 + } in 98 + ignore (Doc_meta.save layer_dir dm) 99 + in 100 + let result = 101 + match Day11_opam_build.Build_layer.build env benv 102 + ~mounts ~build_dirs:dep_compile_layers 103 + ~prep_upper:(doc_prep_upper env ~uid:benv.uid ~gid:benv.gid) 104 + ~on_extract compile_node 105 + ~strategy:{ cmd; cleanup = doc_cleanup } () with 106 + | Day11_opam_build.Types.Success _bl -> 107 + Ok (Day11_opam_layer.Build.dir ~os_dir:config.os_dir compile_node) 108 + | _ -> 109 + Error (Printf.sprintf "compile failed for %s" 110 + (OpamPackage.to_string pkg)) 111 + in 112 + ignore (Day11_exec.Sudo.rm_rf env prep_dir); 113 + result 114 + 115 + let link env benv ~(config : doc_config) ~build_layer 116 + ~compile_layer ~dep_compile_layers ~html_dir ~hash pkg = 117 + match prepare ~config ~build_layer pkg with 118 + | None -> Error "no documentable libraries" 119 + | Some (universe, mounts, prep_dir) -> 120 + let blessed = config.blessed in 121 + let all_compile_dirs = compile_layer :: dep_compile_layers in 122 + let html_mount = Day11_container.Mount.bind_rw 123 + ~src:(Fpath.to_string html_dir) 124 + Odoc_store.container_html in 125 + let cmd = 126 + "export PATH=/home/opam/doc-tools/bin:$PATH && eval $(opam env) && " ^ 127 + Command.odoc_driver_voodoo ~pkg ~universe 128 + ~blessed ~actions:"link-and-gen" ~odoc_bin ~odoc_md_bin in 129 + let link_node : Build.t = 130 + { hash; pkg; deps = []; 131 + universe = Day11_solution.Universe.dummy } in 132 + let on_extract ~layer_dir ~success:_ = 133 + let dm : Doc_meta.t = { 134 + package = OpamPackage.to_string pkg; 135 + phase = Doc_meta.Link; 136 + deps = []; 137 + } in 138 + ignore (Doc_meta.save layer_dir dm) 139 + in 140 + let result = 141 + match Day11_opam_build.Build_layer.build env benv 142 + ~mounts:(mounts @ [html_mount]) 143 + ~build_dirs:all_compile_dirs 144 + ~prep_upper:(doc_prep_upper env ~uid:benv.uid ~gid:benv.gid) 145 + ~on_extract link_node 146 + ~strategy:{ cmd; cleanup = doc_cleanup } () with 147 + | Day11_opam_build.Types.Success _ -> Ok () 148 + | _ -> 149 + Error (Printf.sprintf "link failed for %s" 150 + (OpamPackage.to_string pkg)) 151 + in 152 + ignore (Day11_exec.Sudo.rm_rf env prep_dir); 153 + result 154 + 155 + let doc_all env benv ~(config : doc_config) ~build_layer 156 + ~dep_compile_layers ~html_dir ~hash pkg = 157 + match prepare ~config ~build_layer pkg with 158 + | None -> Error "no documentable libraries" 159 + | Some (universe, mounts, prep_dir) -> 160 + let blessed = config.blessed in 161 + let html_mount = Day11_container.Mount.bind_rw 162 + ~src:(Fpath.to_string html_dir) 163 + Odoc_store.container_html in 164 + let cmd = 165 + "export PATH=/home/opam/doc-tools/bin:$PATH && eval $(opam env) && " ^ 166 + Command.odoc_driver_voodoo ~pkg ~universe 167 + ~blessed ~actions:"all" ~odoc_bin ~odoc_md_bin in 168 + let doc_node : Build.t = 169 + { hash; pkg; deps = []; 170 + universe = Day11_solution.Universe.dummy } in 171 + let on_extract ~layer_dir ~success:_ = 172 + let dm : Doc_meta.t = { 173 + package = OpamPackage.to_string pkg; 174 + phase = Doc_meta.Doc_all; 175 + deps = []; 176 + } in 177 + ignore (Doc_meta.save layer_dir dm) 178 + in 179 + let result = 180 + match Day11_opam_build.Build_layer.build env benv 181 + ~mounts:(mounts @ [html_mount]) 182 + ~build_dirs:dep_compile_layers 183 + ~prep_upper:(doc_prep_upper env ~uid:benv.uid ~gid:benv.gid) 184 + ~on_extract doc_node 185 + ~strategy:{ cmd; cleanup = doc_cleanup } () with 186 + | Day11_opam_build.Types.Success _bl -> 187 + Ok (Day11_opam_layer.Build.dir ~os_dir:config.os_dir doc_node) 188 + | _ -> 189 + Error (Printf.sprintf "doc-all failed for %s" 190 + (OpamPackage.to_string pkg)) 191 + in 192 + ignore (Day11_exec.Sudo.rm_rf env prep_dir); 193 + result
+78
day11/doc/doc_build.mli
··· 1 + (** Stateless per-package doc build primitives. 2 + 3 + Each function takes explicit inputs (layer directories, tool 4 + directories, package metadata) and produces a result. No shared 5 + mutable state, no DAG knowledge, no hashtable lookups. These are 6 + the building blocks for both the DAG-based batch executor and 7 + potential integration with external pipeline systems like OCurrent. 8 + 9 + All functions follow the same pattern: 10 + - Check preconditions (installed libs, tool availability) 11 + - Set up container mounts and prep structure 12 + - Run odoc_driver_voodoo in a container via Build_layer.build 13 + - Return the resulting layer directory or None on failure *) 14 + 15 + type doc_config = { 16 + driver_tool : Day11_opam_layer.Tool.t; 17 + odoc_tool : Day11_opam_layer.Tool.t; 18 + os_dir : Fpath.t; 19 + blessed : bool; 20 + } 21 + (** Static configuration for a doc build. The tools and blessed status 22 + are determined before execution and don't change across packages 23 + within the same compiler universe. *) 24 + 25 + val compile : 26 + Eio_unix.Stdenv.base -> 27 + Day11_opam_build.Types.build_env -> 28 + config:doc_config -> 29 + build_layer:Fpath.t -> 30 + dep_compile_layers:Fpath.t list -> 31 + hash:string -> 32 + OpamPackage.t -> 33 + (Fpath.t, string) result 34 + (** [compile env benv ~config ~build_layer ~dep_compile_layers ~hash pkg] 35 + runs the odoc compile phase for [pkg]. Reads source [.cmti] files from 36 + [build_layer], stacks [dep_compile_layers] for cross-reference 37 + resolution, and produces a compile layer at [os_dir/<hash>/]. 38 + 39 + Returns [Ok layer_dir] on success, [Error msg] on failure. *) 40 + 41 + val link : 42 + Eio_unix.Stdenv.base -> 43 + Day11_opam_build.Types.build_env -> 44 + config:doc_config -> 45 + build_layer:Fpath.t -> 46 + compile_layer:Fpath.t -> 47 + dep_compile_layers:Fpath.t list -> 48 + html_dir:Fpath.t -> 49 + hash:string -> 50 + OpamPackage.t -> 51 + (unit, string) result 52 + (** [link env benv ~config ~build_layer ~compile_layer 53 + ~dep_compile_layers ~html_dir ~hash pkg] runs the odoc link phase 54 + for [pkg]. Reads [.odoc] files from [compile_layer] and 55 + [dep_compile_layers], writes HTML to [html_dir]. 56 + 57 + Returns [Ok ()] on success. The link layer itself is ephemeral — 58 + only the HTML output matters. *) 59 + 60 + val doc_all : 61 + Eio_unix.Stdenv.base -> 62 + Day11_opam_build.Types.build_env -> 63 + config:doc_config -> 64 + build_layer:Fpath.t -> 65 + dep_compile_layers:Fpath.t list -> 66 + html_dir:Fpath.t -> 67 + hash:string -> 68 + OpamPackage.t -> 69 + (Fpath.t, string) result 70 + (** [doc_all env benv ~config ~build_layer ~dep_compile_layers 71 + ~html_dir ~hash pkg] runs compile + link + HTML generation in a 72 + single container invocation. Returns the compile layer directory 73 + (which contains the [.odoc] output for use by dependents). *) 74 + 75 + val has_documentable_libs : 76 + Fpath.t -> bool 77 + (** [has_documentable_libs layer_dir] returns true if the build layer 78 + has installed libraries that can be documented. *)
+76 -236
day11/doc/generate.ml
··· 1 - open Day11_opam_layer 2 1 module Build = Day11_opam_layer.Build 3 2 module Tool = Day11_opam_layer.Tool 4 - (* Doc_meta is now part of this library *) 3 + module Installed_files = Day11_opam_layer.Installed_files 5 4 6 - (* Local aliases so the existing code reads naturally. *) 7 5 type build = Build.t 8 - type tool = Tool.t 9 6 10 7 let concrete_compiler_names = List.map OpamPackage.Name.of_string 11 8 [ "ocaml-base-compiler"; "ocaml-variants"; "ocaml-system" ] ··· 21 18 else None 22 19 ) solution None 23 20 24 - let extract_bin ~os_dir tool_builds name = 25 - let switch = Day11_opam_build.Types.switch in 26 - List.find_map (fun (bl : build) -> 27 - let bin = Fpath.(Build.dir ~os_dir bl / "fs" / "home" / "opam" 28 - / ".opam" / switch / "bin" / name) in 29 - if Bos.OS.File.exists bin |> Result.get_ok then Some bin 30 - else None 31 - ) tool_builds 32 - 33 - let make_doc_mounts ~os_dir ~(driver_tool : tool) ~(odoc_tool : tool) = 34 - let find name builds = 35 - match extract_bin ~os_dir builds name with 36 - | Some p -> p 37 - | None -> failwith (Printf.sprintf "Doc tool binary %s not found" name) 38 - in 39 - let mount src dst = Day11_container.Mount.bind_ro 40 - ~src:(Fpath.to_string src) dst in 41 - [ mount (find "odoc" odoc_tool.builds) "/home/opam/doc-tools/bin/odoc"; 42 - mount (find "odoc-md" driver_tool.builds) "/home/opam/doc-tools/bin/odoc-md"; 43 - mount (find "odoc_driver_voodoo" driver_tool.builds) 44 - "/home/opam/doc-tools/bin/odoc_driver_voodoo"; 45 - mount (find "sherlodoc" driver_tool.builds) 46 - "/home/opam/doc-tools/bin/sherlodoc" ] 47 - 48 - let doc_cleanup _env upper = 49 - ignore (Day11_exec.Sudo.rm_rf _env 50 - Fpath.(upper / "home" / "opam" / "doc-tools")) 51 - 52 - (** Pre-mount prep for an odoc doc container. The container has 53 - bind mounts at [/home/opam/odoc-out] and [/home/opam/html] for 54 - its output, and runc requires those mount points to exist 55 - inside the merged rootfs. We mkdir them in the upper before 56 - mounting and chown them to the build user. No opam switch-state 57 - is needed — doc containers don't run [opam install]. *) 58 - let doc_prep_upper env ~uid ~gid ~upper ~lowers:_ = 59 - let mkdir path = Bos.OS.Dir.create ~path:true path |> ignore in 60 - let odoc_out = Fpath.(upper / "home" / "opam" / "odoc-out") in 61 - let html = Fpath.(upper / "home" / "opam" / "html") in 62 - mkdir odoc_out; mkdir html; 63 - ignore (Day11_exec.Sudo.run env 64 - Bos.Cmd.(v "chown" % Printf.sprintf "%d:%d" uid gid 65 - % Fpath.to_string odoc_out % Fpath.to_string html)) 66 - 67 - let odoc_bin = "/home/opam/doc-tools/bin/odoc" 68 - let odoc_md_bin = "/home/opam/doc-tools/bin/odoc-md" 69 - 70 21 (** Collect transitive build dep hashes into a seen set. *) 71 22 let collect_transitive_deps (seen : (string, unit) Hashtbl.t) 72 23 (node : Build.t) = ··· 78 29 in 79 30 walk node 80 31 32 + (* Thin wrappers that extract DAG state and delegate to Doc_build primitives *) 81 33 82 - (** Prepare mounts and metadata for a doc container. 83 - Returns None if the package has no installed libs or no matching 84 - odoc tool. Caller must clean up [prep_dir] after use. *) 85 - let prepare_package ~os_dir ~(driver_tool : Tool.t) ~odoc_tools:_ ~build_hash_blessed 86 - ~find_odoc_tool (node : build) = 87 - let pkg_dir = Build.dir ~os_dir node in 88 - let installed_libs = Installed_files.scan_libs 89 - ~layer_dir:pkg_dir in 90 - if installed_libs = [] then None 91 - else match find_odoc_tool node.pkg with 34 + let compile_package env benv ~os_dir ~find_odoc_tool ~build_hash_blessed 35 + ~driver_tool ~compile_results ~dag_hash (node : build) = 36 + let blessed = match Hashtbl.find_opt build_hash_blessed node.hash with 37 + | Some true -> true | _ -> false in 38 + match find_odoc_tool node.pkg with 92 39 | None -> None 93 40 | Some (odoc_tool : Tool.t) -> 94 - let installed_docs = Installed_files.scan_docs 95 - ~layer_dir:pkg_dir in 96 - let composite_tool_hash = Day11_layer.Hash.of_strings 97 - [ driver_tool.hash; odoc_tool.hash ] in 98 - let universe = Command.compute_universe_hash [ node.hash ] in 99 - let doc_mounts = make_doc_mounts ~os_dir ~driver_tool ~odoc_tool in 100 - let blessed = match Hashtbl.find_opt build_hash_blessed node.hash with 101 - | Some true -> true 102 - | _ -> false in 103 - let prep_dir = Bos.OS.Dir.tmp "day11_doc_%s" |> Result.get_ok in 104 - (match Prep.create_with_mounts ~source_layer_dir:pkg_dir 105 - ~dest_layer_dir:prep_dir ~universe ~pkg:node.pkg 106 - ~installed_libs ~installed_docs with 107 - | Ok (_prep_root, lib_mounts) -> 108 - let prep_mount = Day11_container.Mount.bind_ro 109 - ~src:(Fpath.to_string Fpath.(prep_dir / "prep")) 110 - "/home/opam/prep" in 111 - let pkg_loc : Odoc_store.pkg_loc = 112 - { pkg = node.pkg; universe; blessed } in 113 - let mounts = doc_mounts @ [ prep_mount ] @ lib_mounts in 114 - Some (composite_tool_hash, universe, blessed, pkg_loc, mounts, prep_dir) 115 - | Error _ -> None) 116 - 117 - let compile_package env benv ~os_dir ~driver_tool ~odoc_tools 118 - ~build_hash_blessed ~find_odoc_tool ~compile_results 119 - ~dag_hash (node : build) = 120 - match prepare_package ~os_dir ~driver_tool ~odoc_tools 121 - ~build_hash_blessed ~find_odoc_tool node with 122 - | None -> None 123 - | Some (_composite_tool_hash, universe, blessed, _pkg_loc, mounts, prep_dir) -> 124 - (* Collect dep compile layers for overlayfs stacking *) 41 + let config : Doc_build.doc_config = 42 + { driver_tool; odoc_tool; os_dir; blessed } in 43 + let build_layer = Build.dir ~os_dir node in 125 44 let seen = Hashtbl.create 16 in 126 45 List.iter (collect_transitive_deps seen) node.deps; 127 - let dep_compile_dirs = Hashtbl.fold (fun bh () acc -> 46 + let dep_compile_layers = Hashtbl.fold (fun bh () acc -> 128 47 match Hashtbl.find_opt compile_results bh with 129 48 | Some bl -> Build.dir ~os_dir bl :: acc 130 49 | None -> acc 131 50 ) seen [] in 132 - let cmd = 133 - "export PATH=/home/opam/doc-tools/bin:$PATH && eval $(opam env) && " ^ 134 - Command.odoc_driver_voodoo ~pkg:node.pkg ~universe 135 - ~blessed ~actions:"compile-only" ~odoc_bin ~odoc_md_bin in 136 - let compile_node : build = 137 - { hash = dag_hash; pkg = node.pkg; deps = [ node ]; 138 - universe = Day11_solution.Universe.dummy } in 139 - let on_extract ~layer_dir ~success:_ = 140 - let dm : Doc_meta.t = { 141 - package = OpamPackage.to_string node.pkg; 142 - phase = Doc_meta.Compile; 143 - deps = List.map (fun (d : build) -> OpamPackage.to_string d.pkg) compile_node.deps; 144 - } in 145 - ignore (Doc_meta.save layer_dir dm) 146 - in 147 - let result = 148 - match Day11_opam_build.Build_layer.build env benv 149 - ~mounts ~build_dirs:dep_compile_dirs 150 - ~prep_upper:(doc_prep_upper env ~uid:benv.uid ~gid:benv.gid) 151 - ~on_extract 152 - compile_node 153 - ~strategy:{ cmd; cleanup = doc_cleanup } () with 154 - | Day11_opam_build.Types.Success bl -> 155 - Hashtbl.replace compile_results node.hash bl; 156 - Some bl 157 - | _ -> 158 - Printf.printf " %s: compile FAILED\n%!" 159 - (OpamPackage.to_string node.pkg); 160 - None 161 - in 162 - ignore (Day11_exec.Sudo.rm_rf env prep_dir); 163 - result 51 + match Doc_build.compile env benv ~config ~build_layer 52 + ~dep_compile_layers ~hash:dag_hash node.pkg with 53 + | Ok _layer_dir -> 54 + let compile_node : build = 55 + { hash = dag_hash; pkg = node.pkg; deps = [ node ]; 56 + universe = Day11_solution.Universe.dummy } in 57 + Hashtbl.replace compile_results node.hash compile_node; 58 + Some compile_node 59 + | Error msg -> 60 + Printf.printf " %s: compile FAILED (%s)\n%!" 61 + (OpamPackage.to_string node.pkg) msg; 62 + None 164 63 165 - let link_package env benv ~os_dir ~driver_tool ~odoc_tools 166 - ~build_hash_blessed ~find_odoc_tool ~compile_results 167 - ~doc_dep_hashes 168 - ~build_hash ~dag_hash 169 - (node : build) = 170 - match Hashtbl.find_opt compile_results build_hash with 171 - | None -> None 172 - | Some compile_bl -> 173 - match prepare_package ~os_dir ~driver_tool ~odoc_tools 174 - ~build_hash_blessed ~find_odoc_tool node with 175 - | None -> None 176 - | Some (_composite_tool_hash, universe, blessed, _pkg_loc, mounts, prep_dir) -> 177 - (* Collect compile layers from doc_deps (wider set) *) 64 + let link_package env benv ~os_dir ~find_odoc_tool ~build_hash_blessed 65 + ~driver_tool ~compile_results ~doc_dep_hashes 66 + ~build_hash ~dag_hash (node : build) = 67 + let blessed = match Hashtbl.find_opt build_hash_blessed node.hash with 68 + | Some true -> true | _ -> false in 69 + match find_odoc_tool node.pkg, Hashtbl.find_opt compile_results build_hash with 70 + | None, _ | _, None -> None 71 + | Some (odoc_tool : Tool.t), Some compile_bl -> 72 + let config : Doc_build.doc_config = 73 + { driver_tool; odoc_tool; os_dir; blessed } in 74 + let build_layer = Build.dir ~os_dir node in 75 + let compile_layer = Build.dir ~os_dir compile_bl in 178 76 let doc_dep_bhs = match Hashtbl.find_opt doc_dep_hashes build_hash with 179 77 | Some bhs -> bhs | None -> [] in 180 - let dep_compile_dirs = List.filter_map (fun bh -> 78 + let dep_compile_layers = List.filter_map (fun bh -> 181 79 match Hashtbl.find_opt compile_results bh with 182 80 | Some bl -> Some (Build.dir ~os_dir bl) 183 81 | None -> None 184 82 ) doc_dep_bhs in 185 - (* Also include own compile layer *) 186 - let own_compile_dir = match Hashtbl.find_opt compile_results build_hash with 187 - | Some bl -> [ Build.dir ~os_dir bl ] 188 - | None -> [] in 189 - let all_compile_dirs = own_compile_dir @ dep_compile_dirs in 190 - (* HTML RW mount — entire html dir *) 191 - let html_base = Fpath.(os_dir / "html") in 192 - let html_mount = Day11_container.Mount.bind_rw 193 - ~src:(Fpath.to_string html_base) 194 - Odoc_store.container_html in 195 - let cmd = 196 - "export PATH=/home/opam/doc-tools/bin:$PATH && eval $(opam env) && " ^ 197 - Command.odoc_driver_voodoo ~pkg:node.pkg ~universe 198 - ~blessed ~actions:"link-and-gen" ~odoc_bin ~odoc_md_bin in 199 - let link_node : build = 200 - { hash = dag_hash; pkg = node.pkg; 201 - deps = [ node; compile_bl ]; 202 - universe = Day11_solution.Universe.dummy } in 203 - let on_extract ~layer_dir ~success:_ = 204 - let dm : Doc_meta.t = { 205 - package = OpamPackage.to_string node.pkg; 206 - phase = Doc_meta.Link; 207 - deps = List.map (fun (d : build) -> OpamPackage.to_string d.pkg) link_node.deps; 208 - } in 209 - ignore (Doc_meta.save layer_dir dm) 210 - in 211 - let result = 212 - match Day11_opam_build.Build_layer.build env benv 213 - ~mounts:(mounts @ [html_mount]) ~build_dirs:all_compile_dirs 214 - ~prep_upper:(doc_prep_upper env ~uid:benv.uid ~gid:benv.gid) 215 - ~on_extract 216 - link_node 217 - ~strategy:{ cmd; cleanup = doc_cleanup } () with 218 - | Day11_opam_build.Types.Success _bl -> 219 - Printf.printf " %s: linked\n%!" 220 - (OpamPackage.to_string node.pkg); 221 - Some 0 222 - | _ -> 223 - Printf.printf " %s: link FAILED\n%!" 224 - (OpamPackage.to_string node.pkg); 225 - None 226 - in 227 - ignore (Day11_exec.Sudo.rm_rf env prep_dir); 228 - result 83 + let html_dir = Fpath.(os_dir / "html") in 84 + match Doc_build.link env benv ~config ~build_layer ~compile_layer 85 + ~dep_compile_layers ~html_dir ~hash:dag_hash node.pkg with 86 + | Ok () -> 87 + Printf.printf " %s: linked\n%!" (OpamPackage.to_string node.pkg); 88 + Some 0 89 + | Error msg -> 90 + Printf.printf " %s: link FAILED (%s)\n%!" 91 + (OpamPackage.to_string node.pkg) msg; 92 + None 229 93 230 - let doc_all_package env benv ~os_dir ~driver_tool ~odoc_tools 231 - ~build_hash_blessed ~find_odoc_tool ~compile_results 232 - ~build_hash ~dag_hash 233 - (node : build) = 234 - match prepare_package ~os_dir ~driver_tool ~odoc_tools 235 - ~build_hash_blessed ~find_odoc_tool node with 94 + let doc_all_package env benv ~os_dir ~find_odoc_tool ~build_hash_blessed 95 + ~driver_tool ~compile_results ~build_hash ~dag_hash (node : build) = 96 + let blessed = match Hashtbl.find_opt build_hash_blessed node.hash with 97 + | Some true -> true | _ -> false in 98 + match find_odoc_tool node.pkg with 236 99 | None -> None 237 - | Some (_composite_tool_hash, universe, blessed, _pkg_loc, mounts, prep_dir) -> 238 - (* Collect dep compile layers for overlayfs stacking *) 100 + | Some (odoc_tool : Tool.t) -> 101 + let config : Doc_build.doc_config = 102 + { driver_tool; odoc_tool; os_dir; blessed } in 103 + let build_layer = Build.dir ~os_dir node in 239 104 let seen = Hashtbl.create 16 in 240 105 List.iter (collect_transitive_deps seen) node.deps; 241 - let dep_compile_dirs = Hashtbl.fold (fun bh () acc -> 106 + let dep_compile_layers = Hashtbl.fold (fun bh () acc -> 242 107 match Hashtbl.find_opt compile_results bh with 243 108 | Some bl -> Build.dir ~os_dir bl :: acc 244 109 | None -> acc 245 110 ) seen [] in 246 - (* HTML RW mount *) 247 - let html_base = Fpath.(os_dir / "html") in 248 - let html_mount = Day11_container.Mount.bind_rw 249 - ~src:(Fpath.to_string html_base) 250 - Odoc_store.container_html in 251 - let cmd = 252 - "export PATH=/home/opam/doc-tools/bin:$PATH && eval $(opam env) && " ^ 253 - Command.odoc_driver_voodoo ~pkg:node.pkg ~universe 254 - ~blessed ~actions:"all" ~odoc_bin ~odoc_md_bin in 255 - let doc_node : build = 256 - { hash = dag_hash; pkg = node.pkg; 257 - deps = [ node ]; universe = Day11_solution.Universe.dummy } in 258 - let on_extract ~layer_dir ~success:_ = 259 - let dm : Doc_meta.t = { 260 - package = OpamPackage.to_string node.pkg; 261 - phase = Doc_meta.Doc_all; 262 - deps = List.map (fun (d : build) -> OpamPackage.to_string d.pkg) doc_node.deps; 263 - } in 264 - ignore (Doc_meta.save layer_dir dm) 265 - in 266 - let result = 267 - match Day11_opam_build.Build_layer.build env benv 268 - ~mounts:(mounts @ [html_mount]) ~build_dirs:dep_compile_dirs 269 - ~prep_upper:(doc_prep_upper env ~uid:benv.uid ~gid:benv.gid) 270 - ~on_extract 271 - doc_node 272 - ~strategy:{ cmd; cleanup = doc_cleanup } () with 273 - | Day11_opam_build.Types.Success bl -> 274 - Hashtbl.replace compile_results build_hash bl; 275 - Printf.printf " %s: doc-all OK\n%!" 276 - (OpamPackage.to_string node.pkg); 277 - Some 0 278 - | _ -> 279 - Printf.printf " %s: doc-all FAILED\n%!" 280 - (OpamPackage.to_string node.pkg); 281 - None 282 - in 283 - ignore (Day11_exec.Sudo.rm_rf env prep_dir); 284 - result 111 + let html_dir = Fpath.(os_dir / "html") in 112 + match Doc_build.doc_all env benv ~config ~build_layer 113 + ~dep_compile_layers ~html_dir ~hash:dag_hash node.pkg with 114 + | Ok _layer_dir -> 115 + let doc_node : build = 116 + { hash = dag_hash; pkg = node.pkg; deps = [ node ]; 117 + universe = Day11_solution.Universe.dummy } in 118 + Hashtbl.replace compile_results build_hash doc_node; 119 + Printf.printf " %s: doc-all OK\n%!" (OpamPackage.to_string node.pkg); 120 + Some 0 121 + | Error msg -> 122 + Printf.printf " %s: doc-all FAILED (%s)\n%!" 123 + (OpamPackage.to_string node.pkg) msg; 124 + None 285 125 286 126 let run env benv ~np ~os_dir ~(driver_tool : Tool.t) ~odoc_tools 287 127 ~tool_source_dirs ~mounts ··· 706 546 | Some build_hash -> 707 547 let build_node = Hashtbl.find build_by_hash build_hash in 708 548 current_build_hash := build_hash; 709 - (match compile_package env benv ~os_dir ~driver_tool ~odoc_tools 710 - ~build_hash_blessed ~find_odoc_tool ~compile_results 549 + (match compile_package env benv ~os_dir ~find_odoc_tool 550 + ~build_hash_blessed ~driver_tool ~compile_results 711 551 ~dag_hash:node.hash build_node with 712 552 | Some _bl -> true 713 553 | None -> true) ··· 718 558 | Some build_hash -> 719 559 let build_node = Hashtbl.find build_by_hash build_hash in 720 560 current_build_hash := build_hash; 721 - (match doc_all_package env benv ~os_dir ~driver_tool ~odoc_tools 722 - ~build_hash_blessed ~find_odoc_tool ~compile_results 561 + (match doc_all_package env benv ~os_dir ~find_odoc_tool 562 + ~build_hash_blessed ~driver_tool ~compile_results 723 563 ~build_hash ~dag_hash:node.hash 724 564 build_node with 725 565 | Some n -> ··· 734 574 | Some build_hash -> 735 575 let build_node = Hashtbl.find build_by_hash build_hash in 736 576 current_build_hash := build_hash; 737 - (match link_package env benv ~os_dir ~driver_tool ~odoc_tools 738 - ~build_hash_blessed ~find_odoc_tool ~compile_results 577 + (match link_package env benv ~os_dir ~find_odoc_tool 578 + ~build_hash_blessed ~driver_tool ~compile_results 739 579 ~doc_dep_hashes 740 580 ~build_hash ~dag_hash:node.hash 741 581 build_node with