From 4480d897c83822e31af3c2f37bd5df010f9451b7 Mon Sep 17 00:00:00 2001 From: Ali Caglayan Date: Sun, 21 May 2023 02:52:42 +0200 Subject: [PATCH] feature: dune show targets and dune show aliases Add a `dune show targets` and `dune show aliases` command for showing targets and aliases in a directory like `ls`. fix https://github.com/ocaml/dune/issues/265 Signed-off-by: Ali Caglayan --- CHANGES.md | 4 + bin/describe/aliases_cmd.ml | 65 +++++++++++ bin/describe/aliases_cmd.mli | 5 + bin/describe/describe.ml | 2 + bin/describe/targets_cmd.ml | 70 ++++++++++++ bin/describe/targets_cmd.mli | 5 + .../describe/aliases.t/dune-project | 1 + .../test-cases/describe/aliases.t/run.t | 107 ++++++++++++++++++ .../test-cases/describe/targets.t/a.ml | 0 .../test-cases/describe/targets.t/b/c.ml | 0 .../test-cases/describe/targets.t/b/dune | 2 + .../test-cases/describe/targets.t/dune | 10 ++ .../describe/targets.t/dune-project | 2 + .../test-cases/describe/targets.t/run.t | 69 +++++++++++ 14 files changed, 342 insertions(+) create mode 100644 bin/describe/aliases_cmd.ml create mode 100644 bin/describe/aliases_cmd.mli create mode 100644 bin/describe/targets_cmd.ml create mode 100644 bin/describe/targets_cmd.mli create mode 100644 test/blackbox-tests/test-cases/describe/aliases.t/dune-project create mode 100644 test/blackbox-tests/test-cases/describe/aliases.t/run.t create mode 100644 test/blackbox-tests/test-cases/describe/targets.t/a.ml create mode 100644 test/blackbox-tests/test-cases/describe/targets.t/b/c.ml create mode 100644 test/blackbox-tests/test-cases/describe/targets.t/b/dune create mode 100644 test/blackbox-tests/test-cases/describe/targets.t/dune create mode 100644 test/blackbox-tests/test-cases/describe/targets.t/dune-project create mode 100644 test/blackbox-tests/test-cases/describe/targets.t/run.t diff --git a/CHANGES.md b/CHANGES.md index b04049699100..19c45c321033 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -48,6 +48,10 @@ Unreleased - Respect `-p` / `--only-packages` for `melange.emit` artifacts (#7849, @anmonteiro) +- Add commands `dune show targets` and `dune show aliases`, which are similar to + `ls`, that display all the available targets and aliases in a given directory + respectively. (#7770, grants #265, @Alizter) + - Fix scanning of Coq installed files (@ejgallego, reported by @palmskog, #7895 , fixes #7893) diff --git a/bin/describe/aliases_cmd.ml b/bin/describe/aliases_cmd.ml new file mode 100644 index 000000000000..f792bab4aca3 --- /dev/null +++ b/bin/describe/aliases_cmd.ml @@ -0,0 +1,65 @@ +open Import +open Stdune + +let doc = "Print aliases in a given directory. Works similalry to ls." + +let pp_aliases ~header ~(contexts : Context.t list) path = + let dir = Path.of_string path in + let root = + match (dir : Path.t) with + | External e -> + Code_error.raise "target_hint: external path" + [ ("path", Path.External.to_dyn e) ] + | In_source_tree d -> d + | In_build_dir d -> ( + match Path.Build.drop_build_context d with + | Some d -> d + | None -> Path.Source.root) + in + let open Action_builder.O in + let+ alias_targets = + let+ load_dir = + Action_builder.List.map contexts ~f:(fun ctx -> + let dir = + Path.Build.append_source + (Dune_engine.Context_name.build_dir (Context.name ctx)) + root + |> Path.build + in + Action_builder.of_memo (Load_rules.load_dir ~dir)) + in + List.fold_left load_dir ~init:Dune_engine.Alias.Name.Map.empty + ~f:(fun acc x -> + match (x : Load_rules.Loaded.t) with + | Build build -> + Dune_engine.Alias.Name.Map.union + ~f:(fun _ a _ -> Some a) + acc build.aliases + | _ -> acc) + |> Dune_engine.Alias.Name.Map.to_list_map ~f:(fun name _ -> + Dune_engine.Alias.Name.to_string name) + in + (if header then [ Pp.textf "%s:" (Path.to_string dir) ] else []) + @ [ Pp.concat_map alias_targets ~f:Pp.text ~sep:Pp.newline ] + |> Pp.concat ~sep:Pp.newline + +let term = + let+ common = Common.term + and+ paths = Arg.(value & pos_all string [ "." ] & info [] ~docv:"DIR") in + let config = Common.init common in + let request (setup : Dune_rules.Main.build_system) = + let header = List.length paths > 1 in + let open Action_builder.O in + let+ paragraphs = + Action_builder.List.map paths + ~f:(pp_aliases ~header ~contexts:setup.contexts) + in + paragraphs + |> Pp.concat ~sep:(Pp.seq Pp.newline Pp.newline) + |> List.singleton |> User_message.make |> User_message.print + in + Scheduler.go ~common ~config @@ fun () -> + let open Fiber.O in + Build_cmd.run_build_system ~common ~request >>| ignore + +let command = Cmd.v (Cmd.info "aliases" ~doc ~envs:Common.envs) term diff --git a/bin/describe/aliases_cmd.mli b/bin/describe/aliases_cmd.mli new file mode 100644 index 000000000000..1e4ac02c4aa4 --- /dev/null +++ b/bin/describe/aliases_cmd.mli @@ -0,0 +1,5 @@ +open Import + +(** The aliases command lists all the aliases available in the given directory, + defaulting to the current working direcctory. *) +val command : unit Cmd.t diff --git a/bin/describe/describe.ml b/bin/describe/describe.ml index b06480b16d29..bd804e70b9ba 100644 --- a/bin/describe/describe.ml +++ b/bin/describe/describe.ml @@ -13,6 +13,8 @@ let subcommands = ; Describe_opam_files.command ; Describe_pp.command ; Printenv.command + ; Targets_cmd.command + ; Aliases_cmd.command ] let group = diff --git a/bin/describe/targets_cmd.ml b/bin/describe/targets_cmd.ml new file mode 100644 index 000000000000..23a57e18fb0f --- /dev/null +++ b/bin/describe/targets_cmd.ml @@ -0,0 +1,70 @@ +open Import +open Stdune + +let pp_all_direct_targets ~header path = + let dir = Path.of_string path in + let root = + match (dir : Path.t) with + | External e -> + Code_error.raise "target_hint: external path" + [ ("path", Path.External.to_dyn e) ] + | In_source_tree d -> d + | In_build_dir d -> ( + match Path.Build.drop_build_context d with + | Some d -> d + | None -> Path.Source.root) + in + let open Action_builder.O in + let+ targets = + let open Memo.O in + Action_builder.of_memo + (Target.all_direct_targets (Some root) >>| Path.Build.Map.to_list) + in + let targets = + if Path.is_in_build_dir dir then + List.map ~f:(fun (path, k) -> (Path.build path, k)) targets + else + List.map targets ~f:(fun (path, k) -> + match Path.Build.extract_build_context path with + | None -> (Path.build path, k) + | Some (_, path) -> (Path.source path, k)) + in + let targets = + (* Only suggest hints for the basename, otherwise it's slow when there are + lots of files *) + List.filter_map targets ~f:(fun (path, kind) -> + if Path.equal (Path.parent_exn path) dir then + (* directory targets can be distinguied by the trailing path seperator *) + Some + (match kind with + | File -> Path.basename path + | Directory -> Path.basename path ^ Filename.dir_sep) + else None) + in + (if header then [ Pp.textf "%s:" (Path.to_string dir) ] else []) + @ [ Pp.concat_map targets ~f:Pp.text ~sep:Pp.newline ] + |> Pp.concat ~sep:Pp.newline + +let term = + let+ common = Common.term + and+ paths = Arg.(value & pos_all string [ "." ] & info [] ~docv:"DIR") in + let config = Common.init common in + let request (_ : Dune_rules.Main.build_system) = + let header = List.length paths > 1 in + let open Action_builder.O in + let+ paragraphs = + Action_builder.List.map paths ~f:(pp_all_direct_targets ~header) + in + paragraphs + |> Pp.concat ~sep:(Pp.seq Pp.newline Pp.newline) + |> List.singleton |> User_message.make |> User_message.print + in + Scheduler.go ~common ~config @@ fun () -> + let open Fiber.O in + Build_cmd.run_build_system ~common ~request >>| ignore + +let command = + let doc = + "Print available targets in a given directory. Works similalry to ls." + in + Cmd.v (Cmd.info "targets" ~doc ~envs:Common.envs) term diff --git a/bin/describe/targets_cmd.mli b/bin/describe/targets_cmd.mli new file mode 100644 index 000000000000..f9b54f159167 --- /dev/null +++ b/bin/describe/targets_cmd.mli @@ -0,0 +1,5 @@ +open Import + +(** The targets command lists all the targets available in the given directory, + defaulting to the current working direcctory. *) +val command : unit Cmd.t diff --git a/test/blackbox-tests/test-cases/describe/aliases.t/dune-project b/test/blackbox-tests/test-cases/describe/aliases.t/dune-project new file mode 100644 index 000000000000..0ececa7d7fff --- /dev/null +++ b/test/blackbox-tests/test-cases/describe/aliases.t/dune-project @@ -0,0 +1 @@ +(lang dune 3.8) diff --git a/test/blackbox-tests/test-cases/describe/aliases.t/run.t b/test/blackbox-tests/test-cases/describe/aliases.t/run.t new file mode 100644 index 000000000000..f4e5ea1689e1 --- /dev/null +++ b/test/blackbox-tests/test-cases/describe/aliases.t/run.t @@ -0,0 +1,107 @@ +Testing the "dune show aliases" command. This command shows the aliases in the +current directory. It acts similarly to ls. It will not show aliases that appear +in subdirectories although this could be changed in the future. + +In an empty dune project, the following aliases are available. + + $ dune show aliases + all + default + fmt + +User defined aliases can be added to a dune file. These should be picked up by +the command. + + $ cat > dune << EOF + > (alias + > (name foo)) + > EOF + + $ dune show aliases + all + default + fmt + foo + +Aliases in subdirectories should not be picked up. + + $ mkdir subdir + $ cat > subdir/dune << EOF + > (alias + > (name bar)) + > EOF + + $ dune show aliases + all + default + fmt + foo + +But checking the subdirectory it should be available. + + $ dune show aliases subdir + all + bar + default + fmt + +Adding an OCaml library will introduce OCaml specific aliases: + + $ cat > dune << EOF + > (library + > (name foo)) + > EOF + + $ dune show aliases + all + check + default + doc-private + fmt + +Adding a cram test will introduce an alias with the name of the test and also +introduce the runtest alias: +bbb + $ rm dune + $ cat > mytest.t + + $ dune show aliases + all + default + fmt + mytest + runtest + +We can also show aliases in multiple directories at once: + + $ dune show aliases . subdir + .: + all + default + fmt + mytest + runtest + + subdir: + all + bar + default + fmt + +Including those in the _build/ directory: + + $ dune build + $ dune show aliases . _build/default + .: + all + default + fmt + mytest + runtest + + _build/default: + all + default + fmt + mytest + runtest diff --git a/test/blackbox-tests/test-cases/describe/targets.t/a.ml b/test/blackbox-tests/test-cases/describe/targets.t/a.ml new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test/blackbox-tests/test-cases/describe/targets.t/b/c.ml b/test/blackbox-tests/test-cases/describe/targets.t/b/c.ml new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test/blackbox-tests/test-cases/describe/targets.t/b/dune b/test/blackbox-tests/test-cases/describe/targets.t/b/dune new file mode 100644 index 000000000000..67231e9fe24b --- /dev/null +++ b/test/blackbox-tests/test-cases/describe/targets.t/b/dune @@ -0,0 +1,2 @@ +(library + (name simple2)) diff --git a/test/blackbox-tests/test-cases/describe/targets.t/dune b/test/blackbox-tests/test-cases/describe/targets.t/dune new file mode 100644 index 000000000000..81c6345a5334 --- /dev/null +++ b/test/blackbox-tests/test-cases/describe/targets.t/dune @@ -0,0 +1,10 @@ +(library + (name simple)) + +(rule + (targets + (dir d)) + (action + (progn + (run mkdir d) + (run cat > d/foo)))) diff --git a/test/blackbox-tests/test-cases/describe/targets.t/dune-project b/test/blackbox-tests/test-cases/describe/targets.t/dune-project new file mode 100644 index 000000000000..c9932b31e04d --- /dev/null +++ b/test/blackbox-tests/test-cases/describe/targets.t/dune-project @@ -0,0 +1,2 @@ +(lang dune 3.8) +(using directory-targets 0.1) diff --git a/test/blackbox-tests/test-cases/describe/targets.t/run.t b/test/blackbox-tests/test-cases/describe/targets.t/run.t new file mode 100644 index 000000000000..cea6af231583 --- /dev/null +++ b/test/blackbox-tests/test-cases/describe/targets.t/run.t @@ -0,0 +1,69 @@ +Testing the "dune show targets" command in a simple OCaml project with an +additional directory target to see the behaviour there. + +We have two libraries with one in a subdirectory. We also have a directory +target d to see how the command will behave. + +With no directory provided to the command, it should default to the current +working directory. + + $ dune show targets + a.ml + d/ + dune + dune-project + simple.a + simple.cma + simple.cmxa + simple.cmxs + simple.ml-gen + +Multiple directories can be provided to the command. Also subdirectories may be +used, and only the targets available in that directory will be displayed. + + $ dune show targets . b/ + .: + a.ml + d/ + dune + dune-project + simple.a + simple.cma + simple.cmxa + simple.cmxs + simple.ml-gen + + b: + c.ml + dune + simple2.a + simple2.cma + simple2.cmxa + simple2.cmxs + simple2.ml-gen + +The command also works with files in the _build directory. + + $ dune show targets _build/default/ + a.ml + d/ + dune + dune-project + simple.a + simple.cma + simple.cmxa + simple.cmxs + simple.ml-gen + + $ dune show targets _build/default/b + c.ml + dune + simple2.a + simple2.cma + simple2.cmxa + simple2.cmxs + simple2.ml-gen +We cannot see inside directory targets + + $ dune show targets d +