From e25b618da187d9126efea11d0fc6ada578c4c04f Mon Sep 17 00:00:00 2001 From: Kate Date: Mon, 24 Jul 2023 18:34:42 +0100 Subject: [PATCH 1/5] opam tree: Allow packages with a specific version, directories or local opam files, as input --- master_changes.md | 4 ++ src/client/opamCommands.ml | 17 +++++-- src/client/opamTreeCommand.ml | 26 ++++++----- src/client/opamTreeCommand.mli | 3 +- tests/reftests/tree.test | 84 +++++++++++++++++++++++++++++++++- 5 files changed, 114 insertions(+), 20 deletions(-) diff --git a/master_changes.md b/master_changes.md index 01a8ec7c921..da33c3a11ef 100644 --- a/master_changes.md +++ b/master_changes.md @@ -41,6 +41,9 @@ users) ## Update / Upgrade +## Tree + * Allow packages with a specific version, directories or local opam files, as input [#5613 @kit-ty-kate] + ## Exec ## Source @@ -109,6 +112,7 @@ users) # API updates ## opam-client + * `OpamTreeCommand.run`: now takes an `atom` instead of `name` [#5613 @kit-ty-kate] ## opam-repository diff --git a/src/client/opamCommands.ml b/src/client/opamCommands.ml index 89b59c00ec3..85f07e9d22c 100644 --- a/src/client/opamCommands.ml +++ b/src/client/opamCommands.ml @@ -821,28 +821,35 @@ let tree ?(why=false) cli = switch to draw the forest" in let tree global_options mode filter post dev doc test dev_setup no_constraint - no_switch names () = - if names = [] && no_switch then + no_switch atoms_or_locals () = + if atoms_or_locals = [] && no_switch then `Error - (true, "--no-switch can't be used without specifying a name") + (true, "--no-switch can't be used without specifying a package") else (apply_global_options cli global_options; OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_none gt @@ fun st -> + let recurse = false in (* TODO *) + let subpath = None in (* TODO *) + let st, atoms = + OpamAuxCommands.simulate_autopin + st ~recurse ?subpath ~quiet:true + ?locked:OpamStateConfig.(!r.locked) atoms_or_locals + in let tog = OpamListCommand.{ post; test; doc; dev; dev_setup; recursive = false; depopts = false; build = true; } in - OpamTreeCommand.run st tog ~no_constraint ~no_switch mode filter names; + OpamTreeCommand.run st tog ~no_constraint ~no_switch mode filter atoms; `Ok ()) in mk_command_ret ~cli (cli_from cli2_2) "tree" ~doc ~man Term.(const tree $global_options cli $mode $filter $post cli $dev cli $doc_flag cli $test cli $dev_setup cli $no_cstr $no_switch - $name_list) + $atom_or_local_list) (* SHOW *) let show_doc = "Display information about specific packages." diff --git a/src/client/opamTreeCommand.ml b/src/client/opamTreeCommand.ml index 4acfbe9ab6f..f3504948cb6 100644 --- a/src/client/opamTreeCommand.ml +++ b/src/client/opamTreeCommand.ml @@ -406,15 +406,13 @@ let simulate_new_state tog st universe install names = (OpamSwitchState.unavailable_reason st) cs); OpamStd.Sys.exit_because `No_solution -let dry_install tog st universe missing = - let install = missing |> List.map (fun name -> name, None) in +let dry_install tog st universe install = simulate_new_state tog st universe install - (OpamPackage.Name.Set.of_list missing) + (OpamPackage.Name.Set.of_list (List.map fst install)) -let raw_state tog st names = +let raw_state tog st install = let OpamListCommand.{doc; test; dev_setup; _} = tog in - let install = List.map (fun name -> name, None) names in - let names = OpamPackage.Name.Set.of_list names in + let names = OpamPackage.Name.Set.of_list (List.map fst install) in let requested = OpamPackage.packages_of_names (Lazy.force st.available_packages) @@ -430,9 +428,15 @@ let raw_state tog st names = in simulate_new_state tog st universe install names -let run st tog ?no_constraint ?(no_switch=false) mode filter names = +let run st tog ?no_constraint ?(no_switch=false) mode filter atoms = let select, missing = - List.partition (OpamSwitchState.is_name_installed st) names + List.fold_left (fun (select, missing) atom -> + if OpamPackage.Set.disjoint + (OpamSwitchState.packages_of_atoms st [atom]) + st.installed + then (select, atom :: missing) + else (fst atom :: select, missing) + ) ([], []) atoms in let st, universe = let universe = get_universe tog st in @@ -450,8 +454,8 @@ let run st tog ?no_constraint ?(no_switch=false) mode filter names = OpamConsole.warning "Not installed package%s %s, skipping" (match missing with | [_] -> "" | _ -> "s") (OpamStd.Format.pretty_list - (List.map OpamPackage.Name.to_string missing)); - if select = [] && names <> [] then + (List.map (fun (name, _) -> OpamPackage.Name.to_string name) missing)); + if select = [] && atoms <> [] then OpamConsole.error_and_exit `Not_found "No package to display" else st, universe @@ -459,7 +463,7 @@ let run st tog ?no_constraint ?(no_switch=false) mode filter names = if OpamPackage.Set.is_empty st.installed then OpamConsole.error_and_exit `Not_found "No package is installed" else - let forest = build st universe tog mode filter names in + let forest = build st universe tog mode filter (select @ List.map fst missing) in print ?no_constraint forest; if OpamClientConfig.(!r.json_out) <> None then (if not no_switch then diff --git a/src/client/opamTreeCommand.mli b/src/client/opamTreeCommand.mli index 18039840e55..d109742b722 100644 --- a/src/client/opamTreeCommand.mli +++ b/src/client/opamTreeCommand.mli @@ -11,7 +11,6 @@ (** Functions handling the "opam tree" subcommand *) -open OpamTypes open OpamStateTypes (** Speficy the type of the forest to build *) @@ -37,4 +36,4 @@ val run : ?no_constraint:bool -> (* do no keep switch consistency *) ?no_switch:bool -> - mode -> tree_filter -> name list -> unit + mode -> tree_filter -> OpamTypes.atom list -> unit diff --git a/tests/reftests/tree.test b/tests/reftests/tree.test index e7573eca312..9e988fa7f04 100644 --- a/tests/reftests/tree.test +++ b/tests/reftests/tree.test @@ -282,8 +282,8 @@ e.1 [ERROR] No package to display # Return code 5 # ### opam tree --no-switch | '…' -> '...' | '`' -> "'" -opam: --no-switch can't be used without specifying a name -Usage: opam tree [OPTION]... [PACKAGES]... +opam: --no-switch can't be used without specifying a package +Usage: opam tree [--recursive] [--subpath=PATH] [OPTION]... [PACKAGES]... Try 'opam tree --help' or 'opam --help' for more information. # Return code 2 # ### opam tree f h --no-switch @@ -388,3 +388,83 @@ Done. You can temporarily relax the switch invariant with `--update-invariant' # Return code 20 # +### +opam-version: "2.0" +depends: "a" +### +opam-version: "2.0" +depends: "b" +### opam switch create extended-inputs --empty +### opam tree i +The following actions are simulated: +=== install 3 packages + - install a 1 [required by b] + - install b 1 [required by i] + - install i 2 + +i.2 +'-- b.1 + '-- a.1 +### opam tree i.1 +The following actions are simulated: +=== install 2 packages + - install a 1 [required by i] + - install i 1 + +i.1 +'-- a.1 +### opam tree i.2 +The following actions are simulated: +=== install 3 packages + - install a 1 [required by b] + - install b 1 [required by i] + - install i 2 + +i.2 +'-- b.1 + '-- a.1 +### opam install i.2 +The following actions will be performed: +=== install 3 packages + - install a 1 [required by b] + - install b 1 [required by i] + - install i 2 + +<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> +-> installed a.1 +-> installed b.1 +-> installed i.2 +Done. +### opam tree i.1 +The following actions are simulated: +=== downgrade 1 package + - downgrade i 2 to 1 + +i.1 +'-- a.1 +### +opam-version: "2.0" +depends: ["local-pkg-core" "b"] +### +opam-version: "2.0" +depends: "a" +### opam tree . +The following actions are simulated: +=== install 2 packages + - install local-pkg dev + - install local-pkg-core dev + +local-pkg.dev +|-- b.1 +| '-- a.1 +'-- local-pkg-core.dev + '-- a.1 [*] + +local-pkg-core.dev +### opam tree ./local-pkg-core.opam +The following actions are simulated: +=== install 1 package + - install local-pkg-core dev + +local-pkg-core.dev +'-- a.1 From 1b6b37677f1f906893b579941f8157e720813806 Mon Sep 17 00:00:00 2001 From: Kate Date: Tue, 8 Aug 2023 13:31:06 +0100 Subject: [PATCH 2/5] Add --recurse and --subpath to opam tree Co-authored-by: R. Boujbel --- master_changes.md | 1 + src/client/opamCommands.ml | 7 +++---- src/client/opamTreeCommand.ml | 2 +- tests/reftests/tree.test | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/master_changes.md b/master_changes.md index da33c3a11ef..e413f208052 100644 --- a/master_changes.md +++ b/master_changes.md @@ -43,6 +43,7 @@ users) ## Tree * Allow packages with a specific version, directories or local opam files, as input [#5613 @kit-ty-kate] + * Add handling of `--recurse` and `--subpath` for directory arguments [#5613 @kit-ty-kate] ## Exec diff --git a/src/client/opamCommands.ml b/src/client/opamCommands.ml index 85f07e9d22c..0bb1133204a 100644 --- a/src/client/opamCommands.ml +++ b/src/client/opamCommands.ml @@ -821,16 +821,14 @@ let tree ?(why=false) cli = switch to draw the forest" in let tree global_options mode filter post dev doc test dev_setup no_constraint - no_switch atoms_or_locals () = + no_switch recurse subpath atoms_or_locals () = if atoms_or_locals = [] && no_switch then `Error - (true, "--no-switch can't be used without specifying a package") + (true, "--no-switch can't be used without specifying a package or a path") else (apply_global_options cli global_options; OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_none gt @@ fun st -> - let recurse = false in (* TODO *) - let subpath = None in (* TODO *) let st, atoms = OpamAuxCommands.simulate_autopin st ~recurse ?subpath ~quiet:true @@ -849,6 +847,7 @@ let tree ?(why=false) cli = Term.(const tree $global_options cli $mode $filter $post cli $dev cli $doc_flag cli $test cli $dev_setup cli $no_cstr $no_switch + $recurse cli $subpath cli $atom_or_local_list) (* SHOW *) diff --git a/src/client/opamTreeCommand.ml b/src/client/opamTreeCommand.ml index f3504948cb6..8a30ecd623f 100644 --- a/src/client/opamTreeCommand.ml +++ b/src/client/opamTreeCommand.ml @@ -454,7 +454,7 @@ let run st tog ?no_constraint ?(no_switch=false) mode filter atoms = OpamConsole.warning "Not installed package%s %s, skipping" (match missing with | [_] -> "" | _ -> "s") (OpamStd.Format.pretty_list - (List.map (fun (name, _) -> OpamPackage.Name.to_string name) missing)); + (List.map OpamFormula.string_of_atom missing)); if select = [] && atoms <> [] then OpamConsole.error_and_exit `Not_found "No package to display" else diff --git a/tests/reftests/tree.test b/tests/reftests/tree.test index 9e988fa7f04..4fa64cbbdbc 100644 --- a/tests/reftests/tree.test +++ b/tests/reftests/tree.test @@ -282,7 +282,7 @@ e.1 [ERROR] No package to display # Return code 5 # ### opam tree --no-switch | '…' -> '...' | '`' -> "'" -opam: --no-switch can't be used without specifying a package +opam: --no-switch can't be used without specifying a package or a path Usage: opam tree [--recursive] [--subpath=PATH] [OPTION]... [PACKAGES]... Try 'opam tree --help' or 'opam --help' for more information. # Return code 2 # From 50beb712269a9a69d6b95d5d0ab8edab149e52c0 Mon Sep 17 00:00:00 2001 From: Kate Date: Tue, 15 Aug 2023 19:56:23 +0100 Subject: [PATCH 3/5] reftest: Test opam tree with installed local packages Co-authored-by: R. Boujbel --- tests/reftests/tree.test | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/reftests/tree.test b/tests/reftests/tree.test index 4fa64cbbdbc..3b553d6bc21 100644 --- a/tests/reftests/tree.test +++ b/tests/reftests/tree.test @@ -468,3 +468,42 @@ The following actions are simulated: local-pkg-core.dev '-- a.1 +### +opam-version: "2.0" +depends: ["b" "installed-local-core"] +### +opam-version: "2.0" +depends: "a" +### opam install ./dir +Package installed-local does not exist, create as a NEW package? [y/n] y +installed-local is now pinned to file://${BASEDIR}/dir (version dev) +Package installed-local-core does not exist, create as a NEW package? [y/n] y +installed-local-core is now pinned to file://${BASEDIR}/dir (version dev) +The following actions will be performed: +=== install 2 packages + - install installed-local dev (pinned) + - install installed-local-core dev (pinned) + +<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> +-> retrieved installed-local.dev (file://${BASEDIR}/dir) +-> retrieved installed-local-core.dev (file://${BASEDIR}/dir) +-> installed installed-local-core.dev +-> installed installed-local.dev +Done. +### opam tree installed-local +installed-local.dev +|-- b.1 +| '-- a.1 +'-- installed-local-core.dev + '-- a.1 [*] +### opam tree ./dir +installed-local.dev +|-- b.1 +| '-- a.1 +'-- installed-local-core.dev + '-- a.1 [*] + +installed-local-core.dev +### opam tree ./dir/installed-local-core.opam +installed-local-core.dev +'-- a.1 From 8e127466f90d96eff3b08c97f442ffd4b118bf3d Mon Sep 17 00:00:00 2001 From: Kate Date: Tue, 15 Aug 2023 20:00:23 +0100 Subject: [PATCH 4/5] Speedup OpamTreeCommand.run Co-authored-by: R. Boujbel --- src/client/opamTreeCommand.ml | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/client/opamTreeCommand.ml b/src/client/opamTreeCommand.ml index 8a30ecd623f..cf5ac7335ef 100644 --- a/src/client/opamTreeCommand.ml +++ b/src/client/opamTreeCommand.ml @@ -43,13 +43,6 @@ type resulting_forest = | DepsForest of deps node forest | RevdepsForest of revdeps node forest -let installed st names = - names |> List.fold_left (fun state n -> - (* non-installed packages should already be simulated to be installed *) - OpamSwitchState.find_installed_package_by_name st n :: state - ) [] |> OpamPackage.Set.of_list - - (** Forest building *) let build_condition_map tog st = @@ -143,7 +136,6 @@ let cut_leaves (mode: [ `succ | `pred]) ~names ~root st graph = OpamPackage.Set.inter root packages, graph let build_deps_forest st universe tog filter names = - let names = installed st names in let OpamListCommand.{ build; post; _ } = tog in let root, graph = let graph = @@ -191,7 +183,6 @@ let build_deps_forest st universe tog filter names = |> snd let build_revdeps_forest st universe tog filter names = - let names = installed st names in let OpamListCommand.{ build; post; _ } = tog in let root, graph = let graph = @@ -429,14 +420,16 @@ let raw_state tog st install = simulate_new_state tog st universe install names let run st tog ?no_constraint ?(no_switch=false) mode filter atoms = + let open OpamPackage.Set.Op in let select, missing = List.fold_left (fun (select, missing) atom -> - if OpamPackage.Set.disjoint - (OpamSwitchState.packages_of_atoms st [atom]) - st.installed - then (select, atom :: missing) - else (fst atom :: select, missing) - ) ([], []) atoms + let installed = + OpamPackage.Set.filter (OpamFormula.check atom) st.installed + in + if OpamPackage.Set.is_empty installed then + (select, atom :: missing) + else (installed ++ select, missing)) + (OpamPackage.Set.empty, []) atoms in let st, universe = let universe = get_universe tog st in @@ -455,7 +448,7 @@ let run st tog ?no_constraint ?(no_switch=false) mode filter atoms = (match missing with | [_] -> "" | _ -> "s") (OpamStd.Format.pretty_list (List.map OpamFormula.string_of_atom missing)); - if select = [] && atoms <> [] then + if OpamPackage.Set.is_empty select && atoms <> [] then OpamConsole.error_and_exit `Not_found "No package to display" else st, universe @@ -463,7 +456,10 @@ let run st tog ?no_constraint ?(no_switch=false) mode filter atoms = if OpamPackage.Set.is_empty st.installed then OpamConsole.error_and_exit `Not_found "No package is installed" else - let forest = build st universe tog mode filter (select @ List.map fst missing) in + let simulated = OpamFormula.packages_of_atoms st.installed missing in + let forest = + build st universe tog mode filter (select ++ simulated) + in print ?no_constraint forest; if OpamClientConfig.(!r.json_out) <> None then (if not no_switch then From 54f0e9b8cf7f173174c80471d81b007b52073d63 Mon Sep 17 00:00:00 2001 From: Kate Date: Tue, 22 Aug 2023 19:47:50 +0100 Subject: [PATCH 5/5] reftest: Test behaviour of opam tree when asking for an uninstalled version of an already installed package Co-authored-by: R. Boujbel --- tests/reftests/tree.test | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/reftests/tree.test b/tests/reftests/tree.test index 3b553d6bc21..d74a2b8956d 100644 --- a/tests/reftests/tree.test +++ b/tests/reftests/tree.test @@ -507,3 +507,26 @@ installed-local-core.dev ### opam tree ./dir/installed-local-core.opam installed-local-core.dev '-- a.1 +### : different package version : +### +opam-version: "2.0" +### opam tree a.2 +The following actions are simulated: +=== recompile 4 packages + - recompile b 1 [uses a] + - recompile i 2 [uses b] + - recompile installed-local dev (pinned) [uses b, installed-local-core] + - recompile installed-local-core dev (pinned) [uses a] +=== upgrade 1 package + - upgrade a 1 to 2 + +a.2 +### opam list a +# Packages matching: name-match(a) & (installed | available) +# Package # Installed # Synopsis +a.1 1 +a.2 1 +### opam tree --rev-deps a.2 +[WARNING] Not installed package a (= 2), skipping +[ERROR] No package to display +# Return code 5 #