diff --git a/bin/lock_dev_tool.ml b/bin/lock_dev_tool.ml index 1d613c5bf8b..4eb2554287e 100644 --- a/bin/lock_dev_tool.ml +++ b/bin/lock_dev_tool.ml @@ -197,28 +197,46 @@ let lockdir_status dev_tool = with | false -> Memo.return (`Lockdir_ok_with_tool_pkg pkg) | true -> - let open Memo.O in - let* compiler = compiler_package () in + let+ compiler = compiler_package () in (match Package_name.Map.find packages compiler.info.name with - | None -> Memo.return `No_compiler_lockfile_in_lockdir - | Some pkg -> - let+ ocaml_compiler = compiler_package () in - (match Lock_dir.Pkg.equal pkg ocaml_compiler with - | true -> `Lockdir_ok_with_tool_pkg pkg - | false -> - `Dev_tool_needs_to_be_relocked_because_project_compiler_version_changed - (User_message.make - [ Pp.textf - "The version of the compiler package (%S) in this project's \ - lockdir has changed to %s (formerly the compiler version \ - was %s). The dev-tool %S will be re-locked and rebuilt with \ - this version of the compiler." - (Package_name.to_string compiler.info.name) - (Package_version.to_string ocaml_compiler.info.version) - (Package_version.to_string pkg.info.version) - (Dune_pkg.Dev_tool.package_name dev_tool - |> Package_name.to_string) - ])))))) + | None -> `No_compiler_lockfile_in_lockdir + | Some locked_compiler -> + let same_compiler_package = + Lock_dir.Pkg.equal_on_platform locked_compiler compiler ~platform + in + if same_compiler_package + then `Lockdir_ok_with_tool_pkg pkg + else ( + let compiler_name = Package_name.to_string compiler.info.name in + let dev_tool_name = + Dune_pkg.Dev_tool.package_name dev_tool |> Package_name.to_string + in + let message = + if + Package_version.equal + compiler.info.version + locked_compiler.info.version + then + Pp.textf + "The compiler package (%S) in this project's lockdir has changed \ + without changing its version (%s). The dev-tool %S will be \ + re-locked and rebuilt with the updated compiler package." + compiler_name + (Package_version.to_string compiler.info.version) + dev_tool_name + else + Pp.textf + "The version of the compiler package (%S) in this project's \ + lockdir has changed to %s (formerly the compiler version was \ + %s). The dev-tool %S will be re-locked and rebuilt with this \ + version of the compiler." + compiler_name + (Package_version.to_string compiler.info.version) + (Package_version.to_string locked_compiler.info.version) + dev_tool_name + in + `Dev_tool_needs_to_be_relocked_because_project_compiler_changed + (User_message.make [ message ])))))) ;; (* [lock_dev_tool_at_version dev_tool version] generates the lockdir for the @@ -261,7 +279,7 @@ let lock_dev_tool_at_version dev_tool version = "ocaml" ]; true - | `Dev_tool_needs_to_be_relocked_because_project_compiler_version_changed message -> + | `Dev_tool_needs_to_be_relocked_because_project_compiler_changed message -> Console.print_user_message message; true | `Lockdir_missing_entry_for_tool message -> diff --git a/doc/changes/fixed/16173.md b/doc/changes/fixed/16173.md new file mode 100644 index 00000000000..1bfbd646bb1 --- /dev/null +++ b/doc/changes/fixed/16173.md @@ -0,0 +1,3 @@ +- Avoid unnecessarily relocking and rebuilding dev tools when the project's + compiler package is unchanged, while still relocking after same-version + compiler recipe changes. (#16173, @Alizter) diff --git a/src/dune_pkg/lock_dir.ml b/src/dune_pkg/lock_dir.ml index 77f6edaf489..6a5e9b83519 100644 --- a/src/dune_pkg/lock_dir.ml +++ b/src/dune_pkg/lock_dir.ml @@ -966,6 +966,28 @@ module Pkg = struct List.is_empty t.enabled_on_platforms || Solver_env_disjunction.matches_platform t.enabled_on_platforms ~platform ;; + + let equal_on_platform a b ~platform = + match is_enabled_on_platform a ~platform, is_enabled_on_platform b ~platform with + | false, false -> true + | true, false | false, true -> false + | true, true -> + let choose choice = + match Conditional_choice.choose_for_platform choice ~platform with + | None -> Conditional_choice.empty + | Some value -> Conditional_choice.singleton Solver_env.empty value + in + let normalize pkg = + { pkg with + build_command = choose pkg.build_command + ; install_command = choose pkg.install_command + ; depends = choose pkg.depends + ; enabled_on_platforms = [ Solver_env.empty ] + } + |> remove_locs + in + equal (normalize a) (normalize b) + ;; end module Repositories = struct diff --git a/src/dune_pkg/lock_dir.mli b/src/dune_pkg/lock_dir.mli index 38ac6492af9..a7eac906969 100644 --- a/src/dune_pkg/lock_dir.mli +++ b/src/dune_pkg/lock_dir.mli @@ -73,6 +73,12 @@ module Pkg : sig val remove_locs : t -> t val equal : t -> t -> bool + + (** Compare package behavior on a platform, ignoring source locations, choices + for other platforms, and availability on other platforms. Packages disabled + on the platform compare equal if both are disabled. *) + val equal_on_platform : t -> t -> platform:Solver_env.t -> bool + val hash : t -> int val digest_feed : t Dune_digest.Feed.t val to_dyn : t -> Dyn.t diff --git a/test/blackbox-tests/test-cases/pkg/merlin/dev-tool-merlin-relock-on-ocaml-package-change.t b/test/blackbox-tests/test-cases/pkg/merlin/dev-tool-merlin-relock-on-ocaml-package-change.t index 226bbbf7c3b..d6386193ba9 100644 --- a/test/blackbox-tests/test-cases/pkg/merlin/dev-tool-merlin-relock-on-ocaml-package-change.t +++ b/test/blackbox-tests/test-cases/pkg/merlin/dev-tool-merlin-relock-on-ocaml-package-change.t @@ -23,7 +23,7 @@ Use an extra file to distinguish reuse from an identical regenerated lockdir. > else > echo 'unchanged dev-tool lock regenerated' > fi - unchanged dev-tool lock regenerated + unchanged dev-tool lock reused $ rm -f "${dev_tool_lock_dir}"/relock-sentinel Change the compiler package's build recipe without changing its version, then @@ -42,10 +42,9 @@ Executing Merlin must notice the changed compiler package and regenerate its lock directory from the updated recipe. $ dune tools exec ocamlmerlin - The version of the compiler package ("ocaml-base-compiler") in this project's - lockdir has changed to 5.2.0 (formerly the compiler version was 5.2.0). The - dev-tool "merlin" will be re-locked and rebuilt with this version of the - compiler. + The compiler package ("ocaml-base-compiler") in this project's lockdir has + changed without changing its version (5.2.0). The dev-tool "merlin" will be + re-locked and rebuilt with the updated compiler package. Solution for _build/.dev-tools.locks/merlin: - merlin.0.0.1 - ocaml-base-compiler.5.2.0 diff --git a/test/blackbox-tests/test-cases/pkg/merlin/dev-tool-merlin-relock-on-ocaml-version-change.t b/test/blackbox-tests/test-cases/pkg/merlin/dev-tool-merlin-relock-on-ocaml-version-change.t index 68284965af8..07fff9379a5 100644 --- a/test/blackbox-tests/test-cases/pkg/merlin/dev-tool-merlin-relock-on-ocaml-version-change.t +++ b/test/blackbox-tests/test-cases/pkg/merlin/dev-tool-merlin-relock-on-ocaml-version-change.t @@ -29,14 +29,6 @@ Initially merlin will depend on ocaml-base-compiler.5.2.0 to match the project. We can re-run "dune tools exec ocamlmerlin" without relocking or rebuilding. $ dune tools exec ocamlmerlin - The version of the compiler package ("ocaml-base-compiler") in this project's - lockdir has changed to 5.2.0 (formerly the compiler version was 5.2.0). The - dev-tool "merlin" will be re-locked and rebuilt with this version of the - compiler. - Solution for _build/.dev-tools.locks/merlin: - - merlin.0.0.1 - - ocaml-base-compiler.5.2.0 - - ocaml-compiler.5.2.0 Running 'ocamlmerlin' hello from fake ocamlmerlin diff --git a/test/blackbox-tests/test-cases/pkg/ocamllsp/dev-tool-ocamllsp-pinned-compiler.t b/test/blackbox-tests/test-cases/pkg/ocamllsp/dev-tool-ocamllsp-pinned-compiler.t index 70cf9516c8a..333e96d64ff 100644 --- a/test/blackbox-tests/test-cases/pkg/ocamllsp/dev-tool-ocamllsp-pinned-compiler.t +++ b/test/blackbox-tests/test-cases/pkg/ocamllsp/dev-tool-ocamllsp-pinned-compiler.t @@ -56,12 +56,5 @@ rather than "ocaml-base-compiler.5.2.0" from opam-repository. - ocaml-lsp-server.0.0.1 $ dune tools exec ocamllsp - The version of the compiler package ("ocaml-base-compiler") in this project's - lockdir has changed to dev (formerly the compiler version was dev). The - dev-tool "ocaml-lsp-server" will be re-locked and rebuilt with this version - of the compiler. - Solution for _build/.dev-tools.locks/ocaml-lsp-server: - - ocaml-base-compiler.dev - - ocaml-lsp-server.0.0.1 Running 'ocamllsp' hello from fake ocamllsp diff --git a/test/blackbox-tests/test-cases/pkg/ocamllsp/dev-tool-ocamllsp-relock-on-ocaml-version-change.t b/test/blackbox-tests/test-cases/pkg/ocamllsp/dev-tool-ocamllsp-relock-on-ocaml-version-change.t index 7253c2c31cf..958d4766696 100644 --- a/test/blackbox-tests/test-cases/pkg/ocamllsp/dev-tool-ocamllsp-relock-on-ocaml-version-change.t +++ b/test/blackbox-tests/test-cases/pkg/ocamllsp/dev-tool-ocamllsp-relock-on-ocaml-version-change.t @@ -29,14 +29,6 @@ Initially ocamllsp will depend on ocaml-base-compiler.5.2.0 to match the project We can re-run "dune tools exec ocamllsp" without relocking or rebuilding. $ dune tools exec ocamllsp - The version of the compiler package ("ocaml-base-compiler") in this project's - lockdir has changed to 5.2.0 (formerly the compiler version was 5.2.0). The - dev-tool "ocaml-lsp-server" will be re-locked and rebuilt with this version - of the compiler. - Solution for _build/.dev-tools.locks/ocaml-lsp-server: - - ocaml-base-compiler.5.2.0 - - ocaml-compiler.5.2.0 - - ocaml-lsp-server.0.0.1 Running 'ocamllsp' hello from fake ocamllsp diff --git a/test/blackbox-tests/test-cases/pkg/odoc/dev-tool-odoc-relock-on-ocaml-version-change.t b/test/blackbox-tests/test-cases/pkg/odoc/dev-tool-odoc-relock-on-ocaml-version-change.t index 148b096483f..5fe837418db 100644 --- a/test/blackbox-tests/test-cases/pkg/odoc/dev-tool-odoc-relock-on-ocaml-version-change.t +++ b/test/blackbox-tests/test-cases/pkg/odoc/dev-tool-odoc-relock-on-ocaml-version-change.t @@ -34,14 +34,6 @@ Initially odoc will depend on ocaml-base-compiler.5.2.0 to match the project. We can re-run "dune ocaml doc" without relocking or rebuilding. $ DUNE_CONFIG__LOCK_DEV_TOOL=enabled dune ocaml doc - The version of the compiler package ("ocaml-base-compiler") in this project's - lockdir has changed to 5.2.0 (formerly the compiler version was 5.2.0). The - dev-tool "odoc" will be re-locked and rebuilt with this version of the - compiler. - Solution for _build/.dev-tools.locks/odoc: - - ocaml-base-compiler.5.2.0 - - ocaml-compiler.5.2.0 - - odoc.0.0.1 hello from fake odoc hello from fake odoc File "_doc/_html/_unknown_", line 1, characters 0-0: