From b4099636c73c28ad002559efab1d7c84285acb2d Mon Sep 17 00:00:00 2001 From: Marek Kubica Date: Sun, 3 Nov 2024 19:06:15 +0100 Subject: [PATCH] pkg: Use `filtered_formula` to represent dependencies (#10918) * pkg: Pass-through `filtered_formula` from opam files to solver The `Dependency_set.t` representation can't deal with disjunctions but in most cases that is not even necessary as the set gets turned into a `filtered_formula` again. Thus it might be easier to keep the original representation and implement the necessary dependency set functionality on top of that. Signed-off-by: Marek Kubica * Remove unused `Dependency_set` Signed-off-by: Marek Kubica * Add a test showing that the disjunction in OPAM files is supported now Signed-off-by: Marek Kubica * Move `filtered_formula` into our own module Signed-off-by: Marek Kubica * Determine the hash from the Sexp Signed-off-by: Marek Kubica * Move reachability into the formula Signed-off-by: Marek Kubica * Add test for dependency formula changes Signed-off-by: Marek Kubica * Clean up the awkward API Signed-off-by: Marek Kubica * Promote expected hash changes Signed-off-by: Marek Kubica * Update the test wording and show the difference Signed-off-by: Marek Kubica * test(pkg): demonstrate unreachable packages being included Signed-off-by: Rudi Grinberg Signed-off-by: Marek Kubica * Do not include post dependencies in reachable packages Signed-off-by: Marek Kubica * Replace sexp by dyn Signed-off-by: Marek Kubica * Promote expected hash changes Signed-off-by: Marek Kubica * `post` deps are excluded now Signed-off-by: Marek Kubica * Simplify Signed-off-by: Marek Kubica * Use `Resolve_opam_formula` to determine dependencies Signed-off-by: Marek Kubica --- bin/describe/describe_pkg.ml | 9 ++- bin/lock_dev_tool.ml | 3 +- src/dune_pkg/dependency_formula.ml | 37 +++++++++ src/dune_pkg/dependency_formula.mli | 27 +++++++ src/dune_pkg/dune_pkg.ml | 1 + src/dune_pkg/local_package.ml | 78 +++++-------------- src/dune_pkg/local_package.mli | 33 +------- src/dune_pkg/lock_dir.ml | 5 +- src/dune_pkg/opam_solver.ml | 41 +++++++++- src/dune_pkg/package_universe.ml | 30 ++++--- src/dune_pkg_outdated/dune_pkg_outdated.ml | 4 +- .../test-cases/pkg/check-dependency-hash.t | 8 +- .../test-cases/pkg/common-filters-deps.t | 4 +- .../test-cases/pkg/dependency-hash.t | 74 +++++++++++++++--- .../test-cases/pkg/hash-algos.t | 2 +- .../pkg/lockfile-generation.t/run.t | 4 +- .../test-cases/pkg/opam-file-errors.t | 38 --------- .../blackbox-tests/test-cases/pkg/opam-file.t | 54 +++++++++++++ .../pkg/solver-vars-in-lockdir-metadata.t | 8 +- 19 files changed, 291 insertions(+), 169 deletions(-) create mode 100644 src/dune_pkg/dependency_formula.ml create mode 100644 src/dune_pkg/dependency_formula.mli create mode 100644 test/blackbox-tests/test-cases/pkg/opam-file.t diff --git a/bin/describe/describe_pkg.ml b/bin/describe/describe_pkg.ml index e777f26fee9..dcbbe48cac3 100644 --- a/bin/describe/describe_pkg.ml +++ b/bin/describe/describe_pkg.ml @@ -46,10 +46,11 @@ module Dependency_hash = struct >>| Package_name.Map.values >>| List.map ~f:Local_package.for_solver in - match - Local_package.( - For_solver.list_non_local_dependency_set local_packages |> Dependency_set.hash) - with + let hash = + Local_package.For_solver.non_local_dependencies local_packages + |> Local_package.Dependency_hash.of_dependency_formula + in + match hash with | None -> User_error.raise [ Pp.text "No non-local dependencies" ] | Some dependency_hash -> print_endline (Local_package.Dependency_hash.to_string dependency_hash) diff --git a/bin/lock_dev_tool.ml b/bin/lock_dev_tool.ml index 55bd8cb4eef..aca0d06436c 100644 --- a/bin/lock_dev_tool.ml +++ b/bin/lock_dev_tool.ml @@ -54,7 +54,8 @@ let make_local_package_wrapping_dev_tool ~dev_tool ~dev_tool_version ~extra_depe in { Dune_pkg.Local_package.name = local_package_name ; version = None - ; dependencies = dependency :: extra_dependencies + ; dependencies = + Dune_pkg.Dependency_formula.of_dependencies (dependency :: extra_dependencies) ; conflicts = [] ; depopts = [] ; pins = Package_name.Map.empty diff --git a/src/dune_pkg/dependency_formula.ml b/src/dune_pkg/dependency_formula.ml new file mode 100644 index 00000000000..055e1153b00 --- /dev/null +++ b/src/dune_pkg/dependency_formula.ml @@ -0,0 +1,37 @@ +open Import + +type t = OpamTypes.filtered_formula + +let of_dependencies deps = Package_dependency.list_to_opam_filtered_formula deps +let to_filtered_formula v = v +let of_filtered_formula v = v +let to_dyn = Opam_dyn.filtered_formula +let ands = OpamFormula.ands + +let remove_packages (v : OpamTypes.filtered_formula) pkgs = + OpamFormula.map_up_formula + (function + | Atom (name, _condition) as a -> + if let name = Package_name.of_opam_package_name name in + Package_name.Set.mem pkgs name + then Empty + else a + | x -> x) + v +;; + +exception Found of Package_name.t + +let any_package_name (v : OpamTypes.filtered_formula) = + try + OpamFormula.iter + (fun (name, _condition) -> + let name = Package_name.of_opam_package_name name in + raise_notrace (Found name)) + v; + None + with + | Found name -> Some name +;; + +let has_entries v = v |> any_package_name |> Option.is_some diff --git a/src/dune_pkg/dependency_formula.mli b/src/dune_pkg/dependency_formula.mli new file mode 100644 index 00000000000..1367d6f33c8 --- /dev/null +++ b/src/dune_pkg/dependency_formula.mli @@ -0,0 +1,27 @@ +type t + +(** Create a dependency formula out of a [Package_dependency.t] list where + all packages are dependencies *) +val of_dependencies : Package_dependency.t list -> t + +(** Convert to the OPAM data type *) +val to_filtered_formula : t -> OpamTypes.filtered_formula + +(** Convert from the OPAM data type to this *) +val of_filtered_formula : OpamTypes.filtered_formula -> t + +(** Create a Dyn representation of the dependency formula *) +val to_dyn : t -> Dyn.t + +(* Join all dependencies in the list to a single conjunction *) +val ands : t list -> t + +(** Remove a package from the entire formula *) +val remove_packages : t -> Package_name.Set.t -> t + +(** Determine whether the dependency formula has any dependencies *) +val has_entries : t -> bool + +(** Returns the [Package_name.t] of a dependency from the formula, if it + exists. *) +val any_package_name : t -> Package_name.t option diff --git a/src/dune_pkg/dune_pkg.ml b/src/dune_pkg/dune_pkg.ml index 88c7bf78b13..8529bf87e2a 100644 --- a/src/dune_pkg/dune_pkg.ml +++ b/src/dune_pkg/dune_pkg.ml @@ -8,6 +8,7 @@ module Opam_solver = Opam_solver module OpamUrl = OpamUrl0 module Package_variable = Package_variable module Package_dependency = Package_dependency +module Dependency_formula = Dependency_formula module Rev_store = Rev_store module Solver_env = Solver_env module Solver_stats = Solver_stats diff --git a/src/dune_pkg/local_package.ml b/src/dune_pkg/local_package.ml index 9a9470ccd53..6bfc71cd798 100644 --- a/src/dune_pkg/local_package.ml +++ b/src/dune_pkg/local_package.ml @@ -15,7 +15,7 @@ type pins = pin Package_name.Map.t type t = { name : Package_name.t ; version : Package_version.t option - ; dependencies : Package_dependency.t list + ; dependencies : Dependency_formula.t ; conflicts : Package_dependency.t list ; conflict_class : Package_name.t list ; depopts : Package_dependency.t list @@ -38,55 +38,20 @@ module Dependency_hash = struct ~loc [ Pp.textf "Dependency hash is not a valid md5 hash: %s" hash ] ;; -end - -module Dependency_set = struct - type t = Package_constraint.Set.t Package_name.Map.t - - let empty = Package_name.Map.empty - - let of_list = - List.fold_left ~init:empty ~f:(fun acc { Package_dependency.name; constraint_ } -> - Package_name.Map.update acc name ~f:(fun existing -> - match existing, constraint_ with - | None, None -> Some Package_constraint.Set.empty - | None, Some constraint_ -> Some (Package_constraint.Set.singleton constraint_) - | Some existing, None -> Some existing - | Some existing, Some constraint_ -> - Some (Package_constraint.Set.add existing constraint_))) - ;; - let union = - Package_name.Map.union ~f:(fun _name a b -> Some (Package_constraint.Set.union a b)) - ;; - - let union_all = List.fold_left ~init:empty ~f:union - - let package_dependencies = - Package_name.Map.to_list_map ~f:(fun name constraints -> - let constraint_ = - if Package_constraint.Set.is_empty constraints - then None - else Some (Package_constraint.And (Package_constraint.Set.to_list constraints)) - in - { Package_dependency.name; constraint_ }) - ;; - - let encode_for_hash t = - package_dependencies t |> Dune_lang.Encoder.list Package_dependency.encode - ;; - - let hash t = - if Package_name.Map.is_empty t - then None - else Some (encode_for_hash t |> Dune_sexp.to_string |> Dune_digest.string) + let of_dependency_formula formula = + match Dependency_formula.has_entries formula with + | false -> None + | true -> + let hashable = formula |> Dependency_formula.to_dyn |> Dyn.to_string in + Some (string hashable) ;; end module For_solver = struct type t = { name : Package_name.t - ; dependencies : Package_dependency.t list + ; dependencies : Dependency_formula.t ; conflicts : Package_dependency.t list ; depopts : Package_dependency.t list ; conflict_class : Package_name.t list @@ -98,8 +63,7 @@ module For_solver = struct them *) OpamFile.OPAM.empty |> OpamFile.OPAM.with_name (Package_name.to_opam_package_name name) - |> OpamFile.OPAM.with_depends - (Package_dependency.list_to_opam_filtered_formula dependencies) + |> OpamFile.OPAM.with_depends (Dependency_formula.to_filtered_formula dependencies) |> OpamFile.OPAM.with_conflicts (Package_dependency.list_to_opam_filtered_formula conflicts) |> OpamFile.OPAM.with_conflict_class @@ -108,16 +72,13 @@ module For_solver = struct (Package_dependency.list_to_opam_filtered_formula depopts) ;; - let opam_filtered_dependency_formula { dependencies; _ } = - Package_dependency.list_to_opam_filtered_formula dependencies - ;; - - let dependency_set { dependencies; _ } = Dependency_set.of_list dependencies - let list_dependency_set ts = List.map ts ~f:dependency_set |> Dependency_set.union_all - - let list_non_local_dependency_set ts = - List.fold_left ts ~init:(list_dependency_set ts) ~f:(fun acc { name; _ } -> - Package_name.Map.remove acc name) + let non_local_dependencies local_deps = + let local_deps_names = Package_name.Set.of_list_map ~f:(fun d -> d.name) local_deps in + let formula = + List.map ~f:(fun { dependencies; _ } -> dependencies) local_deps + |> Dependency_formula.ands + in + Dependency_formula.remove_packages formula local_deps_names ;; end @@ -134,9 +95,10 @@ let of_package (t : Dune_lang.Package.t) = let name = Package.name t in match Package.original_opam_file t with | None -> + let dependencies = t |> Package.depends |> Dependency_formula.of_dependencies in { name ; version - ; dependencies = Package.depends t + ; dependencies ; conflicts = Package.conflicts t ; depopts = Package.depopts t ; loc @@ -148,7 +110,9 @@ let of_package (t : Dune_lang.Package.t) = Opam_file.read_from_string_exn ~contents:opam_file_string (Path.source file) in let convert_filtered_formula = Package_dependency.list_of_opam_filtered_formula loc in - let dependencies = convert_filtered_formula `And (OpamFile.OPAM.depends opam_file) in + let dependencies = + opam_file |> OpamFile.OPAM.depends |> Dependency_formula.of_filtered_formula + in let conflicts = convert_filtered_formula `And (OpamFile.OPAM.conflicts opam_file) in let depopts = convert_filtered_formula `Or (OpamFile.OPAM.depopts opam_file) in let conflict_class = diff --git a/src/dune_pkg/local_package.mli b/src/dune_pkg/local_package.mli index 64e3d002d98..55db3b6a15a 100644 --- a/src/dune_pkg/local_package.mli +++ b/src/dune_pkg/local_package.mli @@ -20,7 +20,7 @@ type pins = pin Package_name.Map.t type t = { name : Package_name.t ; version : Package_version.t option - ; dependencies : Package_dependency.t list + ; dependencies : Dependency_formula.t ; conflicts : Package_dependency.t list ; conflict_class : Package_name.t list ; depopts : Package_dependency.t list @@ -36,32 +36,14 @@ module Dependency_hash : sig val to_string : t -> string val encode : t Encoder.t val decode : t Decoder.t -end - -module Dependency_set : sig - (** A set of dependencies belonging to one or more local packages. Two - different local packages may depend on the same packages with different - version constraints provided that the two constraints intersect - (otherwise there will be no solution). In this case the conjunction of - both constraints will form the constraint associated with that - dependency. Package constraints are de-duplicated by comparing them only - on their syntax. *) - type t - - (** Returns a hash of all dependencies in the set or [None] if the set is - empty. The reason for behaving differently when the set is empty is so - that callers are forced to explicitly handle the case where there are no - dependencies which will likely lead to better user experience. *) - val hash : t -> Dependency_hash.t option - - val package_dependencies : t -> Package_dependency.t list + val of_dependency_formula : Dependency_formula.t -> t option end module For_solver : sig (** The minimum set of fields about a package needed by the solver. *) type t = { name : Package_name.t - ; dependencies : Package_dependency.t list + ; dependencies : Dependency_formula.t ; conflicts : Package_dependency.t list ; depopts : Package_dependency.t list ; conflict_class : Package_name.t list @@ -73,14 +55,7 @@ module For_solver : sig on disk. *) val to_opam_file : t -> OpamFile.OPAM.t - (** Returns an opam dependency formula for this package *) - val opam_filtered_dependency_formula : t -> OpamTypes.filtered_formula - - (** Returns the set of dependencies of all given local packages excluding - dependencies which are packages in the provided list. Pass this the list - of all local package in a project to get a set of all non-local - dependencies of the project. *) - val list_non_local_dependency_set : t list -> Dependency_set.t + val non_local_dependencies : t list -> Dependency_formula.t end val for_solver : t -> For_solver.t diff --git a/src/dune_pkg/lock_dir.ml b/src/dune_pkg/lock_dir.ml index f9e7ef39089..e8dd267dbc3 100644 --- a/src/dune_pkg/lock_dir.ml +++ b/src/dune_pkg/lock_dir.ml @@ -380,8 +380,9 @@ let create_latest_version |> Code_error.raise "Invalid package table"); let version = Syntax.greatest_supported_version_exn Dune_lang.Pkg.syntax in let dependency_hash = - Local_package.( - For_solver.list_non_local_dependency_set local_packages |> Dependency_set.hash) + local_packages + |> Local_package.For_solver.non_local_dependencies + |> Local_package.Dependency_hash.of_dependency_formula |> Option.map ~f:(fun dependency_hash -> Loc.none, dependency_hash) in let complete, used = diff --git a/src/dune_pkg/opam_solver.ml b/src/dune_pkg/opam_solver.ml index a34808ac104..ea1c894c9bc 100644 --- a/src/dune_pkg/opam_solver.ml +++ b/src/dune_pkg/opam_solver.ml @@ -783,8 +783,21 @@ let reject_unreachable_packages = loop roots; !seen in - fun ~local_packages ~pkgs_by_name -> + fun solver_env ~local_packages ~pkgs_by_name -> let roots = Package_name.Map.keys local_packages in + let pkgs_by_version = + Package_name.Map.merge pkgs_by_name local_packages ~f:(fun name lhs rhs -> + match lhs, rhs with + | None, None -> assert false + | Some _, Some _ -> + Code_error.raise + "package is both local and returned by solver" + [ "name", Package_name.to_dyn name ] + | Some (lock_dir_pkg : Lock_dir.Pkg.t), None -> Some lock_dir_pkg.info.version + | None, Some _pkg -> + let version = Package_version.of_string "dev" in + Some version) + in let pkgs_by_name = Package_name.Map.merge pkgs_by_name local_packages ~f:(fun name lhs rhs -> match lhs, rhs with @@ -795,8 +808,28 @@ let reject_unreachable_packages = [ "name", Package_name.to_dyn name ] | Some (pkg : Lock_dir.Pkg.t), None -> Some (List.map pkg.depends ~f:snd) | None, Some (pkg : Local_package.For_solver.t) -> + let formula = pkg.dependencies |> Dependency_formula.to_filtered_formula in + (* Use `dev` because at this point we don't have any version *) + let opam_package = + OpamPackage.of_string (sprintf "%s.dev" (Package_name.to_string pkg.name)) + in + let env = add_self_to_filter_env opam_package (Solver_env.to_env solver_env) in + let resolved = + Resolve_opam_formula.filtered_formula_to_package_names + env + ~with_test:true + pkgs_by_version + formula + in let deps = - List.map pkg.dependencies ~f:(fun (d : Package_dependency.t) -> d.name) + match resolved with + | Ok { regular; post = _ } -> + (* discard post deps *) + regular + | Error _ -> + Code_error.raise + "can't find a valid solution for the dependencies" + [ "name", Package_name.to_dyn pkg.name ] in let depopts = List.filter_map pkg.depopts ~f:(fun (d : Package_dependency.t) -> @@ -912,7 +945,9 @@ let solve_lock_dir (Package_name.to_string name) (Package_name.to_string dep_name) ])); - let reachable = reject_unreachable_packages ~local_packages ~pkgs_by_name in + let reachable = + reject_unreachable_packages solver_env ~local_packages ~pkgs_by_name + in let pkgs_by_name = Package_name.Map.filteri pkgs_by_name ~f:(fun name _ -> Package_name.Set.mem reachable name) diff --git a/src/dune_pkg/package_universe.ml b/src/dune_pkg/package_universe.ml index a72d1a2e99d..a93e4483c57 100644 --- a/src/dune_pkg/package_universe.ml +++ b/src/dune_pkg/package_universe.ml @@ -49,7 +49,9 @@ let concrete_dependencies_of_local_package t local_package_name ~with_test = let local_package = Package_name.Map.find_exn t.local_packages local_package_name in match Local_package.( - for_solver local_package |> For_solver.opam_filtered_dependency_formula) + for_solver local_package + |> (fun x -> x.dependencies) + |> Dependency_formula.to_filtered_formula) |> Resolve_opam_formula.filtered_formula_to_package_names ~with_test (Solver_env.to_env t.solver_env) @@ -131,10 +133,10 @@ let up_to_date local_packages ~dependency_hash:saved_dependency_hash = let local_packages = Package_name.Map.values local_packages |> List.map ~f:Local_package.for_solver in - let non_local_dependencies = - Local_package.For_solver.list_non_local_dependency_set local_packages + let dependency_hash = + Local_package.For_solver.non_local_dependencies local_packages + |> Local_package.Dependency_hash.of_dependency_formula in - let dependency_hash = Local_package.Dependency_set.hash non_local_dependencies in match saved_dependency_hash, dependency_hash with | None, None -> `Valid | Some lock_dir_dependency_hash, Some non_local_dependencies_hash @@ -159,10 +161,10 @@ let validate_dependency_hash local_packages ~saved_dependency_hash = ] ] in - let non_local_dependencies = - Local_package.For_solver.list_non_local_dependency_set local_packages + let dependency_hash = + Local_package.For_solver.non_local_dependencies local_packages + |> Local_package.Dependency_hash.of_dependency_formula in - let dependency_hash = Local_package.Dependency_set.hash non_local_dependencies in match saved_dependency_hash, dependency_hash with | None, None -> () | Some (loc, lock_dir_dependency_hash), None -> @@ -175,8 +177,16 @@ let validate_dependency_hash local_packages ~saved_dependency_hash = (Local_package.Dependency_hash.to_string lock_dir_dependency_hash) ] | None, Some _ -> - let any_non_local_dependency : Package_dependency.t = - List.hd (Local_package.Dependency_set.package_dependencies non_local_dependencies) + let any_non_local_dependency_name = + let non_local_dependencies = + Local_package.For_solver.non_local_dependencies local_packages + in + match Dependency_formula.any_package_name non_local_dependencies with + | Some x -> x + | None -> + Code_error.raise + "Attempting to retrieve a non-local dependency but there aren't any" + [] in User_error.raise ~hints:regenerate_lock_dir_hints @@ -185,7 +195,7 @@ let validate_dependency_hash local_packages ~saved_dependency_hash = contain a dependency hash." ; Pp.textf "An example of a non-local dependency of this project is: %s" - (Package_name.to_string any_non_local_dependency.name) + (Package_name.to_string any_non_local_dependency_name) ] | Some (loc, lock_dir_dependency_hash), Some non_local_dependency_hash -> if Local_package.Dependency_hash.equal diff --git a/src/dune_pkg_outdated/dune_pkg_outdated.ml b/src/dune_pkg_outdated/dune_pkg_outdated.ml index 3947deeb11e..ec8d4f22354 100644 --- a/src/dune_pkg_outdated/dune_pkg_outdated.ml +++ b/src/dune_pkg_outdated/dune_pkg_outdated.ml @@ -91,7 +91,9 @@ let better_candidate let is_immediate_dep_of_local_package = Package_name.Map.exists local_packages ~f:(fun local_package -> Dune_pkg.Local_package.( - for_solver local_package |> For_solver.opam_filtered_dependency_formula) + for_solver local_package + |> (fun x -> x.dependencies) + |> Dune_pkg.Dependency_formula.to_filtered_formula) |> OpamFilter.filter_deps ~build:true ~post:false diff --git a/test/blackbox-tests/test-cases/pkg/check-dependency-hash.t b/test/blackbox-tests/test-cases/pkg/check-dependency-hash.t index e81da810942..e2dceb14d0a 100644 --- a/test/blackbox-tests/test-cases/pkg/check-dependency-hash.t +++ b/test/blackbox-tests/test-cases/pkg/check-dependency-hash.t @@ -52,7 +52,7 @@ Add a non-local dependency to the package: $ cat dune.lock/lock.dune (lang package 0.1) - (dependency_hash 69dfdf4e6a7c8489262f9d8b9958c9b3) + (dependency_hash 7ba1cacd46bb2609d7b9735909c3b8a5) (repositories (complete false) @@ -72,9 +72,9 @@ Add a second dependency to the project: Error: Dependency hash in lockdir does not match the hash of non-local dependencies of this project. The lockdir expects the the non-local dependencies to hash to: - 69dfdf4e6a7c8489262f9d8b9958c9b3 + 7ba1cacd46bb2609d7b9735909c3b8a5 ...but the non-local dependencies of this project hash to: - 0cd7f9253f917ae8182c904fac99c3d9 + d18946fdd9833ae312d309f654f11c1b Hint: Regenerate the lockdir by running 'dune pkg lock' Error: Some lockdirs do not contain solutions for local packages: - dune.lock @@ -90,7 +90,7 @@ Remove all dependencies from the project: Lockdir dune.lock does not contain a solution for local packages: File "dune.lock/lock.dune", line 3, characters 17-49: Error: This project has no non-local dependencies yet the lockfile contains a - dependency hash: 69dfdf4e6a7c8489262f9d8b9958c9b3 + dependency hash: 7ba1cacd46bb2609d7b9735909c3b8a5 Hint: Regenerate the lockdir by running 'dune pkg lock' Error: Some lockdirs do not contain solutions for local packages: - dune.lock diff --git a/test/blackbox-tests/test-cases/pkg/common-filters-deps.t b/test/blackbox-tests/test-cases/pkg/common-filters-deps.t index 2ab9586210e..0fc9258835d 100644 --- a/test/blackbox-tests/test-cases/pkg/common-filters-deps.t +++ b/test/blackbox-tests/test-cases/pkg/common-filters-deps.t @@ -19,8 +19,10 @@ included. Note that dune solves packages with with-doc and with-dev-setup always set to false, so documentation-only deps are omitted from the solution. + +Dune will also not include dependencies marked `post` in the lock directory. + $ solve "(test :with-test) (doc :with-doc) (dev-setup :with-dev-setup) (dev :with-dev) (build :build) (post :post)" Solution for dune.lock: - build.0.0.1 - - post.0.0.1 - test.0.0.1 diff --git a/test/blackbox-tests/test-cases/pkg/dependency-hash.t b/test/blackbox-tests/test-cases/pkg/dependency-hash.t index 3c9165de06b..1d23c89b33b 100644 --- a/test/blackbox-tests/test-cases/pkg/dependency-hash.t +++ b/test/blackbox-tests/test-cases/pkg/dependency-hash.t @@ -40,7 +40,7 @@ A single package with a single non-local dependency: > foo)) > EOF $ dune describe pkg dependency-hash | tee hash1.txt - 9f76a6d656fe14d54ba74f864e736dc3 + 36e640fbcda71963e7e2f689f6c96c3e Adding another dependency causes the hash to change: $ cat >dune-project < bar)) > EOF $ dune describe pkg dependency-hash | tee hash2.txt - 142f33129a06ccbebd65a0bad3d94857 + b6404e14c268884f825aa1fb7d1b4ead $ diff hash1.txt hash2.txt 1c1 - < 9f76a6d656fe14d54ba74f864e736dc3 + < 36e640fbcda71963e7e2f689f6c96c3e --- - > 142f33129a06ccbebd65a0bad3d94857 + > b6404e14c268884f825aa1fb7d1b4ead [1] Adding a new local package which depends on one of the existing dependencies -doesn't change the hash: +changes the hash: + $ cat >dune-project < (lang dune 3.11) > (package @@ -75,8 +76,13 @@ doesn't change the hash: > foo)) > EOF $ dune describe pkg dependency-hash | tee hash3.txt - 142f33129a06ccbebd65a0bad3d94857 + fa35416284004d71ff802a4c582f8797 $ diff hash2.txt hash3.txt + 1c1 + < b6404e14c268884f825aa1fb7d1b4ead + --- + > fa35416284004d71ff802a4c582f8797 + [1] Adding a constraint to one of the dependencies causes the hash to change: $ cat >dune-project < (foo (and :with-test (> 0.1))))) > EOF $ dune describe pkg dependency-hash | tee hash4.txt - ecad1d0d60084711169be48b130c9c52 + fdf713b190b56d52d8cdbdd72a382654 $ diff hash3.txt hash4.txt 1c1 - < 142f33129a06ccbebd65a0bad3d94857 + < fa35416284004d71ff802a4c582f8797 --- - > ecad1d0d60084711169be48b130c9c52 + > fdf713b190b56d52d8cdbdd72a382654 [1] -Adding another local package with the same dependency and constraint doesn't -change the hash: +Adding another local package with the same dependency and constraint changes +the hash: + $ cat >dune-project < (lang dune 3.11) > (package @@ -119,5 +126,48 @@ change the hash: > (foo (and :with-test (> 0.1))))) > EOF $ dune describe pkg dependency-hash | tee hash5.txt - ecad1d0d60084711169be48b130c9c52 + 38fa247158bdf36939ec8b10b3205508 $ diff hash4.txt hash5.txt + 1c1 + < fdf713b190b56d52d8cdbdd72a382654 + --- + > 38fa247158bdf36939ec8b10b3205508 + [1] + +Make sure that the hash changes when the formula changes from a conjunction to +a disjunction, thus changing the solution: + + $ cat > dune-project < (lang dune 3.11) + > EOF + $ cat > local.opam < opam-version: "2.0" + > depends: [ "a" "b" ] + > EOF + $ dune describe pkg dependency-hash | tee hash-a-b.txt + d18946fdd9833ae312d309f654f11c1b + $ cat > local.opam < opam-version: "2.0" + > depends: [ "a" | "b" ] + > EOF + $ dune describe pkg dependency-hash | tee hash-a-or-b.txt + 5b2db8d296a969fbd80033f70919b2ec + $ diff hash-a-and-b.txt hash-a-or-b.txt + diff: hash-a-and-b.txt: No such file or directory + [2] + +The formula also changes if the dependencies being picked end up being the same +("a" and "b") but the formula changed by including another dependency: + + $ cat > local.opam < opam-version: "2.0" + > depends: [ "a" & ("b" | "c") ] + > EOF + $ dune describe pkg dependency-hash | tee hash-a-b-or-c.txt + b704ac23e0d16a5e7a1b10aa6a8cbe0e + $ diff hash-a-b.txt hash-a-b-or-c.txt + 1c1 + < d18946fdd9833ae312d309f654f11c1b + --- + > b704ac23e0d16a5e7a1b10aa6a8cbe0e + [1] diff --git a/test/blackbox-tests/test-cases/pkg/hash-algos.t b/test/blackbox-tests/test-cases/pkg/hash-algos.t index 4751b6af34d..6bfd5c9e940 100644 --- a/test/blackbox-tests/test-cases/pkg/hash-algos.t +++ b/test/blackbox-tests/test-cases/pkg/hash-algos.t @@ -63,7 +63,7 @@ first checksum to the lockfile for this package. $ cat dune.lock/* (lang package 0.1) - (dependency_hash 4435ebc0724374e2f76349d7a2e7ab6e) + (dependency_hash 32180cf311133b30d0b5be2a40c89f43) (repositories (complete false) diff --git a/test/blackbox-tests/test-cases/pkg/lockfile-generation.t/run.t b/test/blackbox-tests/test-cases/pkg/lockfile-generation.t/run.t index 6739a3a580c..a5ee46da897 100644 --- a/test/blackbox-tests/test-cases/pkg/lockfile-generation.t/run.t +++ b/test/blackbox-tests/test-cases/pkg/lockfile-generation.t/run.t @@ -78,7 +78,7 @@ Print the contents of each file in the lockdir: (lang package 0.1) - (dependency_hash ca83e32ab35d71d20fa075b395046c29) + (dependency_hash 8940266fc1693f5f2a008d1d58c1e1b9) (repositories (complete false) @@ -123,7 +123,7 @@ Run the solver again preferring oldest versions of dependencies: (lang package 0.1) - (dependency_hash ca83e32ab35d71d20fa075b395046c29) + (dependency_hash 8940266fc1693f5f2a008d1d58c1e1b9) (repositories (complete false) diff --git a/test/blackbox-tests/test-cases/pkg/opam-file-errors.t b/test/blackbox-tests/test-cases/pkg/opam-file-errors.t index 052bcae8f0f..0574c0f3dec 100644 --- a/test/blackbox-tests/test-cases/pkg/opam-file-errors.t +++ b/test/blackbox-tests/test-cases/pkg/opam-file-errors.t @@ -35,41 +35,3 @@ Handle the case where opam's parser rejects the file. Error: unable to parse opam file Parse error [1] - -Make sure we print an error when encountering opam files with dependency -specifications that can't be represented by dune's package metadata format. - $ cat > x.opam < opam-version: "2.0" - > depends: [ - > "a" | "b" - > ] - > EOF - $ dune pkg lock - File "x.opam", line 1, characters 0-0: - Error: Expected formula to be a conjunction of atoms but encountered non-atom - term 'a | b' - [1] - - $ cat > x.opam < opam-version: "2.0" - > depends: [ - > "a" { "foo" } - > ] - > EOF - $ dune pkg lock - File "x.opam", line 1, characters 0-0: - Error: Can't convert opam filter '"foo"' into dune condition. Only global - variables may appear in this position. - [1] - - $ cat > x.opam < opam-version: "2.0" - > depends: [ - > "a" { < foo:bar } - > ] - > EOF - $ dune pkg lock - File "x.opam", line 1, characters 0-0: - Error: Can't convert opam filter 'foo:bar' into dune value. Only literal - values and global variables may appear in this position. - [1] diff --git a/test/blackbox-tests/test-cases/pkg/opam-file.t b/test/blackbox-tests/test-cases/pkg/opam-file.t new file mode 100644 index 00000000000..fab00c271f3 --- /dev/null +++ b/test/blackbox-tests/test-cases/pkg/opam-file.t @@ -0,0 +1,54 @@ +Tests for reading dependencies out of opam files + + $ . ./helpers.sh + $ mkrepo + $ add_mock_repo_if_needed + + $ cat >dune-project < (lang dune 3.17) + > EOF + +Make sure we can read an disjunction from the opam file and solve a project +respecting the filters. + + $ mkpkg a + $ mkpkg b + +A package that depends on a disjunction should solve correctly with either side +of the disjunction to be picked for a solution: + + $ cat > x.opam < opam-version: "2.0" + > depends: [ + > "a" | "b" + > ] + > EOF + $ dune pkg lock + Solution for dune.lock: + - a.0.0.1 + +With the right filters, the other side of the disjunction should get picked: + + $ cat > x.opam < opam-version: "2.0" + > depends: [ + > "a" {> "1.0"} | "b" {< "1.0"} + > ] + > EOF + $ dune pkg lock + Solution for dune.lock: + - b.0.0.1 + +Unreachable packages should not be included. In the next test, "b" should not +be included in the lock directory because it is a post dep. Those are only +necessary during solving. + + $ cat > x.opam < opam-version: "2.0" + > depends: [ + > "a" {> "1.0"} | "b" {< "1.0" post} + > ] + > EOF + $ dune pkg lock + Solution for dune.lock: + (no dependencies to lock) diff --git a/test/blackbox-tests/test-cases/pkg/solver-vars-in-lockdir-metadata.t b/test/blackbox-tests/test-cases/pkg/solver-vars-in-lockdir-metadata.t index d1b594d379b..42013c43c12 100644 --- a/test/blackbox-tests/test-cases/pkg/solver-vars-in-lockdir-metadata.t +++ b/test/blackbox-tests/test-cases/pkg/solver-vars-in-lockdir-metadata.t @@ -74,7 +74,7 @@ Solve the packages again, this time with the variables set. - static-deps.1.0 (lang package 0.1) - (dependency_hash aea7daa72b636fa3a44973ec5e29d225) + (dependency_hash 3f813eed4e2e65a0b1d17fee9b738899) (repositories (complete false) @@ -85,7 +85,7 @@ Solve the packages again, this time with the variables set. - no-deps-b.1.0 (lang package 0.1) - (dependency_hash 6957fba0128609ffc98fac2561c329cb) + (dependency_hash 2b84dc8b1f93a9cb3c8c060235c014a2) (repositories (complete false) @@ -101,7 +101,7 @@ Solve the packages again, this time with the variables set. - no-deps-b.1.0 (lang package 0.1) - (dependency_hash 9675a3014e7e2db0f946b3ad2a95c037) + (dependency_hash dcccc0b378d9035f0f00a871c2d29359) (repositories (complete false) @@ -149,7 +149,7 @@ stored in the lockdir metadata: $ cat dune.lock/lock.dune (lang package 0.1) - (dependency_hash 72ab96748951e41c88d4ad9673fea081) + (dependency_hash e99c6a04197fafe2e8b7153de21bba97) (repositories (complete false)