Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

opam 2.1 integration #142

Merged
merged 13 commits into from
Nov 10, 2021
133 changes: 96 additions & 37 deletions depext.ml
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,15 @@ let has_prefix s pfx =
true
with Exit -> false

let is_opam_2_1 =
let is = lazy (String.sub (Lazy.force opam_version) 0 3 = "2.1") in
fun () -> Lazy.force is

let cliv_2_1 = "--cli=2.1"

let opam_query_global var =
let opt =
if Lazy.force opam_version = "2.1.0~alpha" then "--global" else ""
if is_opam_2_1 () then cliv_2_1 ^" --global" else ""
in
command_output (Printf.sprintf "opam var %s --readonly %s" var opt)

Expand Down Expand Up @@ -121,12 +127,13 @@ let depexts ~with_tests ~with_docs opam_packages =
fatal_error
"This version of opam-depext requires opam 2.0.0~beta5 or higher";
let c =
Printf.sprintf "opam list --readonly %s%s--external %s"
Printf.sprintf "opam list --readonly %s%s--external %s%s"
(if with_tests then "--with-test " else "")
(if with_docs then "--with-doc " else "")
(match opam_packages with
| [] -> ""
| ps -> " " ^ Filename.quote ("--resolve=" ^ String.concat "," ps))
(if is_opam_2_1 () then " "^cliv_2_1 else "")
in
let s = lines_of_command c in
let lines = List.filter (fun s -> String.length s > 0 && s.[0] <> '#') s in
Expand Down Expand Up @@ -171,7 +178,8 @@ let install_packages_commands ~interactive packages =
| s ->
fatal_error "Sorry, don't know how to install packages on your %s system" s

