Skip to content

Commit

Permalink
provide Nix depexts with shell environment variables
Browse files Browse the repository at this point in the history
  • Loading branch information
RyanGibb committed May 30, 2024
1 parent c8366f7 commit e2442fc
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 14 deletions.
6 changes: 3 additions & 3 deletions src/client/opamSolution.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1181,7 +1181,7 @@ let install_depexts ?(force_depext=false) ?(confirm=true) t packages =
let answer =
let pkgman =
OpamConsole.colorise `yellow
(OpamSysInteract.package_manager_name ~env config)
(OpamSysInteract.package_manager_name ~env t.switch config)
in
OpamConsole.menu ~unsafe_yes:`Yes ~default:`Yes ~no:`Quit
"opam believes some required external dependencies are missing. opam \
Expand Down Expand Up @@ -1213,7 +1213,7 @@ let install_depexts ?(force_depext=false) ?(confirm=true) t packages =
| `Quit -> give_up_msg (); OpamStd.Sys.exit_because `Aborted
and print_command sys_packages =
let commands =
OpamSysInteract.install_packages_commands ~env config sys_packages
OpamSysInteract.install_packages_commands ~env t.switch config sys_packages
|> List.map (fun ((`AsAdmin c | `AsUser c), a) -> c::a)
in
OpamConsole.formatted_msg
Expand Down Expand Up @@ -1242,7 +1242,7 @@ let install_depexts ?(force_depext=false) ?(confirm=true) t packages =
| `Quit -> give_up ()
and auto_install t sys_packages =
try
OpamSysInteract.install ~env config sys_packages; (* handles dry_run *)
OpamSysInteract.install ~env t.switch config sys_packages; (* handles dry_run *)
map_sysmap (fun _ -> OpamSysPkg.Set.empty) t
with Failure msg ->
OpamConsole.error "%s" msg;
Expand Down
9 changes: 8 additions & 1 deletion src/state/opamEnv.ml
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,14 @@ let compute_updates ?(force_path=false) st =
in
List.map resolve_separator_and_format updates
in
switch_env @ pkg_env @ man_path @ [path]
let nix_env =
let open OpamFilename in
create (OpamPath.Switch.meta OpamStateConfig.(!r.root_dir) st.switch) (basename (raw "nix.env"))
|> OpamFile.make
|> OpamFile.Environment.read_opt
|> Option.fold ~none:[] ~some:(List.map resolve_separator_and_format)
in
switch_env @ pkg_env @ man_path @ [path] @ nix_env

let updates_common ~set_opamroot ~set_opamswitch root switch =
let root =
Expand Down
56 changes: 49 additions & 7 deletions src/state/opamSysInteract.ml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ type families =
| Macports
| Msys2
| Netbsd
| Nix
| Openbsd
| Suse

Expand Down Expand Up @@ -198,6 +199,7 @@ let family ~env () =
| "gentoo" -> Gentoo
| "homebrew" -> Homebrew
| "macports" -> Macports
| "nixos" -> Nix
| "macos" ->
failwith
"External dependency handling for macOS requires either \
Expand Down Expand Up @@ -896,6 +898,16 @@ let packages_status ?(env=OpamVariable.Map.empty) config packages =
|> package_set_of_pkgpath
in
compute_sets sys_installed
| Nix ->
(* We say all requested packages are available but uninstalled.
We could check that these packages are available in Nixpkgs,
but that would involve an expensive Nixpkgs evaluation.
Saying no packages are installed results in a warning that
conf packages depend on a 'system package that can no longer
be found.' But omitting them will mean that they won't be
added to the Nix derivation.
*)
packages, OpamSysPkg.Set.empty;
| Openbsd ->
let sys_installed =
run_query_command "pkg_info" ["-mqP"]
Expand Down Expand Up @@ -931,7 +943,7 @@ let packages_status ?(env=OpamVariable.Map.empty) config packages =

(* Install *)

let install_packages_commands_t ?(env=OpamVariable.Map.empty) config sys_packages =
let install_packages_commands_t ?(env=OpamVariable.Map.empty) switch config sys_packages =
let unsafe_yes = OpamCoreConfig.answer_is `unsafe_yes in
let yes ?(no=[]) yes r =
if unsafe_yes then
Expand Down Expand Up @@ -1009,14 +1021,43 @@ let install_packages_commands_t ?(env=OpamVariable.Map.empty) config sys_package
[`AsUser (Commands.msys2 config),
"-Su"::"--noconfirm"::packages], None
| Netbsd -> [`AsAdmin "pkgin", yes ["-y"] ("install" :: packages)], None
| Nix ->
let open OpamFilename in
let dir = OpamPath.Switch.meta OpamStateConfig.(!r.root_dir) switch in
let drvFile = create dir (basename (raw "env.nix")) in
let packages = String.concat " " (List.rev (OpamSysPkg.Set.fold (fun p l -> OpamSysPkg.to_string p :: l) sys_packages [])) in
let contents =
{|{ pkgs ? import <nixpkgs> {} }:
with pkgs;
stdenv.mkDerivation {
name = "opam-nix-env";
nativeBuildInputs = with buildPackages; [ |} ^ packages ^ {| ];

phases = [ "buildPhase" ];

buildPhase = ''
vars=("NIX_CC" "NIX_CC_FLAGS" "NIX_CFLAGS_COMPILE" "NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu" "NIX_LDFLAGS" "PKG_CONFIG_PATH")
for var in "''${vars[@]}"; do
escaped="$(echo "''${!var}" | sed -e 's/^$/@/' -e 's/ /\\ /g')"
echo "$var = $escaped Nix" >> $out
done
echo "PATH += $PATH Nix" >> $out
'';

preferLocalBuild = true;
}
|} in
write drvFile contents;
let envFile = create dir (basename (raw "nix.env")) |> OpamFilename.to_string in
[`AsUser "nix-build", [ OpamFilename.to_string drvFile; "--out-link"; envFile ] ], None
| Openbsd -> [`AsAdmin "pkg_add", yes ~no:["-i"] ["-I"] packages], None
| Suse -> [`AsAdmin "zypper", yes ["--non-interactive"] ("install"::packages)], None

let install_packages_commands ?env config sys_packages =
fst (install_packages_commands_t ?env config sys_packages)
let install_packages_commands ?env switch config sys_packages =
fst (install_packages_commands_t ?env switch config sys_packages)

let package_manager_name ?env config =
match install_packages_commands ?env config OpamSysPkg.Set.empty with
let package_manager_name ?env switch config =
match install_packages_commands ?env switch config OpamSysPkg.Set.empty with
| ((`AsAdmin pkgman | `AsUser pkgman), _) :: _ -> pkgman
| [] -> assert false

Expand All @@ -1041,11 +1082,11 @@ let sudo_run_command ?(env=OpamVariable.Map.empty) ?vars cmd args =
"failed with exit code %d at command:\n %s"
code (String.concat " " (cmd::args))

let install ?env config packages =
let install ?env switch config packages =
if OpamSysPkg.Set.is_empty packages then
log "Nothing to install"
else
let commands, vars = install_packages_commands_t ?env config packages in
let commands, vars = install_packages_commands_t ?env switch config packages in
let vars = OpamStd.Option.map (List.map (fun x -> `add, x)) vars in
List.iter
(fun (cmd, args) ->
Expand All @@ -1069,6 +1110,7 @@ let update ?(env=OpamVariable.Map.empty) config =
| Macports -> Some (`AsAdmin "port", ["sync"])
| Msys2 -> Some (`AsUser (Commands.msys2 config), ["-Sy"])
| Netbsd -> None
| Nix -> None
| Openbsd -> None
| Suse -> Some (`AsAdmin "zypper", ["--non-interactive"; "refresh"])
in
Expand Down
6 changes: 3 additions & 3 deletions src/state/opamSysInteract.mli
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ val packages_status:
(* Return the commands to run to install given system packages.
[env] is used to determine host specification. *)
val install_packages_commands:
?env:gt_variables -> OpamFile.Config.t -> OpamSysPkg.Set.t ->
?env:gt_variables -> OpamSwitch.t -> OpamFile.Config.t -> OpamSysPkg.Set.t ->
([`AsAdmin of string | `AsUser of string] * string list) list

(* Install given system packages, by calling local system package manager.
[env] is used to determine host specification. *)
val install: ?env:gt_variables -> OpamFile.Config.t -> OpamSysPkg.Set.t -> unit
val install: ?env:gt_variables -> OpamSwitch.t -> OpamFile.Config.t -> OpamSysPkg.Set.t -> unit

val update: ?env:gt_variables -> OpamFile.Config.t -> unit

val package_manager_name: ?env:gt_variables -> OpamFile.Config.t -> string
val package_manager_name: ?env:gt_variables -> OpamSwitch.t -> OpamFile.Config.t -> string

(* Determine if special packages may need installing to enable other
repositories.
Expand Down

0 comments on commit e2442fc

Please sign in to comment.