Skip to content

Commit

Permalink
Add odoc dev tool
Browse files Browse the repository at this point in the history
The command `dune ocaml doc` will now lock, build, and run odoc as a
dev tool if the dev tools feature is enabled.

Signed-off-by: Stephen Sherratt <stephen@sherra.tt>
  • Loading branch information
gridbugs committed Sep 19, 2024
1 parent 396611a commit 1b86797
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 18 deletions.
20 changes: 12 additions & 8 deletions bin/lock_dev_tool.ml
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,21 @@ let solve ~local_packages ~lock_dirs =
~lock_dirs
;;

let lock_ocamlformat () : unit Fiber.t =
let version = Dune_pkg.Ocamlformat.version_of_current_project's_ocamlformat_config () in
let ocamlformat_dev_tool_lock_dir =
Dune_pkg.Lock_dir.dev_tool_lock_dir_path Ocamlformat
in
if not (Path.exists @@ Path.source ocamlformat_dev_tool_lock_dir)
let lock_dev_tool dev_tool version =
let dev_tool_lock_dir = Dune_pkg.Lock_dir.dev_tool_lock_dir_path dev_tool in
if not (Path.exists @@ Path.source dev_tool_lock_dir)
then (
let local_pkg =
make_local_package_wrapping_dev_tool ~dev_tool:Ocamlformat ~dev_tool_version:version
make_local_package_wrapping_dev_tool ~dev_tool ~dev_tool_version:version
in
let local_packages = Package_name.Map.singleton local_pkg.name local_pkg in
solve ~local_packages ~lock_dirs:[ ocamlformat_dev_tool_lock_dir ])
solve ~local_packages ~lock_dirs:[ dev_tool_lock_dir ])
else Fiber.return ()
;;

let lock_ocamlformat () =
let version = Dune_pkg.Ocamlformat.version_of_current_project's_ocamlformat_config () in
lock_dev_tool Ocamlformat version
;;

let lock_odoc () = lock_dev_tool Odoc None
1 change: 1 addition & 0 deletions bin/lock_dev_tool.mli
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
val is_enabled : bool Lazy.t
val lock_ocamlformat : unit -> unit Fiber.t
val lock_odoc : unit -> unit Fiber.t
8 changes: 8 additions & 0 deletions bin/ocaml/doc.ml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,20 @@ let man =

let info = Cmd.info "doc" ~doc ~man

let lock_odoc_if_dev_tool_enabled () =
match Lazy.force Lock_dev_tool.is_enabled with
| false -> Action_builder.return ()
| true ->
Action_builder.of_memo (Memo.of_reproducible_fiber (Lock_dev_tool.lock_odoc ()))
;;

let term =
let+ builder = Common.Builder.term in
let common, config = Common.init builder in
let request (setup : Main.build_system) =
let dir = Path.(relative root) (Common.prefix_target common ".") in
let open Action_builder.O in
let* () = lock_odoc_if_dev_tool_enabled () in
let+ () =
Alias.in_dir ~name:Dune_rules.Alias.doc ~recursive:true ~contexts:setup.contexts dir
|> Alias.request
Expand Down
12 changes: 10 additions & 2 deletions src/dune_pkg/dev_tool.ml
Original file line number Diff line number Diff line change
@@ -1,29 +1,37 @@
open! Import

type t = Ocamlformat
type t =
| Ocamlformat
| Odoc

let all = [ Ocamlformat ]
let all = [ Ocamlformat; Odoc ]

let equal a b =
match a, b with
| Ocamlformat, Ocamlformat -> true
| Odoc, Odoc -> true
| _ -> false
;;

let package_name = function
| Ocamlformat -> Package_name.of_string "ocamlformat"
| Odoc -> Package_name.of_string "odoc"
;;

let of_package_name package_name =
match Package_name.to_string package_name with
| "ocamlformat" -> Ocamlformat
| "odoc" -> Odoc
| other -> User_error.raise [ Pp.textf "No such dev tool: %s" other ]
;;

let exe_name = function
| Ocamlformat -> "ocamlformat"
| Odoc -> "odoc"
;;

