1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
#!/usr/bin/env opam-admin.top
#directory "+../opam-lib";;
(**************************************************************************)
(* *)
(* Copyright 2015-2018 OCamlPro *)
(* *)
(* All rights reserved. This file is distributed under the terms of the *)
(* GNU Lesser General Public License version 2.1, with the special *)
(* exception on linking described in the file LICENSE. *)
(* *)
(**************************************************************************)
(** This script gives scenarios to install all named packages in a given set.
This may require several steps, in case of conflicts.
Consistent installation steps are printed one per line to stdout. Stderr
gives more detail.
Relies on the current opam root for the list of available packages, i.e.
depends on configured remotes, OS and OCaml version, but not on the set of
currently installed packages.
*)
open OpamTypes
let max_install t inst_packages =
let universe = OpamState.universe t Query in
let wish_field = "wished" in
let base = OpamState.base_packages t in
let universe =
{ universe with u_installed = base;
u_installed_roots = base;
u_attrs = [wish_field, inst_packages]; }
in
if not (OpamCudf.external_solver_available ()) then
failwith "No external solver found";
let preferences =
let preferences = OpamSolverConfig.criteria `Default in
Some (lazy (Printf.sprintf "+sum(solution,%s),%s" wish_field preferences))
in
OpamSolverConfig.update ~solver_preferences_default:preferences ();
let version_map =
OpamSolver.cudf_versions_map universe universe.u_available
in
let request = {
wish_install = [];
wish_remove = [];
wish_upgrade = [];
extra_attributes = [wish_field];
criteria = `Default;
} in
let cudf_universe =
OpamSolver.load_cudf_universe ~build:true universe ~version_map
universe.u_available
in
match OpamCudf.resolve ~extern:true ~version_map cudf_universe request with
| Conflicts _ -> failwith "Solver error (unexpected conflicts)"
| Success u ->
OpamPackage.Set.diff
(OpamPackage.Set.of_list
(List.map OpamCudf.cudf2opam (OpamCudf.packages u)))
base
module P = OpamPackage
open P.Set.Op
let rec couverture acc t pkgs =
Printf.eprintf "# %d packages remaining...\n%!"
(P.Name.Set.cardinal (P.names_of_packages pkgs));
let step = max_install t pkgs in
let added =
P.Name.Set.inter (P.names_of_packages step) (P.names_of_packages pkgs)
in
if P.Name.Set.is_empty added then
let () =
Printf.eprintf "# -> %d uninstallable packages remaining.\n%!"
(P.Name.Set.cardinal (P.names_of_packages pkgs))
in
List.rev acc, pkgs
else
let n = P.Name.Set.cardinal added in
Printf.eprintf "# -> Step %d: covering %d/%d packages%s.\n%!"
(List.length acc + 1) n (P.Name.Set.cardinal (P.names_of_packages pkgs))
(if n > 5 then "" else
OpamStd.List.concat_map ~left:" (" ~right:")" " " P.Name.to_string
(OpamPackage.Name.Set.elements added));
let pkgs =
P.Set.filter
(fun nv -> not (P.has_name step (P.name nv))) pkgs
in
couverture (step::acc) t pkgs
let () =
let root = OpamStateConfig.opamroot () in
OpamFormatConfig.init ();
if not (OpamStateConfig.load_defaults root) then
failwith "Opam root not found";
OpamCoreConfig.init ();
OpamSolverConfig.init ();
OpamStateConfig.init ();
let t =
OpamState.load_state ~save_cache:false "couverture"
(OpamStateConfig.get_switch_opt ())
in
let avail = Lazy.force t.OpamState.Types.available_packages in
let wanted = match Array.to_list Sys.argv with
| [] | _::[] ->
avail -- P.packages_of_names avail (OpamState.base_package_names t)
| _::l ->
List.fold_left (fun wanted name ->
let nvs =
if String.contains name '.' then
P.Set.singleton (P.of_string name)
else
P.packages_of_name avail
(P.Name.of_string name)
in
if P.Set.is_empty (nvs %% avail) then
failwith (Printf.sprintf "Package %s not found" name)
else
wanted ++ nvs
) P.Set.empty l
in
let couv,remaining = couverture [] t wanted in
let avail_names = P.names_of_packages avail in
let remaining_names = P.names_of_packages remaining in
Printf.eprintf "# Found a couverture for %d over %d packages in %d steps:\n%!"
(P.Name.Set.cardinal (P.Name.Set.diff avail_names remaining_names))
(P.Name.Set.cardinal avail_names)
(List.length couv);
List.iter (fun s ->
print_endline
(OpamStd.List.concat_map " " OpamPackage.to_string
(P.Set.elements s)))
couv;
Printf.eprintf "# %d uninstallable packages remain: %s\n%!"
(P.Name.Set.cardinal remaining_names)
(OpamStd.List.concat_map " " OpamPackage.Name.to_string
(P.Name.Set.elements remaining_names))
|