From c12f8034c783989ec38b0b4cd55f9d035f254274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Dimino?= Date: Wed, 13 Oct 2021 14:10:22 +0100 Subject: [PATCH] Add support for %{bin-available:...} (#4995) Signed-off-by: Jeremie Dimino --- CHANGES.md | 2 ++ doc/concepts.rst | 2 ++ src/dune_engine/pform.ml | 7 ++++++ src/dune_engine/pform.mli | 1 + src/dune_rules/artifacts.ml | 12 ++++++++++ src/dune_rules/artifacts.mli | 2 ++ src/dune_rules/expander.ml | 7 ++++++ .../blackbox-tests/test-cases/bin-available.t | 23 +++++++++++++++++++ 8 files changed, 56 insertions(+) create mode 100644 test/blackbox-tests/test-cases/bin-available.t diff --git a/CHANGES.md b/CHANGES.md index 42ed513708c..41aeaa0db3c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -216,6 +216,8 @@ Unreleased - Add support for `(empty_module_interface_if_absent)` in executable and library stanzas. (#4955, @nojb) +- Add support for `%{bin-available:...}` (#4995, @jeremiedimino) + 2.9.1 (07/09/2021) ------------------ diff --git a/doc/concepts.rst b/doc/concepts.rst index 51fa901b6c3..9b6dd9d6354 100644 --- a/doc/concepts.rst +++ b/doc/concepts.rst @@ -202,6 +202,8 @@ In addition, ``(action ...)`` fields support the following special variables: %{bin:program} ...)`` and ``(run program ...)`` behave in the same way. ``%{bin:...}`` is only necessary when you are using ``(bash ...)`` or ``(system ...)`` +- ``bin-available:`` expands to ``true`` or ``false`` depending + on whether ```` is available or not. - ``lib::`` expands to the installation path of the file ```` in the library ````. If ```` is available in the current workspace, the local diff --git a/src/dune_engine/pform.ml b/src/dune_engine/pform.ml index 376c0ed90c6..db35e644346 100644 --- a/src/dune_engine/pform.ml +++ b/src/dune_engine/pform.ml @@ -137,6 +137,7 @@ module Macro = struct ; lib_private : bool } | Lib_available + | Bin_available | Version | Read | Read_strings @@ -165,6 +166,9 @@ module Macro = struct | Lib_available, Lib_available -> Eq | Lib_available, _ -> Lt | _, Lib_available -> Gt + | Bin_available, Bin_available -> Eq + | Bin_available, _ -> Lt + | _, Bin_available -> Gt | Version, Version -> Eq | Version, _ -> Lt | _, Version -> Gt @@ -200,6 +204,7 @@ module Macro = struct [ ("lib_exec", bool lib_exec); ("lib_private", bool lib_private) ] ] | Lib_available -> string "Lib_available" + | Bin_available -> string "Bin_available" | Version -> string "Version" | Read -> string "Read" | Read_strings -> string "Read_strings" @@ -302,6 +307,7 @@ let encode_to_latest_dune_lang_version t = | Lib { lib_exec = false; lib_private = true } -> Some "lib-private" | Lib { lib_exec = true; lib_private = true } -> Some "libexec-private" | Lib_available -> Some "lib-available" + | Bin_available -> Some "bin-available" | Version -> Some "version" | Read -> Some "read" | Read_strings -> Some "read-strings" @@ -388,6 +394,7 @@ module Env = struct , since ~version:(2, 1) (Macro.Lib { lib_exec = true; lib_private = true }) ) ; ("lib-available", macro Lib_available) + ; ("bin-available", since ~version:(3, 0) Macro.Bin_available) ; ("version", macro Version) ; ("read", macro Read) ; ("read-lines", macro Read_lines) diff --git a/src/dune_engine/pform.mli b/src/dune_engine/pform.mli index 5ee89094c79..b07db0eb45a 100644 --- a/src/dune_engine/pform.mli +++ b/src/dune_engine/pform.mli @@ -77,6 +77,7 @@ module Macro : sig ; lib_private : bool } | Lib_available + | Bin_available | Version | Read | Read_strings diff --git a/src/dune_rules/artifacts.ml b/src/dune_rules/artifacts.ml index c1cf6121696..77aeccad251 100644 --- a/src/dune_rules/artifacts.ml +++ b/src/dune_rules/artifacts.ml @@ -25,6 +25,18 @@ module Bin = struct (let context = t.context.name in Action.Prog.Not_found.create ~program:name ?hint ~context ~loc ())) + let binary_available t name = + if not (Filename.is_relative name) then + let p = Path.of_filename_relative_to_initial_cwd name in + Fs_memo.path_exists p + else + match String.Map.find t.local_bins name with + | Some _ -> Memo.Build.return true + | None -> ( + t.context.which name >>| function + | Some _ -> true + | None -> false) + let add_binaries t ~dir l = let local_bins = List.fold_left l ~init:t.local_bins ~f:(fun acc fb -> diff --git a/src/dune_rules/artifacts.mli b/src/dune_rules/artifacts.mli index 5dd8d93db3a..4462d3283c9 100644 --- a/src/dune_rules/artifacts.mli +++ b/src/dune_rules/artifacts.mli @@ -14,6 +14,8 @@ module Bin : sig -> string -> Action.Prog.t Memo.Build.t + val binary_available : t -> string -> bool Memo.Build.t + val add_binaries : t -> dir:Path.Build.t -> File_binding.Expanded.t list -> t end diff --git a/src/dune_rules/expander.ml b/src/dune_rules/expander.ml index 0a3eef11f0e..dd6deac154c 100644 --- a/src/dune_rules/expander.ml +++ b/src/dune_rules/expander.ml @@ -564,6 +564,13 @@ let expand_pform_gen ~(context : Context.t) ~bindings ~dir ~source let open Memo.Build.O in let+ available = Lib.DB.available (Scope.libs t.scope) lib in available |> string_of_bool |> string)) + | Bin_available -> + Need_full_expander + (fun t -> + Without + (let open Memo.Build.O in + let+ b = Artifacts.Bin.binary_available t.bin_artifacts_host s in + b |> string_of_bool |> string)) | Read -> let path = relative ~source dir s in Direct diff --git a/test/blackbox-tests/test-cases/bin-available.t b/test/blackbox-tests/test-cases/bin-available.t new file mode 100644 index 00000000000..36dd0b4d47a --- /dev/null +++ b/test/blackbox-tests/test-cases/bin-available.t @@ -0,0 +1,23 @@ +Test for %{bin-available:...} + + $ cat >dune-project <<"EOF" + > (lang dune 3.0) + > (package (name foo)) + > EOF + $ cat >dune<<"EOF" + > (rule + > (alias default) + > (action + > (progn + > (echo "dune: %{bin-available:dune}\n") + > (echo "local program foo: %{bin-available:foo}\n") + > (echo "non existant program: %{bin-available:*}\n")))) + > + > (executable (public_name foo)) + > EOF + $ touch foo.ml + + $ dune build + dune: true + local program foo: true + non existant program: false