Skip to content

Commit 1af52ea

Browse files
PizieDustpitag-ha
andauthored
Ensure dune version installed is appropriate (#1904)
* ensure dune version installed is appropriate * add changelong * Update src/dune.ml Co-authored-by: Sonja Heinze <[email protected]> * remove redundant * dune release versions have only a numeric output so dont check for dune keyword * log the dune version * for pre relase and alpha versions, we should only extract numeric values * bug fix, refactoring and logging * use the dune with the features we want * refactoring and bug fix * Update src/dune.ml Co-authored-by: Sonja Heinze <[email protected]> * remove ai comments * remove debugging artifacts --------- Co-authored-by: Sonja Heinze <[email protected]>
1 parent 1d3a0e8 commit 1af52ea

File tree

2 files changed

+112
-13
lines changed

2 files changed

+112
-13
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Unreleased
44

5+
- Check that the dune version installed supports DPM (Dune Package Management).
6+
Only if it does, add DPM to the list of available sandboxes. (#1904)
57
- Fix DPM (Dune Package Management) support for users with Dune installed via
68
Opam, Nix or similar. Previously, DPM support worked only when Dune was
79
installed using the installation script for the Dune binary distribution. (#1903)

src/dune.ml

Lines changed: 110 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,69 @@
11
open Import
22

3+
module Dune_version = struct
4+
type t =
5+
| Release of int * int * int
6+
| Preview of int * int * int
7+
8+
let parse_release_version version_str =
9+
let extract_int s =
10+
let digits = String.filter s ~f:Char.is_digit in
11+
if String.is_empty digits then None else Some (Int.of_string digits)
12+
in
13+
match String.split_on_chars ~on:[ '.' ] version_str with
14+
| [ major; minor; patch ] ->
15+
(match extract_int major, extract_int minor, extract_int patch with
16+
| Some major, Some minor, Some patch_num ->
17+
Some (Release (major, minor, patch_num))
18+
| _ -> None)
19+
| _ -> None
20+
;;
21+
22+
let parse_preview_version rest =
23+
match String.split_on_chars ~on:[ ',' ] rest with
24+
| timestamp_str :: _ ->
25+
(try
26+
Stdlib.Scanf.sscanf
27+
(String.strip timestamp_str)
28+
"%d-%d-%dT%d:%d:%dZ"
29+
(fun y m d _h _min _s -> Some (Preview (y, m, d)))
30+
with
31+
| Stdlib.Scanf.Scan_failure _ | End_of_file -> None)
32+
| _ -> None
33+
;;
34+
35+
let from_string str =
36+
let prefix = "\"Dune Developer Preview: build " in
37+
if String.is_prefix str ~prefix
38+
then (
39+
let rest = String.drop_prefix str (String.length prefix) in
40+
match parse_preview_version rest with
41+
| Some version -> Some version
42+
| None -> parse_release_version str)
43+
else parse_release_version str
44+
;;
45+
46+
(* Released versions >= 3.20.0 and preview versions with a timestamp on or
47+
after 2025-07-30 support everything needed for VSCode to support DPM,
48+
e.g. `dune lock`, `dune tools exec`, support of various Dune dev tools etc.
49+
The last feature needed was implemented on 2025-07-29 and ensures that
50+
other Dune dev tools (in particular ocamlformat) are included in the PATH
51+
of the `ocamllsp` process. *)
52+
let is_valid version =
53+
match version with
54+
| Release (major, minor, patch) ->
55+
Stdlib.compare (major, minor, patch) (3, 20, 0) >= 0
56+
| Preview (y, m, d) -> Stdlib.compare (y, m, d) (2025, 7, 30) >= 0
57+
;;
58+
end
59+
360
type t =
461
{ root : Path.t
562
; bin : Cmd.spawn
663
}
764

865
let binary = Path.of_string "dune"
966

10-
let make root () =
11-
let open Promise.Syntax in
12-
(* Should we do something specific for Windows ? *)
13-
match root with
14-
| Some root ->
15-
let spawn = { Cmd.bin = binary; args = [] } in
16-
let+ spawn = Cmd.check_spawn spawn in
17-
(match spawn with
18-
| Ok bin -> Some { bin; root }
19-
| Error _ -> None)
20-
| None -> Promise.return None
21-
;;
22-
2367
let is_project_locked t =
2468
(* Path to the dune.lock dir *)
2569
let dune_lock_path = Path.join t.root (Path.of_string "dune.lock") in
@@ -50,3 +94,56 @@ let exec_tool ~tool ?(args = []) t =
5094

5195
let equal d1 d2 = Path.equal d1.root d2.root
5296
let root t = t.root
97+
98+
let make root () =
99+
let open Promise.Syntax in
100+
let dune_version_output bin root =
101+
command { root; bin } ~args:[ "--version" ] |> Cmd.output ~cwd:root
102+
in
103+
(* Should we do something specific for Windows ? *)
104+
match root with
105+
| Some root ->
106+
let spawn = { Cmd.bin = binary; args = [] } in
107+
let* spawn = Cmd.check_spawn spawn in
108+
(match spawn with
109+
| Ok bin ->
110+
let+ dune_version_output = dune_version_output bin root in
111+
(match dune_version_output with
112+
| Ok v ->
113+
(match Dune_version.from_string v with
114+
| Some version when Dune_version.is_valid version ->
115+
show_message
116+
`Info
117+
"Dune Package Management selected with dune from %s, version %s."
118+
(Path.to_string binary)
119+
v;
120+
Some { bin; root }
121+
| _ -> None)
122+
| Error _err -> None)
123+
| Error _err ->
124+
let* check_if_dune_is_installed_with_opam =
125+
command
126+
{ root; bin = { Cmd.bin = Path.of_string "opam"; args = [] } }
127+
~args:[ "exec"; "--"; "which"; "dune" ]
128+
|> Cmd.output ~cwd:root
129+
in
130+
(match check_if_dune_is_installed_with_opam with
131+
| Error _err -> Promise.return None
132+
| Ok path when String.is_empty path -> Promise.return None
133+
| Ok path ->
134+
let bin = { Cmd.bin = Path.of_string path; args = [] } in
135+
let* dune_version_output = dune_version_output bin root in
136+
(match dune_version_output with
137+
| Ok v ->
138+
(match Dune_version.from_string v with
139+
| Some version when Dune_version.is_valid version ->
140+
show_message
141+
`Info
142+
"Dune Package Management selected with dune from %s, version %s."
143+
path
144+
v;
145+
Promise.return (Some { bin; root })
146+
| _ -> Promise.return None)
147+
| Error _err -> Promise.return None)))
148+
| None -> Promise.return None
149+
;;

0 commit comments

Comments
 (0)