Sorry I also realised you might want to just know if it is possible, and I think it is. The problem is that something as seemingly simple as
opam install irmin is actually very complicated involving global state and switch state. To understand how opam installs something for example, you can read the source code for the opam commands in the client – for example the install command.
Hopefully you’ll agree that it is very complicated but not impossible to reproduce. For example on my machine the following will install
let install () =
OpamClientConfig.opam_init ~current_switch:(OpamSwitch.of_string "4.11.0") ();
let pkg = OpamPackage.Name.of_string "irmin" in
OpamGlobalState.with_ `Lock_none @@ fun gt ->
OpamSwitchState.with_ `Lock_write gt @@ fun st ->
OpamClient.install st [ (pkg, None) ]
let () = ignore (install ())
This was fast and dirty (I happen to have a 4.11.0 switch) just to show that is ~possible~ but I’m not going to recommend it because I don’t understand enough of the internals of opam to make sure it doesn’t break lots of invariants etc. and leave someone’s opam in a broken state. For these complicated functions I still think using the command line is your safest bet.
For simpler functions, say to list the names of packages based on the available opam files in your current directory, then using these exposed modules makes sense as it doesn’t alter the internals of opam.
let opam_files () =
let lst = OpamPinned.files_in_source (OpamFilename.Dir.of_string ".") in
| Some f, _, _ -> print_endline (OpamPackage.Name.to_string f) | _ -> ())
To get your head around the exposed functions I’d recommend installing the libraries from the opam repo and then using
odig doc opam-<xyz> (odig) to have a look at the documentation (I don’t think it is currently online anywhere).