Skip to content

Commit

Permalink
feature(pkg): add field to indicate ocaml package (#8079)
Browse files Browse the repository at this point in the history
We can now write:

```
(ocaml foo)
```

To designate the package `foo` as the one providing the ocaml toolchain.

Signed-off-by: Rudi Grinberg <me@rgrinberg.com>
  • Loading branch information
rgrinberg authored Jul 3, 2023
1 parent 78040cd commit 2c8c7a4
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 24 deletions.
51 changes: 34 additions & 17 deletions src/dune_pkg/lock_dir.ml
Original file line number Diff line number Diff line change
Expand Up @@ -251,24 +251,31 @@ end
type t =
{ version : Syntax.Version.t
; packages : Pkg.t Package_name.Map.t
; ocaml : (Loc.t * Package_name.t) option
}

let remove_locs t =
{ t with packages = Package_name.Map.map t.packages ~f:Pkg.remove_locs }
{ t with
packages = Package_name.Map.map t.packages ~f:Pkg.remove_locs
; ocaml = Option.map t.ocaml ~f:(fun (_, ocaml) -> (Loc.none, ocaml))
}

let equal { version; packages } t =
let equal { version; packages; ocaml } t =
Syntax.Version.equal version t.version
&& Option.equal (Tuple.T2.equal Loc.equal Package_name.equal) ocaml t.ocaml
&& Package_name.Map.equal packages t.packages ~equal:Pkg.equal

let to_dyn { version; packages } =
let to_dyn { version; packages; ocaml } =
Dyn.record
[ ("version", Syntax.Version.to_dyn version)
; ("packages", Package_name.Map.to_dyn Pkg.to_dyn packages)
; ( "ocaml"
, Dyn.option (Tuple.T2.to_dyn Loc.to_dyn_hum Package_name.to_dyn) ocaml )
]

let create_latest_version packages =
let create_latest_version packages ~ocaml =
let version = Syntax.greatest_supported_version Dune_lang.Pkg.syntax in
{ version; packages }
{ version; packages; ocaml }

let default_path = Path.Source.(relative root "dune.lock")

Expand All @@ -278,13 +285,21 @@ module Metadata = Dune_sexp.Versioned_file.Make (Unit)

let () = Metadata.Lang.register Dune_lang.Pkg.syntax ()

let encode_metadata t =
let encode_metadata { version; ocaml; packages = _ } =
let open Dune_lang.Encoder in
list sexp
[ string "lang"
; string (Syntax.name Dune_lang.Pkg.syntax)
; Dune_lang.Syntax.Version.encode t.version
]
let base =
list sexp
[ string "lang"
; string (Syntax.name Dune_lang.Pkg.syntax)
; Dune_lang.Syntax.Version.encode version
]
in
[ base ]
@
match ocaml with
| None -> []
| Some ocaml ->
[ list sexp [ string "ocaml"; Package_name.encode (snd ocaml) ] ]

module Package_filename = struct
type t = Filename.t
Expand All @@ -301,7 +316,7 @@ module Package_filename = struct
end

let file_contents_by_path t =
(metadata, [ encode_metadata t ])
(metadata, encode_metadata t)
:: (Package_name.Map.to_list t.packages
|> List.map ~f:(fun (name, pkg) ->
(Package_filename.of_package_name name, Pkg.encode pkg)))
Expand Down Expand Up @@ -376,13 +391,15 @@ end

let load_metadata_version source_path =
let open Or_exn.O in
let* syntax, version =
let* syntax, version, ocaml =
Metadata.load (Path.source source_path)
~f:(fun { Metadata.Lang.Instance.syntax; data = (); version } ->
Dune_lang.Decoder.return (syntax, version))
let open Dune_sexp.Decoder in
let+ ocaml = fields @@ field_o "ocaml" (located Package_name.decode) in
(syntax, version, ocaml))
in
if String.equal (Syntax.name syntax) (Syntax.name Dune_lang.Pkg.syntax) then
Ok version
Ok (version, ocaml)
else
Error
User_error.(
Expand Down Expand Up @@ -424,7 +441,7 @@ let read_disk ~lock_dir_path =
(Path.Source.to_string lock_dir_path)
]))
in
let* version =
let* version, ocaml =
load_metadata_version (Path.Source.relative lock_dir_path metadata)
in
let parser_context =
Expand All @@ -446,4 +463,4 @@ let read_disk ~lock_dir_path =
>>| fun pkg -> (package_name, pkg) ))
|> Result.List.all >>| Package_name.Map.of_list_exn
in
{ version; packages }
{ version; packages; ocaml }
4 changes: 3 additions & 1 deletion src/dune_pkg/lock_dir.mli
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ end
type t =
{ version : Syntax.Version.t
; packages : Pkg.t Package_name.Map.t
; ocaml : (Loc.t * Package_name.t) option
}

