type doc_entry = { pkg : OpamPackage.t; html_path : Fpath.t; universe : string; blessed : bool; } let scan_cache ~os_dir = let layers = Day11_layer.Scan.list_layers os_dir in List.filter_map (fun (name, path) -> if not (Astring.String.is_prefix ~affix:"doc-" name) || Astring.String.is_prefix ~affix:"doc-driver-" name || Astring.String.is_prefix ~affix:"doc-odoc-" name then None else let json_path = Fpath.(path / "layer.json") in match try Some (Yojson.Safe.from_file (Fpath.to_string json_path)) with _ -> None with | None -> None | Some json -> try let open Yojson.Safe.Util in let pkg_str = json |> member "package" |> to_string in let pkg = OpamPackage.of_string pkg_str in let doc = json |> member "doc" in let status = doc |> member "status" |> to_string in if status <> "success" then None else let html_path = doc |> member "html_path" |> to_string in let blessed = doc |> member "blessed" |> to_bool in let dep_hashes = json |> member "dep_doc_hashes" |> to_list |> List.map to_string in let universe = Command.compute_universe_hash dep_hashes in Some { pkg; html_path = Fpath.v html_path; universe; blessed } with _ -> None ) layers let sync env ~entries ~destination ?(blessed_only = false) ?(package_filter = fun _ -> true) ?(dry_run = false) () = let filtered = entries |> List.filter (fun e -> (not blessed_only || e.blessed) && package_filter (OpamPackage.to_string e.pkg)) in let results = List.map (fun entry -> let src = Fpath.to_string entry.html_path ^ "/" in let dst_subpath = if entry.blessed then Printf.sprintf "%s/%s/" (OpamPackage.name_to_string entry.pkg) (OpamPackage.version_to_string entry.pkg) else Printf.sprintf "universes/%s/%s/%s/" entry.universe (OpamPackage.name_to_string entry.pkg) (OpamPackage.version_to_string entry.pkg) in let dst = destination ^ "/" ^ dst_subpath in let cmd = Bos.Cmd.(v "rsync" % "-av" %% (if dry_run then Bos.Cmd.v "--dry-run" else Bos.Cmd.empty) % "--delete" % src % dst) in match Day11_exec.Run.run env cmd None with | run when run.Day11_exec.Run.status = `Exited 0 -> Ok () | run -> Rresult.R.error_msgf "rsync failed for %s: %s" (OpamPackage.to_string entry.pkg) run.errors | exception exn -> Rresult.R.error_msgf "rsync: %s" (Printexc.to_string exn) ) filtered in match List.find_opt Result.is_error results with | Some (Error _ as e) -> e | _ -> Ok ()