let update_command = match family with
let update_command =
match family with
| "debian" ->
["apt-get";"update"]
| "homebrew" ->
Expand Down Expand Up @@ -353,6 +361,11 @@ let main print_flags list short
let with_tests_arg = checkenv "OPAMWITHTEST" with_tests_arg in
let with_docs_arg = checkenv "OPAMWITHDOC" with_docs_arg in
if debug_arg then debug := true;
if is_opam_2_1 () then
Printf.eprintf
"You are using opam 2.1, where external dependency handling has been \
integrated: consider calling opam directly, the 'depext' plugin \
interface is provided for backwards compatibility only\n";
if print_flags then
(if short then
List.iter (fun (v,x) -> Printf.eprintf "%s=%s\n" v x) opam_vars
Expand All @@ -363,7 +376,9 @@ let main print_flags list short
if not short then
Printf.eprintf "# Detecting depexts using vars: %s\n%!"
(String.concat ", " (List.map (fun (v,x) -> v^"="^x) opam_vars));
let os_packages = depexts ~with_tests:with_tests_arg ~with_docs:with_docs_arg opam_packages in
let os_packages =
depexts ~with_tests:with_tests_arg ~with_docs:with_docs_arg opam_packages
in
if os_packages <> [] && not short then
begin
prerr_endline "# The following system packages are needed:";
Expand All @@ -374,43 +389,86 @@ let main print_flags list short
if list then exit 0;
if os_packages = [] && not short then
Printf.eprintf "# No extra OS packages requirements found.\n%!";
let installed = get_installed_packages os_packages in
let os_packages =
List.filter (fun p -> not (List.mem p installed)) os_packages
in
if short then List.iter print_endline os_packages
else if installed <> [] then
if os_packages <> [] then
Printf.eprintf
"# The following new OS packages need to be installed: %s\n%!"
(String.concat " " os_packages)
else
Printf.eprintf
"# All required OS packages found.\n%!";
if dryrun_arg then exit (if os_packages = [] then 0 else 1);
let su = su_arg || not (has_command "sudo") in
let interactive = match interactive_arg with
| Some i -> i
| None -> not (List.mem "--yes" opam_args) && Unix.isatty Unix.stdin
in
if (os_packages <> [] || opam_packages = []) && update_arg then
update ~su ~interactive;
install ~su ~interactive os_packages;
let opam_cmdline = "opam"::"install":: opam_args @ opam_packages in
if install_arg && opam_packages <> [] then begin
(if not short then Printf.eprintf "# Now letting OPAM install the packages\n%!");
let opam_cmdline = opam_cmdline @ (if with_tests_arg then ["--with-test"] else [])
@ (if with_docs_arg then ["--with-doc"] else []) in
(if !debug then Printf.eprintf "+ %s\n%!" (String.concat " " opam_cmdline));
Unix.execvp "opam" (Array.of_list opam_cmdline)
end
if is_opam_2_1 () then
let opam_run_args =
(if interactive then [] else ["--confirm-level=unsafe-yes"])
@ (if dryrun_arg then ["--dry-run"] else [])
in
let opam_install_args =
opam_args
@ (if with_tests_arg then ["--with-test"] else [])
@ (if with_docs_arg then ["--with-doc"] else [])
@ opam_run_args
in
(let opam_packages =
let toreinstall =
let pending =
lines_of_command ("opam reinstall --list-pending " ^ cliv_2_1)
|> List.filter_map (fun nv ->
match string_split '.' nv with
| n::_ -> Some n
| _ -> None)
in
let pin = lines_of_command ("opam pin list --short " ^ cliv_2_1) in
List.filter (fun p -> not (List.mem p pin)) pending
in
opam_packages @ toreinstall
in
if opam_packages <> [] then
if update_arg then
(match run_command (["opam"; "update"; "--depexts"]
@ opam_run_args @ [ cliv_2_1 ]) with
| Unix.WEXITED 0 ->
Printf.eprintf "# OS package update successful\n%!"
| _ -> fatal_error "OS package update failed");
let cmd =
let opam_install =
["opam"; "install"] @ opam_packages @ opam_install_args @ [ cliv_2_1 ]
in
if install_arg then opam_install else opam_install @ ["--depext-only"]
in
if !debug then Printf.eprintf "+ %s\n%!" (String.concat " " cmd);
Unix.execvp "opam" (Array.of_list cmd))
else
(let installed = get_installed_packages os_packages in
let os_packages =
List.filter (fun p -> not (List.mem p installed)) os_packages
in
if short then List.iter print_endline os_packages
else if installed <> [] then
if os_packages <> [] then
Printf.eprintf
"# The following new OS packages need to be installed: %s\n%!"
(String.concat " " os_packages)
else
Printf.eprintf
"# All required OS packages found.\n%!";
if dryrun_arg then exit (if os_packages = [] then 0 else 1);
let su = su_arg || not (has_command "sudo") in
if (os_packages <> [] || opam_packages = []) && update_arg then
update ~su ~interactive;
install ~su ~interactive os_packages;
let opam_cmdline = "opam"::"install":: opam_args @ opam_packages in
if install_arg && opam_packages <> [] then
((if not short then
Printf.eprintf "# Now letting opam install the packages\n%!");
let opam_cmdline =
opam_cmdline @ (if with_tests_arg then ["--with-test"] else [])
@ (if with_docs_arg then ["--with-doc"] else [])
in
(if !debug then Printf.eprintf "+ %s\n%!" (String.concat " " opam_cmdline));
Unix.execvp "opam" (Array.of_list opam_cmdline)))

open Cmdliner

let packages_arg =
Arg.(value & pos_all string [] &
info ~docv:"PACKAGES"
~doc:"OPAM packages to install external dependencies for. \
~doc:"opam packages to install external dependencies for. \
All installed packages if omitted" [])

let print_flags_arg =
Expand Down Expand Up @@ -498,8 +556,8 @@ let command =
let man = [
`S "DESCRIPTION";
`P "$(b,opam-depext) is a simple program intended to facilitate the \
interaction between OPAM packages and the host package management \
system. It can perform OS and distribution detection, query OPAM for \
interaction between opam packages and the host package management \
system. It can perform OS and distribution detection, query opam for \
the right external dependencies on a set of packages, and call the OS \
package manager in the appropriate way to install then.";
`S "OPAM OPTIONS";
Expand All @@ -508,21 +566,22 @@ let command =
$(i,--noninteractive) unless $(i,--interactive) was made explicit.";
`S "COPYRIGHT";
`P "$(b,opam-depext) is written by Louis Gesbert \
<louis.gesbert@ocamlpro.com>, copyright OCamlPro 2014-2015 with \
contributions from Anil Madhavapeddy, distributed under the terms of \
<louis.gesbert@ocamlpro.com>, copyright OCamlPro 2014-2021 with \
contributions from David Allsopp, Raja Boujbel, Kate Deplaix, \
Anil Madhavapeddy, distributed under the terms of \
the LGPL v2.1 with linking exception. Full source available at \
$(i,https://github.com/ocaml/opam-depext)";
`S "BUGS";
`P "Bugs are tracked at $(i,https://github.com/ocaml/opam-depext/issues) \
or can be reported to $(i,<opam-devel@lists.ocaml.org>).";
] in
let doc = "Query and install external dependencies of OPAM packages" in
let doc = "Query and install external dependencies of opam packages" in
Term.(pure main $ print_flags_arg $ list_arg $ short_arg $
debug_arg $ install_arg $ update_arg $ dryrun_arg $
with_tests_arg $ with_docs_arg $
su_arg $ interactive_arg $ opam_args $
packages_arg),
Term.info "opam-depext" ~version:"1.1.2" ~doc ~man
Term.info "opam-depext" ~version:"1.2.0" ~doc ~man

let () =
Sys.catch_break true;
Expand Down
2 changes: 1 addition & 1 deletion opam
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
opam-version: "2.0"
name: "opam-depext"
version: "1.1.0"
version: "1.2.0"
flags: plugin
maintainer: [
"Louis Gesbert <louis.gesbert@ocamlpro.com>"
Expand Down