From 64e49533b95f71bdd030298481939c5d56445191 Mon Sep 17 00:00:00 2001 From: Marek Kubica Date: Fri, 1 Sep 2023 15:27:01 +0200 Subject: [PATCH] feature(pkg): Opam repositories from dune-workspace Signed-off-by: Marek Kubica --- bin/pkg.ml | 163 +++++++++++------- src/dune_pkg/dune_pkg.ml | 1 + src/dune_pkg/lock_dir.ml | 103 ++++++++--- src/dune_pkg/lock_dir.mli | 8 +- src/dune_pkg/opam_repo.ml | 146 ++++++++++++---- src/dune_pkg/opam_repo.mli | 30 +++- src/dune_pkg/opam_solver.ml | 54 ++++-- src/dune_pkg/opam_solver.mli | 2 +- src/dune_pkg/solver_env.ml | 22 ++- src/dune_pkg/solver_env.mli | 3 + src/dune_pkg/workspace.ml | 48 ++++++ src/dune_pkg/workspace.mli | 24 +++ src/dune_rules/workspace.ml | 20 ++- src/dune_rules/workspace.mli | 1 + .../test-cases/pkg/command-from-user-path.t | 5 +- .../test-cases/pkg/default-exported-env.t | 7 +- .../test-cases/pkg/exported-env.t | 5 +- .../test-cases/pkg/external-source.t | 5 +- .../test-cases/pkg/extra-sources.t | 6 +- test/blackbox-tests/test-cases/pkg/gh8325.t | 5 +- .../test-cases/pkg/git-source.t | 5 +- test/blackbox-tests/test-cases/pkg/helpers.sh | 5 +- .../test-cases/pkg/install-action-dirs.t | 5 +- .../test-cases/pkg/install-action.t | 5 +- .../test-cases/pkg/install-missing-entry.t | 5 +- .../test-cases/pkg/installed-binary.t | 5 +- .../test-cases/pkg/just-print-solver-env.t | 6 + .../run.t | 8 + .../pkg/lockfile-generation.t/run.t | 8 + .../test-cases/pkg/opam-repository-download.t | 27 ++- .../test-cases/pkg/package-files.t | 5 +- .../test-cases/pkg/package-resolution-cycle.t | 5 +- test/blackbox-tests/test-cases/pkg/patch.t | 5 +- .../test-cases/pkg/per-context.t | 1 + .../test-cases/pkg/pkg-action-when.t | 5 +- .../test-cases/pkg/simple-lock.t | 5 +- .../test-cases/pkg/substitute.t | 5 +- .../test-cases/pkg/unknown-package.t | 5 +- .../blackbox-tests/test-cases/pkg/variables.t | 5 +- test/blackbox-tests/test-cases/pkg/withenv.t | 5 +- .../dune_pkg/dune_pkg_unit_tests.ml | 27 ++- 41 files changed, 559 insertions(+), 251 deletions(-) create mode 100644 src/dune_pkg/workspace.ml create mode 100644 src/dune_pkg/workspace.mli diff --git a/bin/pkg.ml b/bin/pkg.ml index 3bce3c58f0e..7ba21b2c673 100644 --- a/bin/pkg.ml +++ b/bin/pkg.ml @@ -1,6 +1,8 @@ open Import module Lock_dir = Dune_pkg.Lock_dir module Fetch = Dune_pkg.Fetch +module Opam_repo = Dune_pkg.Opam_repo +module Repository_id = Dune_pkg.Repository_id module Lock = struct module Opam_repository_path = struct @@ -96,8 +98,16 @@ module Lock = struct ; version_preference : Version_preference.t ; solver_env : Dune_pkg.Solver_env.t ; context_common : Dune_rules.Workspace.Context.Common.t + ; repos : + Dune_pkg.Pkg_workspace.Repository.t Dune_pkg.Pkg_workspace.Repository.Name.Map.t } + let repositories_of_workspace (workspace : Workspace.t) = + List.map workspace.repos ~f:(fun repo -> + Dune_pkg.Pkg_workspace.Repository.name repo, repo) + |> Dune_pkg.Pkg_workspace.Repository.Name.Map.of_list_exn + ;; + let choose ~context_name_arg ~all_contexts_arg ~version_preference_arg = let open Fiber.O in match context_name_arg, all_contexts_arg with @@ -134,6 +144,7 @@ module Lock = struct ~from_context:version_preference_context ; solver_env = Option.value solver_env ~default:Dune_pkg.Solver_env.default ; context_common + ; repos = repositories_of_workspace workspace } ] | Some (Opam _) -> @@ -162,6 +173,7 @@ module Lock = struct ~from_context:version_preference_context ; context_common ; solver_env = Option.value solver_env ~default:Dune_pkg.Solver_env.default + ; repos = repositories_of_workspace workspace } | Opam _ -> None) ;; @@ -346,72 +358,107 @@ module Lock = struct (* a list of thunks that will perform all the file IO side effects after performing validation so that if materializing any lockdir would fail then no side effect takes place. *) - (let+ opam_file_map = + (let* local_packages = let+ dune_package_map = let+ source_dir = Memo.run (Source_tree.root ()) in let project = Source_tree.Dir.project source_dir in Dune_project.packages project in opam_file_map_of_dune_package_map dune_package_map - and+ repo, repo_id = - let+ opam_repo_dir, repo_id = - match opam_repository_path with - | Some path -> - (* TODO determine repo_id here *) - let repo_id = Dune_pkg.Repository_id.of_path path in - Fiber.return (path, repo_id) - | None -> - let repo = - Option.map ~f:Fetch.Opam_repository.of_url opam_repository_url - |> Option.value ~default:Fetch.Opam_repository.default - in - let+ opam_repository = Fetch.Opam_repository.path repo in - (match opam_repository with - | Ok { path; repo_id } -> path, repo_id - | Error _ -> - User_error.raise - [ Pp.textf "Can't determine the location of the opam-repository" ]) - in - Dune_pkg.Opam_repo.of_opam_repo_dir_path opam_repo_dir, repo_id in - (* TODO figure out the loc situation *) - let repo_id = Option.map ~f:(fun repo_id -> Loc.none, repo_id) repo_id in - List.map - per_context - ~f: - (fun - { Per_context.lock_dir_path - ; version_preference - ; solver_env = solver_env_from_context - ; context_common = { name = context_name; _ } - } - -> - let solver_env = - merge_current_system_bindings_into_solver_env_from_context - ~context_name - ~solver_env_from_context - ~sys_bindings_from_current_system - ~use_env_from_current_system - in - match - Dune_pkg.Opam_solver.solve_lock_dir - solver_env - version_preference - (repo, repo_id) - ~local_packages:opam_file_map - with - | Error (`Diagnostic_message message) -> Error (context_name, message) - | Ok { Dune_pkg.Opam_solver.Solver_result.summary; lock_dir; files } -> - let summary_message = - Dune_pkg.Opam_solver.Summary.selected_packages_message - summary - ~lock_dir_path - |> User_message.pp + let* solutions = + List.map + per_context + ~f: + (fun + { Per_context.lock_dir_path + ; version_preference + ; repos + ; solver_env = solver_env_from_context + ; context_common = { name = context_name; _ } + } + -> + let solver_env = + merge_current_system_bindings_into_solver_env_from_context + ~context_name + ~solver_env_from_context + ~sys_bindings_from_current_system + ~use_env_from_current_system + in + let+ repos = + match opam_repository_path, opam_repository_url with + | Some _, Some _ -> + (* in theory you can set both, but how to prioritize them? *) + User_error.raise + [ Pp.text "Can't specify both path and URL to an opam-repository" ] + | Some path, None -> + let repo_id = Repository_id.of_path path in + Fiber.return + @@ [ Opam_repo.of_opam_repo_dir_path ~source:None ~repo_id path ] + | None, Some url -> + let repo = Fetch.Opam_repository.of_url url in + let+ opam_repository = Fetch.Opam_repository.path repo in + (match opam_repository with + | Ok { path; repo_id } -> + [ Opam_repo.of_opam_repo_dir_path + ~source:(Some (OpamUrl.to_string url)) + ~repo_id + path + ] + | Error _ -> + User_error.raise + [ Pp.text "Can't determine the location of the opam-repository" ]) + | None, None -> + (* read from workspace *) + solver_env + |> Dune_pkg.Solver_env.repos + |> List.map ~f:(fun name -> + match Dune_pkg.Pkg_workspace.Repository.Name.Map.find repos name with + | None -> + (* TODO: have loc for this failure? *) + User_error.raise + [ Pp.textf "Repository '%s' is not a known repository" + @@ Dune_pkg.Pkg_workspace.Repository.Name.to_string name + ] + | Some repo -> + let url = Dune_pkg.Pkg_workspace.Repository.opam_url repo in + let repo = Fetch.Opam_repository.of_url url in + let+ opam_repository = Fetch.Opam_repository.path repo in + (match opam_repository with + | Ok { path; repo_id } -> + Opam_repo.of_opam_repo_dir_path + ~source:(Some (OpamUrl.to_string url)) + ~repo_id + path + | Error _ -> + User_error.raise + [ Pp.textf + "Can't determine the location of the opam-repository '%s'" + @@ Dune_pkg.Pkg_workspace.Repository.Name.to_string name + ])) + |> Fiber.all_concurrently in - Ok - ( Lock_dir.Write_disk.prepare ~lock_dir_path ~files lock_dir - , summary_message )) - |> Result.List.all) + match + Dune_pkg.Opam_solver.solve_lock_dir + solver_env + version_preference + repos + ~local_packages + with + | Error (`Diagnostic_message message) -> Error (context_name, message) + | Ok { Dune_pkg.Opam_solver.Solver_result.summary; lock_dir; files } -> + let summary_message = + Dune_pkg.Opam_solver.Summary.selected_packages_message + summary + ~lock_dir_path + |> User_message.pp + in + Ok + ( Lock_dir.Write_disk.prepare ~lock_dir_path ~files lock_dir + , summary_message )) + |> Fiber.all_concurrently + in + Result.List.all solutions |> Fiber.return) >>| function | Error (context_name, message) -> User_error.raise diff --git a/src/dune_pkg/dune_pkg.ml b/src/dune_pkg/dune_pkg.ml index ced0e283b46..00b5c086322 100644 --- a/src/dune_pkg/dune_pkg.ml +++ b/src/dune_pkg/dune_pkg.ml @@ -10,3 +10,4 @@ module Solver_env = Solver_env module Substs = Substs module Sys_poll = Sys_poll module Version_preference = Version_preference +module Pkg_workspace = Workspace diff --git a/src/dune_pkg/lock_dir.ml b/src/dune_pkg/lock_dir.ml index 5a4de38528b..c9fae38e8fb 100644 --- a/src/dune_pkg/lock_dir.ml +++ b/src/dune_pkg/lock_dir.ml @@ -261,40 +261,91 @@ module Pkg = struct ;; end +module Repositories = struct + type t = + { complete : bool + ; used : Opam_repo.Serializable.t list option + } + + let equal { complete; used } t = + Bool.equal complete t.complete + && Option.equal (List.equal Opam_repo.Serializable.equal) used t.used + ;; + + let to_dyn { complete; used } = + Dyn.record + [ "complete", Dyn.bool complete + ; "used", Dyn.option (Dyn.list Opam_repo.Serializable.to_dyn) used + ] + ;; + + let encode_used used = + let open Encoder in + List.map ~f:(fun repo -> list sexp @@ Opam_repo.Serializable.encode repo) used + ;; + + let encode { complete; used } = + let open Encoder in + let base = list sexp [ string "complete"; bool complete ] in + [ base ] + @ + match used with + | None -> [] + | Some [] -> [ list sexp [ string "used" ] ] + | Some used -> [ list sexp (string "used" :: encode_used used) ] + ;; + + let decode = + let open Decoder in + fields + (let+ complete = field "complete" bool + and+ used = field_o "used" (repeat (enter Opam_repo.Serializable.decode)) in + { complete; used }) + ;; +end + type t = { version : Syntax.Version.t ; packages : Pkg.t Package_name.Map.t ; ocaml : (Loc.t * Package_name.t) option - ; repo_id : (Loc.t * Repository_id.t) option + ; repos : Repositories.t } let remove_locs t = { t with packages = Package_name.Map.map t.packages ~f:Pkg.remove_locs ; ocaml = Option.map t.ocaml ~f:(fun (_, ocaml) -> Loc.none, ocaml) - ; repo_id = Option.map t.repo_id ~f:(fun (_, repo_id) -> Loc.none, repo_id) } ;; -let equal { version; packages; ocaml; repo_id } t = +let equal { version; packages; ocaml; repos } t = Syntax.Version.equal version t.version && Option.equal (Tuple.T2.equal Loc.equal Package_name.equal) ocaml t.ocaml - && Option.equal (Tuple.T2.equal Loc.equal Repository_id.equal) repo_id t.repo_id + && Repositories.equal repos t.repos && Package_name.Map.equal packages t.packages ~equal:Pkg.equal ;; -let to_dyn { version; packages; ocaml; repo_id } = +let to_dyn { version; packages; ocaml; repos } = 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 - ; "repo_id", Dyn.option (Tuple.T2.to_dyn Loc.to_dyn_hum Repository_id.to_dyn) repo_id + ; "repos", Repositories.to_dyn repos ] ;; -let create_latest_version packages ~ocaml ~repo_id = +let create_latest_version packages ~ocaml ~repos = let version = Syntax.greatest_supported_version Dune_lang.Pkg.syntax in - { version; packages; ocaml; repo_id } + let complete, used = + match repos with + | None -> true, None + | Some repos -> + let used = List.filter_map repos ~f:Opam_repo.serializable in + let complete = Int.equal (List.length repos) (List.length used) in + complete, Some used + in + let repos : Repositories.t = { complete; used } in + { version; packages; ocaml; repos } ;; let default_path = Path.Source.(relative root "dune.lock") @@ -304,7 +355,7 @@ module Metadata = Dune_sexp.Versioned_file.Make (Unit) let () = Metadata.Lang.register Dune_lang.Pkg.syntax () -let encode_metadata { version; ocaml; repo_id; packages = _ } = +let encode_metadata { version; ocaml; repos; packages = _ } = let open Encoder in let base = list @@ -318,10 +369,15 @@ let encode_metadata { version; ocaml; repo_id; packages = _ } = @ (match ocaml with | None -> [] | Some ocaml -> [ list sexp [ string "ocaml"; Package_name.encode (snd ocaml) ] ]) - @ - match repo_id with - | None -> [] - | Some repo_id -> [ list sexp [ string "repo_id"; Repository_id.encode (snd repo_id) ] ] + @ [ list sexp (string "repositories" :: Repositories.encode repos) ] +;; + +let decode_metadata = + let open Decoder in + fields + (let+ ocaml = field_o "ocaml" (located Package_name.decode) + and+ repos = field "repositories" Repositories.decode in + ocaml, repos) ;; module Package_filename = struct @@ -361,8 +417,8 @@ module Write_disk = struct (match Path.exists metadata_path && not (Path.is_directory metadata_path) with | false -> Error `No_metadata_file | true -> - (match Metadata.load metadata_path ~f:(Fun.const (Decoder.return ())) with - | Ok () -> Ok `Is_existing_lock_dir + (match Metadata.load metadata_path ~f:(Fun.const decode_metadata) with + | Ok _unused -> Ok `Is_existing_lock_dir | Error exn -> Error (`Failed_to_parse_metadata exn)))) ;; @@ -443,22 +499,17 @@ module Make_load (Io : sig struct let load_metadata metadata_file_path = let open Io.O in - let+ syntax, version, ocaml, repo_id = + let+ syntax, version, ocaml, repos = Io.with_lexbuf_from_file metadata_file_path ~f:(fun lexbuf -> Metadata.parse_contents lexbuf ~f:(fun { Metadata.Lang.Instance.syntax; data = (); version } -> let open Decoder in - let+ ocaml, repo_id = - fields - (let+ ocaml = field_o "ocaml" (located Package_name.decode) - and+ repo_id = field_o "repo_id" (located Repository_id.decode) in - ocaml, repo_id) - in - syntax, version, ocaml, repo_id)) + let+ ocaml, repos = decode_metadata in + syntax, version, ocaml, repos)) in if String.equal (Syntax.name syntax) (Syntax.name Dune_lang.Pkg.syntax) - then version, ocaml, repo_id + then version, ocaml, repos else User_error.raise [ Pp.textf @@ -506,7 +557,7 @@ struct let load lock_dir_path = let open Io.O in check_path lock_dir_path; - let* version, ocaml, repo_id = + let* version, ocaml, repos = load_metadata (Path.Source.relative lock_dir_path metadata) in let+ packages = @@ -522,7 +573,7 @@ struct package_name, pkg) >>| Package_name.Map.of_list_exn in - { version; packages; ocaml; repo_id } + { version; packages; ocaml; repos } ;; end diff --git a/src/dune_pkg/lock_dir.mli b/src/dune_pkg/lock_dir.mli index b8f5c125169..dada36c00c0 100644 --- a/src/dune_pkg/lock_dir.mli +++ b/src/dune_pkg/lock_dir.mli @@ -38,11 +38,15 @@ module Pkg : sig val decode : (lock_dir:Path.Source.t -> Package_name.t -> t) Dune_sexp.Decoder.t end +module Repositories : sig + type t +end + type t = { version : Syntax.Version.t ; packages : Pkg.t Package_name.Map.t ; ocaml : (Loc.t * Package_name.t) option - ; repo_id : (Loc.t * Repository_id.t) option + ; repos : Repositories.t } val remove_locs : t -> t @@ -52,7 +56,7 @@ val to_dyn : t -> Dyn.t val create_latest_version : Pkg.t Package_name.Map.t -> ocaml:(Loc.t * Package_name.t) option - -> repo_id:(Loc.t * Repository_id.t) option + -> repos:Opam_repo.t list option -> t val default_path : Path.Source.t diff --git a/src/dune_pkg/opam_repo.ml b/src/dune_pkg/opam_repo.ml index 968ef661f4f..faf4f06fc46 100644 --- a/src/dune_pkg/opam_repo.ml +++ b/src/dune_pkg/opam_repo.ml @@ -1,10 +1,59 @@ open! Stdune +module Encoder = Dune_lang.Encoder +module Decoder = Dune_lang.Decoder let ( / ) = Path.relative -type t = { packages_dir_path : Path.t } +module Serializable = struct + type t = + { repo_id : Repository_id.t option + ; source : string + } + + let equal { repo_id; source } t = + Option.equal Repository_id.equal repo_id t.repo_id && String.equal source t.source + ;; + + let to_dyn { repo_id; source } = + let open Dyn in + variant + "opam_repo_serializable" + [ option Repository_id.to_dyn repo_id; string source ] + ;; + + let encode { repo_id; source } = + let open Encoder in + record_fields + [ field "source" string source; field_o "repo_id" Repository_id.encode repo_id ] + ;; + + let decode = + let open Decoder in + fields + (let+ source = field "source" string + and+ repo_id = field_o "repo_id" Repository_id.decode in + { repo_id; source }) + ;; +end + +type t = + { packages_dir_path : Path.t + ; serializable : Serializable.t option + } + +let equal { packages_dir_path; serializable } t = + Path.equal packages_dir_path t.packages_dir_path + && Option.equal Serializable.equal serializable t.serializable +;; let minimum_opam_version = OpamVersion.of_string "2.0" +let serializable { serializable; _ } = serializable + +let repo_id t = + let open Option.O in + let* serializable = serializable t in + serializable.repo_id +;; let validate_repo_file opam_repo_dir_path = let opam_repo_file_path = opam_repo_dir_path / "repo" in @@ -54,7 +103,7 @@ let validate_repo_file opam_repo_dir_path = ] ;; -let of_opam_repo_dir_path opam_repo_dir_path = +let of_opam_repo_dir_path ~source ~repo_id opam_repo_dir_path = if not (Path.exists opam_repo_dir_path) then User_error.raise @@ -74,62 +123,83 @@ let of_opam_repo_dir_path opam_repo_dir_path = (Path.to_string_maybe_quoted opam_repo_dir_path) ]; validate_repo_file opam_repo_dir_path; - { packages_dir_path } + let serializable = + Option.map source ~f:(fun source -> { Serializable.repo_id; source }) + in + { packages_dir_path; serializable } +;; + +let if_exists p = + match Path.exists p with + | false -> None + | true -> Some p ;; (* Return the path to the directory containing the version directories for a package name *) -let get_opam_package_version_dir_path t opam_package_name = - t.packages_dir_path / OpamPackage.Name.to_string opam_package_name +let get_opam_package_version_dir_path { packages_dir_path; _ } opam_package_name = + let p = packages_dir_path / OpamPackage.Name.to_string opam_package_name in + if_exists p ;; (* Return the path to an "opam" file describing a particular package (name and version) from this opam repository. *) let get_opam_file_path t opam_package = - get_opam_package_version_dir_path t (OpamPackage.name opam_package) - / OpamPackage.to_string opam_package - / "opam" + let open Option.O in + let* base = get_opam_package_version_dir_path t (OpamPackage.name opam_package) in + base / OpamPackage.to_string opam_package / "opam" |> if_exists ;; let get_opam_package_files_path t opam_package = - get_opam_package_version_dir_path t (OpamPackage.name opam_package) - / OpamPackage.to_string opam_package - / "files" + let open Option.O in + let* base = get_opam_package_version_dir_path t (OpamPackage.name opam_package) in + base / OpamPackage.to_string opam_package / "files" |> if_exists ;; (* Returns a list containing all versions of a package with a given name *) let all_package_versions t opam_package_name = - let version_dir_path = get_opam_package_version_dir_path t opam_package_name in - if Path.exists version_dir_path - then ( - match Path.readdir_unsorted version_dir_path with - | Error e -> - User_error.raise - [ Pp.textf - "Unable to read package versions from %s: %s" - (Path.to_string_maybe_quoted version_dir_path) - (Dune_filesystem_stubs.Unix_error.Detailed.to_string_hum e) - ] - | Ok version_dirs -> Ok (List.map version_dirs ~f:OpamPackage.of_string)) - else Error `Package_not_found + let open Option.O in + let* version_dir_path = get_opam_package_version_dir_path t opam_package_name in + match Path.readdir_unsorted version_dir_path with + | Error e -> + User_error.raise + [ Pp.textf + "Unable to read package versions from %s: %s" + (Path.to_string_maybe_quoted version_dir_path) + (Dune_filesystem_stubs.Unix_error.Detailed.to_string_hum e) + ] + | Ok version_dirs -> Some (List.map version_dirs ~f:OpamPackage.of_string) ;; (* Reads an opam package definition from an "opam" file in this repository corresponding to a package (name and version). *) let load_opam_package t opam_package = - let opam_file_path = get_opam_file_path t opam_package in - if not (Path.exists opam_file_path) - then - User_error.raise - [ Pp.textf - "Couldn't find package file for \"%s\". It was expected to be located in %s \ - but this file does not exist" - (OpamPackage.to_string opam_package) - (Path.to_string_maybe_quoted opam_file_path) - ]; - OpamFile.OPAM.read (OpamFile.make (OpamFilename.raw (Path.to_string opam_file_path))) + let open Option.O in + let* opam_file_path = get_opam_file_path t opam_package in + Some + (OpamFile.OPAM.read + (OpamFile.make (OpamFilename.raw (Path.to_string opam_file_path)))) ;; -let load_all_versions t opam_package_name = - all_package_versions t opam_package_name - |> Result.map ~f:(List.map ~f:(load_opam_package t)) +let load_all_versions ts opam_package_name = + let versions = + List.filter_map ts ~f:(fun t -> all_package_versions t opam_package_name) + in + match versions with + | [] -> Error `Package_not_found + | pkgs -> + pkgs + |> List.concat + |> List.filter_map ~f:(fun opam_pkg -> + List.find_map ts ~f:(fun t -> load_opam_package t opam_pkg)) + |> Result.ok ;; + +module Private = struct + let create ?source ?repo_id () = + let packages_dir_path = Path.of_string "/" in + let serializable = + Option.map source ~f:(fun source -> { Serializable.repo_id; source }) + in + { packages_dir_path; serializable } + ;; +end diff --git a/src/dune_pkg/opam_repo.mli b/src/dune_pkg/opam_repo.mli index 7f2dcb556c3..246c983a84c 100644 --- a/src/dune_pkg/opam_repo.mli +++ b/src/dune_pkg/opam_repo.mli @@ -2,17 +2,39 @@ open! Stdune type t +module Serializable : sig + type t + + val encode : t -> Dune_lang.t list + val decode : t Dune_lang.Decoder.t + val equal : t -> t -> bool + val to_dyn : t -> Dyn.t +end + +val equal : t -> t -> bool + (** [of_opam_repo_dir_path opam_repo_dir] creates a repo representedy by a local directory in the path given by [opam_repo_dir]. *) -val of_opam_repo_dir_path : Path.t -> t +val of_opam_repo_dir_path + : source:string option + -> repo_id:Repository_id.t option + -> Path.t + -> t + +val repo_id : t -> Repository_id.t option +val serializable : t -> Serializable.t option (** Load package metadata for a single package *) -val load_opam_package : t -> OpamPackage.t -> OpamFile.OPAM.t +val load_opam_package : t -> OpamPackage.t -> OpamFile.OPAM.t option (** Load package metadata for all versions of a package with a given name *) val load_all_versions - : t + : t list -> OpamPackage.Name.t -> (OpamFile.OPAM.t list, [ `Package_not_found ]) result -val get_opam_package_files_path : t -> OpamPackage.t -> Path.t +val get_opam_package_files_path : t -> OpamPackage.t -> Path.t option + +module Private : sig + val create : ?source:string -> ?repo_id:Repository_id.t -> unit -> t +end diff --git a/src/dune_pkg/opam_solver.ml b/src/dune_pkg/opam_solver.ml index 45bd4862af4..946c4755df8 100644 --- a/src/dune_pkg/opam_solver.ml +++ b/src/dune_pkg/opam_solver.ml @@ -91,14 +91,14 @@ module Context_for_dune = struct ;; type t = - { repo : Opam_repo.t + { repos : Opam_repo.t list ; version_preference : Version_preference.t ; local_packages : OpamFile.OPAM.t OpamPackage.Name.Map.t ; solver_env : Solver_env.t } - let create ~solver_env ~repo ~local_packages ~version_preference = - { repo; version_preference; local_packages; solver_env } + let create ~solver_env ~repos ~local_packages ~version_preference = + { repos; version_preference; local_packages; solver_env } ;; type rejection = Unavailable @@ -162,7 +162,7 @@ module Context_for_dune = struct in [ version, Ok opam_file ] | None -> - (match Opam_repo.load_all_versions t.repo name with + (match Opam_repo.load_all_versions t.repos name with | Error `Package_not_found -> (* The CONTEXT interface doesn't give us a way to report this type of error and there's not enough context to give a helpful error message @@ -417,13 +417,20 @@ let make_action = function | actions -> Some (Action.Progn actions) ;; -let opam_package_to_lock_file_pkg ~repo ~local_packages opam_package = +let opam_package_to_lock_file_pkg ~repos ~local_packages opam_package = let name = OpamPackage.name opam_package in let version = OpamPackage.version opam_package |> OpamPackage.Version.to_string in let dev = OpamPackage.Name.Map.mem name local_packages in let opam_file = match OpamPackage.Name.Map.find_opt name local_packages with - | None -> Opam_repo.load_opam_package repo opam_package + | None -> + let opam_files = + List.filter_map repos ~f:(fun repo -> + Opam_repo.load_opam_package repo opam_package) + in + (match opam_files with + | [ opam_file ] -> opam_file + | _ -> Code_error.raise "Couldn't map opam package to a repository" []) | Some local_package -> local_package in let extra_sources = @@ -525,7 +532,7 @@ let solve_package_list local_packages context = (* Scan a path recursively down retrieving a list of all files together with their relative path. *) -let scan_files_entries ~repo_id path = +let scan_files_entries path = (* TODO Add some cycle detection *) let rec read acc dir = let path = Path.append_local path dir in @@ -542,7 +549,6 @@ let scan_files_entries ~repo_id path = | Error (Unix.ENOENT, _, _) -> acc | Error err -> User_error.raise - ?loc:(Option.map ~f:fst repo_id) [ Pp.text "Unable to read file in opam repository:"; Unix_error.Detailed.pp err ] in read [] Path.Local.root @@ -560,12 +566,12 @@ module Solver_result = struct } end -let solve_lock_dir solver_env version_preference (repo, repo_id) ~local_packages = +let solve_lock_dir solver_env version_preference repos ~local_packages = let is_local_package package = OpamPackage.Name.Map.mem (OpamPackage.name package) local_packages in let context = - Context_for_dune.create ~solver_env ~repo ~version_preference ~local_packages + Context_for_dune.create ~solver_env ~repos ~version_preference ~local_packages in solve_package_list local_packages context |> Result.map ~f:(fun solution -> @@ -575,7 +581,7 @@ let solve_lock_dir solver_env version_preference (repo, repo_id) ~local_packages let lock_dir = match Package_name.Map.of_list_map opam_packages_to_lock ~f:(fun opam_package -> - let pkg = opam_package_to_lock_file_pkg ~repo ~local_packages opam_package in + let pkg = opam_package_to_lock_file_pkg ~repos ~local_packages opam_package in pkg.info.name, pkg) with | Error (name, _pkg1, _pkg2) -> @@ -585,16 +591,26 @@ let solve_lock_dir solver_env version_preference (repo, repo_id) ~local_packages (Package_name.to_string name)) [] | Ok pkgs_by_name -> - Lock_dir.create_latest_version pkgs_by_name ~ocaml:None ~repo_id + Lock_dir.create_latest_version pkgs_by_name ~ocaml:None ~repos:(Some repos) in let files = - Package_name.Map.of_list_map_exn opam_packages_to_lock ~f:(fun opam_package -> - let files_path = Opam_repo.get_opam_package_files_path repo opam_package in - ( Package_name.of_string - (OpamPackage.Name.to_string (OpamPackage.name opam_package)) - , scan_files_entries ~repo_id files_path )) - |> Package_name.Map.filter_map ~f:(fun files -> - if List.is_empty files then None else Some files) + opam_packages_to_lock + |> List.filter_map ~f:(fun opam_package -> + let files_path = + List.find_map repos ~f:(fun repo -> + Opam_repo.get_opam_package_files_path repo opam_package) + in + match files_path with + | None -> None + | Some files_path -> + (match scan_files_entries files_path with + | [] -> None + | files -> + Some + ( Package_name.of_string + (OpamPackage.Name.to_string (OpamPackage.name opam_package)) + , files ))) + |> Package_name.Map.of_list_exn in { Solver_result.summary; lock_dir; files }) ;; diff --git a/src/dune_pkg/opam_solver.mli b/src/dune_pkg/opam_solver.mli index 441962d83d0..2120c271b9b 100644 --- a/src/dune_pkg/opam_solver.mli +++ b/src/dune_pkg/opam_solver.mli @@ -19,6 +19,6 @@ end val solve_lock_dir : Solver_env.t -> Version_preference.t - -> Opam_repo.t * (Loc.t * Repository_id.t) option + -> Opam_repo.t list -> local_packages:OpamFile.OPAM.t OpamTypes.name_map -> (Solver_result.t, [ `Diagnostic_message of _ Pp.t ]) result diff --git a/src/dune_pkg/solver_env.ml b/src/dune_pkg/solver_env.ml index 5e718ee7ab7..9495b3d3267 100644 --- a/src/dune_pkg/solver_env.ml +++ b/src/dune_pkg/solver_env.ml @@ -210,18 +210,21 @@ type t = { flags : Variable.Flag.Set.t ; sys : Variable.Sys.Bindings.t ; const : Variable.Const.Bindings.t + ; repos : Workspace.Repository.Name.t list } module Fields = struct let flags = "flags" let sys = "sys" let const = "const" + let repos = "repositories" end let default = { flags = Variable.Flag.Set.all ; sys = Variable.Sys.Bindings.empty ; const = Variable.Const.bindings + ; repos = [ Workspace.Repository.Name.of_string ":standard" ] (* TODO *) } ;; @@ -229,30 +232,36 @@ let decode = let open Decoder in fields @@ let+ flags = field Fields.flags ~default:default.flags Variable.Flag.Set.decode - and+ sys = field Fields.sys ~default:default.sys Variable.Sys.Bindings.decode in + and+ sys = field Fields.sys ~default:default.sys Variable.Sys.Bindings.decode + and+ repos = + field Fields.repos ~default:default.repos (repeat Workspace.Repository.Name.decode) + in let const = default.const in - { flags; sys; const } + { flags; sys; const; repos } ;; -let to_dyn { flags; sys; const } = +let to_dyn { flags; sys; const; repos } = Dyn.record [ Fields.flags, Variable.Flag.Set.to_dyn flags ; Fields.sys, Variable.Sys.Bindings.to_dyn sys ; Fields.const, Variable.Const.Bindings.to_dyn const + ; Fields.repos, Dyn.list Workspace.Repository.Name.to_dyn repos ] ;; -let equal { flags; sys; const } t = +let equal { flags; sys; const; repos } t = Variable.Flag.Set.equal flags t.flags && Variable.Sys.Bindings.equal sys t.sys && Variable.Const.Bindings.equal const t.const + && List.equal Workspace.Repository.Name.equal repos t.repos ;; let sys { sys; _ } = sys let set_sys t sys = { t with sys } let clear_flags t = { t with flags = Variable.Flag.Set.empty } +let repos { repos; _ } = repos -let pp { flags; sys; const } = +let pp { flags; sys; const; repos } = let pp_section heading pp_section = (* The hbox is to prevent long values in [pp_section] from causing the heading to wrap. *) let pp_heading = Pp.hbox (Pp.text heading) in @@ -263,6 +272,9 @@ let pp { flags; sys; const } = [ pp_section "Flags" (Variable.Flag.Set.pp flags) ; pp_section "System Environment Variables" (Variable.Sys.Bindings.pp sys) ; pp_section "Constants" (Variable.Const.Bindings.pp const) + ; pp_section + "Repositories" + (Pp.chain repos ~f:(fun r -> Workspace.Repository.Name.pp r)) ] ;; diff --git a/src/dune_pkg/solver_env.mli b/src/dune_pkg/solver_env.mli index 9c4795bdc0c..5308bb2b42b 100644 --- a/src/dune_pkg/solver_env.mli +++ b/src/dune_pkg/solver_env.mli @@ -73,6 +73,9 @@ val equal : t -> t -> bool val sys : t -> Variable.Sys.Bindings.t val set_sys : t -> Variable.Sys.Bindings.t -> t +(** [repos t] returns the selected repository names in priority order *) +val repos : t -> Workspace.Repository.Name.t list + (** Set all the flags to false *) val clear_flags : t -> t diff --git a/src/dune_pkg/workspace.ml b/src/dune_pkg/workspace.ml new file mode 100644 index 00000000000..530f71d1da5 --- /dev/null +++ b/src/dune_pkg/workspace.ml @@ -0,0 +1,48 @@ +open Import + +module Repository = struct + module Name = struct + include String + + let pp v = Pp.text v + + include ( + Stringlike.Make (struct + type nonrec t = t + + let description_of_valid_string = None + let hint_valid = None + let to_string t = t + let module_ = "Repository.Name" + let description = "Opam Repository name" + let of_string_opt name = Some name + end) : + Stringlike with type t := t) + end + + type t = + { name : Name.t + ; source : string + } + + let name { name; _ } = name + + let to_dyn { name; source } = + let open Dyn in + variant "repository" [ Name.to_dyn name; string source ] + ;; + + let equal { name; source } t = Name.equal name t.name && String.equal source t.source + let hash { name; source } = Tuple.T2.hash Name.hash String.hash (name, source) + let default = { name = ":standard"; source = "https://opam.ocaml.org/index.tar.gz" } + + let decode = + let open Dune_lang.Decoder in + fields + (let+ name = field "name" Name.decode + and+ source = field "source" string in + { name; source }) + ;; + + let opam_url { source; _ } = OpamUrl.of_string source +end diff --git a/src/dune_pkg/workspace.mli b/src/dune_pkg/workspace.mli new file mode 100644 index 00000000000..dd1f5e532d9 --- /dev/null +++ b/src/dune_pkg/workspace.mli @@ -0,0 +1,24 @@ +open Import + +module Repository : sig + type t + + val opam_url : t -> OpamUrl.t + val hash : t -> int + val to_dyn : t -> Dyn.t + val equal : t -> t -> bool + val default : t + val decode : t Decoder.t + + module Name : sig + type t + + val equal : t -> t -> bool + val pp : t -> 'a Pp.t + + include Stringlike with type t := t + include Comparable_intf.S with type key := t + end + + val name : t -> Name.t +end diff --git a/src/dune_rules/workspace.ml b/src/dune_rules/workspace.ml index d2d5be1c56d..ec0fa496550 100644 --- a/src/dune_rules/workspace.ml +++ b/src/dune_rules/workspace.ml @@ -1,5 +1,6 @@ open Import open Dune_lang.Decoder +module Repository = Dune_pkg.Pkg_workspace.Repository (* workspace files use the same version numbers as dune-project files for simplicity *) @@ -424,31 +425,35 @@ type t = ; contexts : Context.t list ; env : Dune_env.Stanza.t option ; config : Dune_config.t + ; repos : Dune_pkg.Pkg_workspace.Repository.t list } -let to_dyn { merlin_context; contexts; env; config } = +let to_dyn { merlin_context; contexts; env; config; repos } = let open Dyn in record [ "merlin_context", option Context_name.to_dyn merlin_context ; "contexts", list Context.to_dyn contexts ; "env", option Dune_env.Stanza.to_dyn env ; "config", Dune_config.to_dyn config + ; "repos", list Repository.to_dyn repos ] ;; -let equal { merlin_context; contexts; env; config } w = +let equal { merlin_context; contexts; env; config; repos } w = Option.equal Context_name.equal merlin_context w.merlin_context && List.equal Context.equal contexts w.contexts && Option.equal Dune_env.Stanza.equal env w.env && Dune_config.equal config w.config + && List.equal Repository.equal repos w.repos ;; -let hash { merlin_context; contexts; env; config } = +let hash { merlin_context; contexts; env; config; repos } = Poly.hash ( Option.hash Context_name.hash merlin_context , List.hash Context.hash contexts , Option.hash Dune_env.Stanza.hash env - , Dune_config.hash config ) + , Dune_config.hash config + , List.hash Repository.hash repos ) ;; include Dune_lang.Versioned_file.Make (struct @@ -551,7 +556,7 @@ let create_final_config ++ config_from_command_line ;; -(* We load the configuration it two steps: +(* We load the configuration in two steps: - step1: we eagerly interpret all the bits that are common to the workspace file and the user configuration file. The other fields are left under a lazy @@ -590,6 +595,7 @@ let step1 clflags = superpose_with_command_line cl_profile (field "profile" (lazy_ Profile.decode) ~default:(lazy Profile.default)) + and+ repos = multi_field "repository" (lazy_ Repository.decode) and+ instrument_with = superpose_with_command_line cl_instrument_with @@ -619,6 +625,7 @@ let step1 clflags = in let defined_names = ref Context_name.Set.empty in let env = Lazy.force env in + let repos = Repository.default :: List.map ~f:Lazy.force repos in let merlin_context = List.fold_left contexts ~init:None ~f:(fun acc ctx -> let name = Context.name ctx in @@ -662,7 +669,7 @@ let step1 clflags = then Some Context_name.default else None in - { merlin_context; contexts = top_sort (List.rev contexts); env; config }) + { merlin_context; contexts = top_sort (List.rev contexts); env; config; repos }) in { Step1.t; config } ;; @@ -691,6 +698,7 @@ let default clflags = ; contexts = [ Context.default ~x ~profile ~instrument_with ] ; env = None ; config + ; repos = [ Repository.default ] } ;; diff --git a/src/dune_rules/workspace.mli b/src/dune_rules/workspace.mli index e5e27250eea..244bbd363aa 100644 --- a/src/dune_rules/workspace.mli +++ b/src/dune_rules/workspace.mli @@ -79,6 +79,7 @@ type t = private ; contexts : Context.t list ; env : Dune_env.Stanza.t option ; config : Dune_config.t + ; repos : Dune_pkg.Pkg_workspace.Repository.t list } val equal : t -> t -> bool diff --git a/test/blackbox-tests/test-cases/pkg/command-from-user-path.t b/test/blackbox-tests/test-cases/pkg/command-from-user-path.t index eabd8fb5cd0..9bab2a4a9ce 100644 --- a/test/blackbox-tests/test-cases/pkg/command-from-user-path.t +++ b/test/blackbox-tests/test-cases/pkg/command-from-user-path.t @@ -12,10 +12,7 @@ Create a directory containing a shell script and add the directory to PATH. $ PATH=$PATH:$PWD/bin Create a lockdir with a lockfile that runs the shell script in a build command. - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir $ cat >dune.lock/test.pkg <<'EOF' > (build (system hello)) > EOF diff --git a/test/blackbox-tests/test-cases/pkg/default-exported-env.t b/test/blackbox-tests/test-cases/pkg/default-exported-env.t index 3ed3d9c4b81..65d7d3473a4 100644 --- a/test/blackbox-tests/test-cases/pkg/default-exported-env.t +++ b/test/blackbox-tests/test-cases/pkg/default-exported-env.t @@ -2,13 +2,8 @@ Some environment variables are automatically exported by packages: $ . ./helpers.sh - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF - + $ make_lockdir $ touch dune.lock/test.pkg - $ cat >dune.lock/usetest.pkg <<'EOF' > (deps test) > (build diff --git a/test/blackbox-tests/test-cases/pkg/exported-env.t b/test/blackbox-tests/test-cases/pkg/exported-env.t index dd6e24d8bb8..2de2bfb37bd 100644 --- a/test/blackbox-tests/test-cases/pkg/exported-env.t +++ b/test/blackbox-tests/test-cases/pkg/exported-env.t @@ -2,10 +2,7 @@ Packages can export environment variables $ . ./helpers.sh - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir $ cat >dune.lock/test.pkg < (exported_env > (= FOO bar) diff --git a/test/blackbox-tests/test-cases/pkg/external-source.t b/test/blackbox-tests/test-cases/pkg/external-source.t index 4b24188b130..b5b5b74ec37 100644 --- a/test/blackbox-tests/test-cases/pkg/external-source.t +++ b/test/blackbox-tests/test-cases/pkg/external-source.t @@ -5,10 +5,7 @@ Test that can fetch the sources from an external dir $ mkdir foo $ echo "y" > foo/x - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir $ cat >dune.lock/test.pkg < (source (copy $PWD/foo)) > (build diff --git a/test/blackbox-tests/test-cases/pkg/extra-sources.t b/test/blackbox-tests/test-cases/pkg/extra-sources.t index 212254fd84d..32befa16a0e 100644 --- a/test/blackbox-tests/test-cases/pkg/extra-sources.t +++ b/test/blackbox-tests/test-cases/pkg/extra-sources.t @@ -2,11 +2,7 @@ Fetch from more than one source $ . ./helpers.sh - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF - + $ make_lockdir $ mkdir foo $ cat >foo/bar < this is bar diff --git a/test/blackbox-tests/test-cases/pkg/gh8325.t b/test/blackbox-tests/test-cases/pkg/gh8325.t index e92da4587cd..9745b566e11 100644 --- a/test/blackbox-tests/test-cases/pkg/gh8325.t +++ b/test/blackbox-tests/test-cases/pkg/gh8325.t @@ -2,10 +2,7 @@ Things should be the same whether dependencies are specified or not. $ . ./helpers.sh - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir If we have a package we depend on diff --git a/test/blackbox-tests/test-cases/pkg/git-source.t b/test/blackbox-tests/test-cases/pkg/git-source.t index be36fa18d2f..c8ff0040dc2 100644 --- a/test/blackbox-tests/test-cases/pkg/git-source.t +++ b/test/blackbox-tests/test-cases/pkg/git-source.t @@ -13,10 +13,7 @@ Test fetching from git $ MYGITREPO=$PWD/somerepo $ mkdir foo && cd foo - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir $ cat >dune.lock/test.pkg < (source (fetch (url "git+file://$MYGITREPO"))) > (build (run cat foo)) diff --git a/test/blackbox-tests/test-cases/pkg/helpers.sh b/test/blackbox-tests/test-cases/pkg/helpers.sh index 7674587ac0c..f694f79212d 100644 --- a/test/blackbox-tests/test-cases/pkg/helpers.sh +++ b/test/blackbox-tests/test-cases/pkg/helpers.sh @@ -47,8 +47,9 @@ solve_project() { } make_lockdir() { -mkdir dune.lock -cat >dune.lock/lock.dune <dune.lock/lock.dune <dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir $ cat >dune.lock/test.pkg <<'EOF' > (install (system "find %{prefix} | sort")) > EOF diff --git a/test/blackbox-tests/test-cases/pkg/install-action.t b/test/blackbox-tests/test-cases/pkg/install-action.t index a9702a0aedf..59822f07e5c 100644 --- a/test/blackbox-tests/test-cases/pkg/install-action.t +++ b/test/blackbox-tests/test-cases/pkg/install-action.t @@ -2,10 +2,7 @@ Testing install actions $ . ./helpers.sh - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir $ cat >dune.lock/test.pkg <<'EOF' > (install (system "echo foobar; mkdir -p %{lib}; touch %{lib}/xxx")) > EOF diff --git a/test/blackbox-tests/test-cases/pkg/install-missing-entry.t b/test/blackbox-tests/test-cases/pkg/install-missing-entry.t index 1f90c347b79..65b29431e33 100644 --- a/test/blackbox-tests/test-cases/pkg/install-missing-entry.t +++ b/test/blackbox-tests/test-cases/pkg/install-missing-entry.t @@ -2,10 +2,7 @@ Test missing entries in the .install file $ . ./helpers.sh - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir $ lockfile() { > cat >dune.lock/test.pkg < (build diff --git a/test/blackbox-tests/test-cases/pkg/installed-binary.t b/test/blackbox-tests/test-cases/pkg/installed-binary.t index 5384371a021..75bdecfa83e 100644 --- a/test/blackbox-tests/test-cases/pkg/installed-binary.t +++ b/test/blackbox-tests/test-cases/pkg/installed-binary.t @@ -2,10 +2,7 @@ Test that installed binaries are visible in dependent packages $ . ./helpers.sh - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir $ cat >dune.lock/test.pkg < (build > (system "\| echo "#!/bin/sh\necho from test package" > foo; diff --git a/test/blackbox-tests/test-cases/pkg/just-print-solver-env.t b/test/blackbox-tests/test-cases/pkg/just-print-solver-env.t index 2f1e1a591a7..22d40c49f40 100644 --- a/test/blackbox-tests/test-cases/pkg/just-print-solver-env.t +++ b/test/blackbox-tests/test-cases/pkg/just-print-solver-env.t @@ -12,6 +12,8 @@ Print the solver env when no dune-workspace is present - os-family (unset) - Constants - opam-version = 2.2.0~alpha-vendored + - Repositories + :standard Add some build contexts with different environments $ cat >dune-workspace < /dev/null -Now try it with an existing cached dir +Now try it with an existing cached dir, which given it is not reproducible should not be included $ rm -r dune.lock $ dune pkg lock --opam-repository-path=$(pwd)/fake-xdg-cache-with-git/dune/opam-repository @@ -125,4 +126,28 @@ Now try it with an existing cached dir foo.0.0.1 + $ grep "git_hash $REPO_HASH" dune.lock/lock.dune > /dev/null || echo "not found" + not found + + +The repository can also be injected via the dune-workspace file + + $ cat > dune-workspace < (lang dune 3.10) + > (repository + > (name foo) + > (source "git+file://$(pwd)/mock-opam-repository")) + > (context + > (default + > (name default) + > (solver_env + > (repositories foo)))) + > EOF + $ mkdir dune-workspace-cache + $ XDG_CACHE_HOME=$(pwd)/dune-workspace-cache dune pkg lock + Solution for dune.lock: + bar.0.0.1 + foo.0.0.1 + + $ grep "git_hash $REPO_HASH" dune.lock/lock.dune > /dev/null diff --git a/test/blackbox-tests/test-cases/pkg/package-files.t b/test/blackbox-tests/test-cases/pkg/package-files.t index 7c2afdc03da..500f275d43f 100644 --- a/test/blackbox-tests/test-cases/pkg/package-files.t +++ b/test/blackbox-tests/test-cases/pkg/package-files.t @@ -6,10 +6,7 @@ Additional files overlaid on top of the source can be found in the $ mkdir test-source $ touch test-source/foo - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir $ cat >dune.lock/test.pkg < (source > (copy $PWD/test-source)) diff --git a/test/blackbox-tests/test-cases/pkg/package-resolution-cycle.t b/test/blackbox-tests/test-cases/pkg/package-resolution-cycle.t index 759499c57d2..e6582d7b0f5 100644 --- a/test/blackbox-tests/test-cases/pkg/package-resolution-cycle.t +++ b/test/blackbox-tests/test-cases/pkg/package-resolution-cycle.t @@ -6,10 +6,7 @@ Dune should gracefully error when packages introduce circular dependenices > (lang dune 3.11) > EOF - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir $ cat >dune.lock/a.pkg < (deps c) > EOF diff --git a/test/blackbox-tests/test-cases/pkg/patch.t b/test/blackbox-tests/test-cases/pkg/patch.t index 3cb62ac5f3a..ae1485f6bc6 100644 --- a/test/blackbox-tests/test-cases/pkg/patch.t +++ b/test/blackbox-tests/test-cases/pkg/patch.t @@ -3,10 +3,7 @@ Applying patches $ . ./helpers.sh $ mkdir test-source - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir $ cat >dune.lock/test.pkg < (source (copy $PWD/test-source)) > (build diff --git a/test/blackbox-tests/test-cases/pkg/per-context.t b/test/blackbox-tests/test-cases/pkg/per-context.t index 133068a368a..588464ca330 100644 --- a/test/blackbox-tests/test-cases/pkg/per-context.t +++ b/test/blackbox-tests/test-cases/pkg/per-context.t @@ -18,6 +18,7 @@ TODO: versioning will be added once this feature is stable $ mkdir foo.lock $ cat >foo.lock/lock.dune < (lang package 0.1) + > (repositories (complete true)) > EOF $ cat >foo.lock/test.pkg < (build diff --git a/test/blackbox-tests/test-cases/pkg/pkg-action-when.t b/test/blackbox-tests/test-cases/pkg/pkg-action-when.t index 5d8a3f12f9a..dc6723d9127 100644 --- a/test/blackbox-tests/test-cases/pkg/pkg-action-when.t +++ b/test/blackbox-tests/test-cases/pkg/pkg-action-when.t @@ -2,10 +2,7 @@ Testing the when action in lockfiles $ . ./helpers.sh - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir Case with a mix of uncoditional and conditional actions in a progn action $ cat >dune.lock/test.pkg <<'EOF' diff --git a/test/blackbox-tests/test-cases/pkg/simple-lock.t b/test/blackbox-tests/test-cases/pkg/simple-lock.t index 7b6ee0c3e13..bce196d1960 100644 --- a/test/blackbox-tests/test-cases/pkg/simple-lock.t +++ b/test/blackbox-tests/test-cases/pkg/simple-lock.t @@ -2,10 +2,7 @@ Test that we run the build command $ . ./helpers.sh - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir $ cat >dune.lock/test.pkg < (build > (progn diff --git a/test/blackbox-tests/test-cases/pkg/substitute.t b/test/blackbox-tests/test-cases/pkg/substitute.t index 97f7327126e..8136dbf6563 100644 --- a/test/blackbox-tests/test-cases/pkg/substitute.t +++ b/test/blackbox-tests/test-cases/pkg/substitute.t @@ -6,10 +6,7 @@ The test-source folder has a file to use substitution on. $ cat >test-source/foo.ml.in < This file will be fed to the substitution mechanism > EOF - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir $ cat >dune.lock/test.pkg < (source (copy $PWD/test-source)) > (build diff --git a/test/blackbox-tests/test-cases/pkg/unknown-package.t b/test/blackbox-tests/test-cases/pkg/unknown-package.t index 7b9aff1c4e3..7c63fdc77e7 100644 --- a/test/blackbox-tests/test-cases/pkg/unknown-package.t +++ b/test/blackbox-tests/test-cases/pkg/unknown-package.t @@ -2,10 +2,7 @@ Try to build a package that doesn't exist $ . ./helpers.sh - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir $ build_pkg fakepkg Error: Unknown package "fakepkg" [1] diff --git a/test/blackbox-tests/test-cases/pkg/variables.t b/test/blackbox-tests/test-cases/pkg/variables.t index 2516be7b698..9df4b8b4667 100644 --- a/test/blackbox-tests/test-cases/pkg/variables.t +++ b/test/blackbox-tests/test-cases/pkg/variables.t @@ -2,10 +2,7 @@ Test that we can set variables $ . ./helpers.sh - $ mkdir dune.lock - $ cat >dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir $ cat >dune.lock/test.pkg < (build > (system "\| cat >test.config <dune.lock/lock.dune < (lang package 0.1) - > EOF + $ make_lockdir $ cat >dune.lock/test.pkg <<'EOF' > (build > (withenv diff --git a/test/expect-tests/dune_pkg/dune_pkg_unit_tests.ml b/test/expect-tests/dune_pkg/dune_pkg_unit_tests.ml index 0b894822161..4a5134a8768 100644 --- a/test/expect-tests/dune_pkg/dune_pkg_unit_tests.ml +++ b/test/expect-tests/dune_pkg/dune_pkg_unit_tests.ml @@ -185,11 +185,15 @@ 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 ~ocaml:None ~repo_id:None); + (Lock_dir.create_latest_version Package_name.Map.empty ~ocaml:None ~repos:None); [%expect {| lockdir matches after roundtrip: - { version = (0, 1); packages = map {}; ocaml = None; repo_id = None } |}] + { version = (0, 1) + ; packages = map {} + ; ocaml = None + ; repos = { complete = true; used = None } + } |}] ;; let%expect_test "encode/decode round trip test for lockdir with simple deps" = @@ -214,7 +218,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")) - ~repo_id:None + ~repos:None (Package_name.Map.of_list_exn [ mk_pkg_basic ~name:"foo" ~version:"0.1.0" ; mk_pkg_basic ~name:"bar" ~version:"0.2.0" @@ -253,7 +257,7 @@ let%expect_test "encode/decode round trip test for lockdir with simple deps" = } } ; ocaml = Some ("simple_lock_dir/lock.dune:3", "ocaml") - ; repo_id = None + ; repos = { complete = true; used = None } } |}] ;; @@ -343,9 +347,13 @@ let%expect_test "encode/decode round trip test for lockdir with complex deps" = ; exported_env = [] } ) in + let repo_id = Dune_pkg.Repository_id.Private.git_hash "95cf548dc" in + let opam_repo = + Dune_pkg.Opam_repo.Private.create ~source:"well-known-repo" ~repo_id () + in Lock_dir.create_latest_version ~ocaml:(Some (Loc.none, Package_name.of_string "ocaml")) - ~repo_id:(Some (Loc.none, Dune_pkg.Repository_id.Private.git_hash "95cf548dc")) + ~repos:(Some [ opam_repo ]) (Package_name.Map.of_list_exn [ pkg_a; pkg_b; pkg_c ])); [%expect {| @@ -404,6 +412,13 @@ let%expect_test "encode/decode round trip test for lockdir with complex deps" = } } ; ocaml = Some ("complex_lock_dir/lock.dune:3", "ocaml") - ; repo_id = Some ("complex_lock_dir/lock.dune:6", Git_hash "95cf548dc") + ; repos = + { complete = true + ; used = + Some + [ opam_repo_serializable + Some Git_hash "95cf548dc","well-known-repo" + ] + } } |}] ;;