val remove_locs : t -> t
Expand All @@ -48,7 +49,8 @@ val equal : t -> t -> bool

val to_dyn : t -> Dyn.t

val create_latest_version : Pkg.t Package_name.Map.t -> t
val create_latest_version :
Pkg.t Package_name.Map.t -> ocaml:(Loc.t * Package_name.t) option -> t

val default_path : Path.Source.t

Expand Down
3 changes: 2 additions & 1 deletion src/dune_pkg/opam.ml
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ let solve_lock_dir ~version_preference ~repo_selection local_packages =
(sprintf "Solver selected multiple packages named \"%s\""
(Package_name.to_string name))
[]
| Ok pkgs_by_name -> Lock_dir.create_latest_version pkgs_by_name
| Ok pkgs_by_name ->
Lock_dir.create_latest_version pkgs_by_name ~ocaml:None
in
(summary, lock_dir))
10 changes: 7 additions & 3 deletions src/dune_rules/pkg_rules.ml
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,16 @@ module Lock_dir = struct
(* TODO *)
User_error.raise [ Pp.text "" ]
| Ok content ->
let* version =
let* version, ocaml =
Fs_memo.with_lexbuf_from_file
(In_source_dir (Path.Source.relative path metadata))
~f:(fun lexbuf ->
Metadata.parse_contents lexbuf ~f:(fun instance ->
Dune_sexp.Decoder.return instance.version))
let open Dune_sexp.Decoder in
let+ ocaml =
fields @@ field_o "ocaml" (located Package.Name.decode)
in
(instance.version, ocaml)))
in
let+ packages =
Fs_cache.Dir_contents.to_list content
Expand Down Expand Up @@ -135,7 +139,7 @@ module Lock_dir = struct
(name, package))
>>| Package.Name.Map.of_list_exn
in
{ packages; version })
{ packages; version; ocaml })
end

module Paths = struct
Expand Down
9 changes: 7 additions & 2 deletions test/expect-tests/dune_pkg/dune_pkg_unit_tests.ml
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,12 @@ let lock_dir_encode_decode_round_trip_test ~lock_dir_path ~lock_dir =

let%expect_test "encode/decode round trip test for lockdir with no deps" =
lock_dir_encode_decode_round_trip_test ~lock_dir_path:"empty_lock_dir"
~lock_dir:(Lock_dir.create_latest_version Package_name.Map.empty);
~lock_dir:
(Lock_dir.create_latest_version Package_name.Map.empty ~ocaml:None);
[%expect
{|
lockdir matches after roundtrip:
{ version = (0, 1); packages = map {} } |}]
{ version = (0, 1); packages = map {}; ocaml = None } |}]

let%expect_test "encode/decode round trip test for lockdir with simple deps" =
lock_dir_encode_decode_round_trip_test ~lock_dir_path:"simple_lock_dir"
Expand All @@ -195,6 +196,7 @@ let%expect_test "encode/decode round trip test for lockdir with simple deps" =
} )
in
Lock_dir.create_latest_version
~ocaml:(Some (Loc.none, Package_name.of_string "ocaml"))
(Package_name.Map.of_list_exn
[ mk_pkg_basic ~name:"foo" ~version:"0.1.0"
; mk_pkg_basic ~name:"bar" ~version:"0.2.0"
Expand Down Expand Up @@ -232,6 +234,7 @@ let%expect_test "encode/decode round trip test for lockdir with simple deps" =
; exported_env = []
}
}
; ocaml = Some ("simple_lock_dir/lock.dune:2", "ocaml")
} |}]

let%expect_test "encode/decode round trip test for lockdir with complex deps" =
Expand Down Expand Up @@ -326,6 +329,7 @@ let%expect_test "encode/decode round trip test for lockdir with complex deps" =
} )
in
Lock_dir.create_latest_version
~ocaml:(Some (Loc.none, Package_name.of_string "ocaml"))
(Package_name.Map.of_list_exn [ pkg_a; pkg_b; pkg_c ]));
[%expect
{|
Expand Down Expand Up @@ -380,4 +384,5 @@ let%expect_test "encode/decode round trip test for lockdir with complex deps" =
; exported_env = []
}
}
; ocaml = Some ("complex_lock_dir/lock.dune:2", "ocaml")
} |}]

0 comments on commit 2c8c7a4

Please sign in to comment.