diff --git a/README.md b/README.md index 4e7b253..770069d 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ nix run github:eureka-cpu/ns -- # Add or remove it from your user profile: ```sh -nix profile install github:eureka-cpu/ns +nix profile add github:eureka-cpu/ns nix profile remove ns ``` diff --git a/dune-project b/dune-project index 9477af7..525cce3 100644 --- a/dune-project +++ b/dune-project @@ -2,7 +2,7 @@ (name ns) -(version 0.4.2) +(version 0.4.3) (generate_opam_files true) diff --git a/lib/cmd.ml b/lib/cmd.ml index a8b3e7c..f103e5b 100644 --- a/lib/cmd.ml +++ b/lib/cmd.ml @@ -19,14 +19,14 @@ module Cmd = struct Bos.Cmd.v "nix" |>+ [ "develop" ] @ [ Uri.sprintf_uri_attr_opt entrypoint attribute ] |>+ Option.value ~default:[] force_experimental_features - |>+ [ "--command"; Unix.shell ] + |>+ [ "--command"; Unix.shell () ] ;; let legacy_nix_shell_from_entrypoint entrypoint attribute = Bos.Cmd.v "nix-shell" |>+ Option.value ~default:[] (Option.map (fun attr -> [ "--attr"; attr ]) attribute) |>+ [ entrypoint ] - |>+ [ "--command"; Unix.shell ] + |>+ [ "--command"; Unix.shell () ] ;; let nix_shell installables force_experimental_features = @@ -40,7 +40,7 @@ module Cmd = struct (* Need to combine/validate that the installables given are all Nixpkgs *) Bos.Cmd.v "nix-shell" |>+ [ "--packages" ] @ installables - |>+ [ "--command"; Unix.shell ] + |>+ [ "--command"; Unix.shell () ] ;; let print_strategy ({ workdir; primary; fallback } : strategy) = diff --git a/lib/util.ml b/lib/util.ml index 13b3479..5b420f9 100644 --- a/lib/util.ml +++ b/lib/util.ml @@ -22,12 +22,8 @@ module Util = struct Error.handle_ns_error "%s" (Error.sprintf_unix_error e path) ;; - (** Get the user's shell from the environment *) - let shell = - match Sys.getenv_opt "SHELL" with - | Some s -> s - | None -> "/bin/sh" - ;; + (** Get the user's login shell *) + let shell () = (Unix.getpwuid (Unix.getuid ())).Unix.pw_shell (** Whether a flake.nix file exists at the given directory *) let flake_exists_at dir = Sys.file_exists (Filename.concat dir "flake.nix") diff --git a/ns.opam b/ns.opam index b29416a..7603df2 100644 --- a/ns.opam +++ b/ns.opam @@ -1,6 +1,6 @@ # This file is generated by dune, edit dune-project instead opam-version: "2.0" -version: "0.4.2" +version: "0.4.3" synopsis: "A unified interface for nix shell." description: "An intuitive nix shell interface that unifies the `nix shell`, `nix develop` and `nix-shell` commands." diff --git a/test/dune b/test/dune index 3acffcd..29c44e5 100644 --- a/test/dune +++ b/test/dune @@ -16,4 +16,4 @@ (targets test_ns) ; the Dune target name (deps test_ns.rs) ; path relative to this dune file (action - (run rustc --test %{deps} -o %{targets} --allow warnings))) + (run rustc --test %{deps} -o %{targets} -A warnings -l c))) diff --git a/test/test_ns.rs b/test/test_ns.rs index edaa50b..dfa2164 100644 --- a/test/test_ns.rs +++ b/test/test_ns.rs @@ -1,4 +1,4 @@ -use std::{env, path, process, sync}; +use std::{env, ffi, path, process, sync}; static DUNE_TEST_DIR: sync::OnceLock = sync::OnceLock::new(); static ENV_SHELL: sync::OnceLock = sync::OnceLock::new(); @@ -6,8 +6,41 @@ static ENV_SHELL: sync::OnceLock = sync::OnceLock::new(); fn dune_test_dir() -> &'static path::PathBuf { DUNE_TEST_DIR.get_or_init(|| env::current_dir().expect("failed to get test directory")) } -fn env_shell() -> &'static String { - ENV_SHELL.get_or_init(|| env::var("SHELL").expect("failed to get shell from environment")) + +/// Minimal bindings to dynamically linked libc, used for getting the shell of the logged in user. +mod libc { + unsafe extern "C" { + pub fn getuid() -> u32; + pub fn getpwuid(uid: u32) -> *mut Passwd; + } + + #[repr(C)] + pub struct Passwd { + pub pw_name: *mut i8, + pub pw_passwd: *mut i8, + pub pw_uid: u32, + pub pw_gid: u32, + #[cfg(target_os = "macos")] + pub pw_change: i64, + #[cfg(target_os = "macos")] + pub pw_class: *mut i8, + pub pw_gecos: *mut i8, + pub pw_dir: *mut i8, + pub pw_shell: *mut i8, + #[cfg(target_os = "macos")] + pub pw_expire: i64, + } +} + +fn env_shell() -> &'static str { + ENV_SHELL.get_or_init(|| unsafe { + let uid = libc::getuid(); + let pw = libc::getpwuid(uid); + assert!(!pw.is_null()); + ffi::CStr::from_ptr((*pw).pw_shell) + .to_string_lossy() + .into_owned() + }) } fn ns() -> path::PathBuf {