let exe_path_components_within_package t =
match t with
| Ocamlformat -> [ "bin"; exe_name t ]
| Odoc -> [ "bin"; exe_name t ]
;;
4 changes: 3 additions & 1 deletion src/dune_pkg/dev_tool.mli
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
open! Import

type t = Ocamlformat
type t =
| Ocamlformat
| Odoc

val all : t list
val equal : t -> t -> bool
Expand Down
33 changes: 26 additions & 7 deletions src/dune_rules/odoc.ml
Original file line number Diff line number Diff line change
Expand Up @@ -245,14 +245,33 @@ let odoc_base_flags quiet build_dir =
| Nonfatal -> S []
;;

let odoc_dev_tool_lock_dir_exists () =
let path = Dune_pkg.Lock_dir.dev_tool_lock_dir_path Odoc in
Fs_memo.dir_exists (Path.source path |> Path.as_outside_build_dir_exn)
;;

let odoc_dev_tool_exe_path_building_if_necessary () =
let open Action_builder.O in
let path = Path.build (Pkg_dev_tool.exe_path Odoc) in
let+ () = Action_builder.path path in
Ok path
;;

let odoc_program sctx dir =
Super_context.resolve_program
sctx
~dir
~where:Original_path
"odoc"
~loc:None
~hint:"opam install odoc"
let open Action_builder.O in
let* odoc_dev_tool_lock_dir_exists =
Action_builder.of_memo (odoc_dev_tool_lock_dir_exists ())
in
match odoc_dev_tool_lock_dir_exists with
| true -> odoc_dev_tool_exe_path_building_if_necessary ()
| false ->
Super_context.resolve_program
sctx
~dir
~where:Original_path
"odoc"
~loc:None
~hint:"opam install odoc"
;;

let run_odoc sctx ~dir command ~quiet ~flags_for args =
Expand Down
34 changes: 34 additions & 0 deletions test/blackbox-tests/test-cases/pkg/odoc/dev-tool-odoc-basic.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
Test that the "dune ocaml doc" command causes odoc to be locked and
build, and then used to generate documentation.

$ . ../helpers.sh
$ . ./helpers.sh

$ mkrepo
$ make_mock_odoc_package

$ setup_odoc_workspace

$ cat > dune-project <<EOF
> (lang dune 3.16)
>
> (package
> (name foo)
> (allow_empty))
> EOF

Lock and build the fake odoc executable, and then use the fake
executable to attempt to generate documentation. The fake executable
doesn't actually do anything so the command fails but this
demonstrates that it was run.
$ DUNE_CONFIG__LOCK_DEV_TOOL=enabled dune ocaml doc
Solution for dev-tools.locks/odoc:
- odoc.0.0.1
hello from fake odoc
hello from fake odoc
File "_doc/_html/_unknown_", line 1, characters 0-0:
Error: Rule failed to produce directory "_doc/_html/odoc.support"
File "_doc/_odoc/pkg/foo/_unknown_", line 1, characters 0-0:
Error: Rule failed to generate the following targets:
- _doc/_odoc/pkg/foo/page-index.odoc
[1]
3 changes: 3 additions & 0 deletions test/blackbox-tests/test-cases/pkg/odoc/dune
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(cram
(deps helpers.sh)
(applies_to :whole_subtree))
27 changes: 27 additions & 0 deletions test/blackbox-tests/test-cases/pkg/odoc/helpers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Create a dune-workspace file with mock repos set up for the main
# project and the odoc lockdir.
setup_odoc_workspace() {
cat > dune-workspace <<EOF
(lang dune 3.16)
(lock_dir
(path "dev-tools.locks/odoc")
(repositories mock))
(lock_dir
(repositories mock))
(repository
(name mock)
(source "file://$(pwd)/mock-opam-repository"))
EOF
}

# Create a fake odoc package containing an executable that
# just prints a message.
make_mock_odoc_package() {
mkpkg odoc <<EOF
install: [
[ "sh" "-c" "echo '#!/bin/sh' > %{bin}%/odoc" ]
[ "sh" "-c" "echo 'echo hello from fake odoc' >> %{bin}%/odoc" ]
[ "sh" "-c" "chmod a+x %{bin}%/odoc" ]
]
EOF
}

0 comments on commit 1b86797

Please sign in to comment.