diff --git a/bin/main.ml b/bin/main.ml index c016d04..35adfb5 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -7,34 +7,34 @@ let main Cli.strategy) = let ({ entrypoint; attribute; subshell_dir } : Cli.target_info) = target_info in - Option.value ~default:(Option.value ~default:(Sys.getcwd ()) entrypoint) subshell_dir - |> Unix.cd; - let cmd = - match entrypoint with - | Some entrypoint -> - (match Unix.flake_exists_at entrypoint with - | true -> - Cmd.builder "nix" - |>+ [ "develop" ] @ [ Uri.sprintf_uri_attr_opt entrypoint attribute ] - |>+ Option.value ~default:[] force_experimental_features - | false -> - (match Unix.shell_exists_at entrypoint with - | true -> - Cmd.builder "nix-shell" - |>+ Option.value - ~default:[] - (Option.map (fun attr -> [ "--attr"; attr ]) attribute) - |>+ [ entrypoint ] - | false -> - Error.handle_ns_error "no available devshell entrypoint: %s\n%!" entrypoint)) - |>+ [ "--command"; Unix.shell ] - | None -> - Cmd.builder "nix" - |>+ [ "shell" ] - |>+ installables - |>+ Option.value ~default:[] force_experimental_features + let strategy = + let workdir = + Option.value + ~default:(Option.value ~default:(Sys.getcwd ()) entrypoint) + subshell_dir + and primary, fallback = + match entrypoint with + | Some entrypoint -> + if Unix.flake_exists_at entrypoint + then + ( Cmd.nix_develop entrypoint attribute force_experimental_features + , if Unix.shell_exists_at entrypoint + then Some (Cmd.legacy_nix_shell_from_entrypoint entrypoint attribute) + else None ) + else if Unix.shell_exists_at entrypoint + then Cmd.legacy_nix_shell_from_entrypoint entrypoint attribute, None + else Error.handle_ns_error "no available devshell entrypoint: %s\n%!" entrypoint + | None -> + ( Cmd.nix_shell + (List.map Uri.uri_to_string installables) + force_experimental_features + , Option.map + (fun installables -> Cmd.legacy_nix_shell_from_installables installables) + (Uri.combine_installables_tr installables) ) + in + { workdir; primary; fallback } in - if printcmd then print_endline (Cmd.to_string cmd) else ignore (Cmd.run cmd) + if printcmd then print_strategy strategy else execute_strategy strategy ;; Cli.eval main diff --git a/lib/cli.ml b/lib/cli.ml index 116dea6..703b8c6 100644 --- a/lib/cli.ml +++ b/lib/cli.ml @@ -15,7 +15,7 @@ module Cli = struct (** Processed args that will be consumed by the main function to determine the behavior of the program. *) type strategy = - { installables : string list + { installables : Uri.uri list ; target_info : target_info ; printcmd : bool ; force_experimental_features : string list option @@ -25,7 +25,12 @@ module Cli = struct let uris = Arg.(value & pos_all dirpath [] & info []) let printcmd = - let doc = "Print the command to stdout instead of executing it." in + let doc = + "Print the command strategy as newline separated values to stdout instead of \ + executing it. The first command changes to the working directory, the second is \ + the primary nix command and the last is an optional fallback nix command in the \ + event that flake/nix-command features fail." + in Arg.(value & flag & info [ "printcmd" ] ~doc) ;; @@ -64,7 +69,9 @@ module Cli = struct (* Two args passed *) (*******************) | [ maybe_subshell_dir; target ] -> - (match Uri.parse_target maybe_subshell_dir, Uri.parse_target target with + let maybe_subshell_dir = Uri.parse_target maybe_subshell_dir + and target = Uri.parse_target target in + (match maybe_subshell_dir, target with (* If maybe_subshell_dir does not have any attributes we know the user wants to change directories. *) | ( LocalResourceMaybeAttr (subshell_dir, None) , LocalResourceMaybeAttr (entrypoint, attribute) ) -> @@ -73,12 +80,10 @@ module Cli = struct ; attribute ; subshell_dir = Some subshell_dir } ) - | LocalResourceMaybeAttr (subshell_dir, None), LocalResourceMultiAttr _ -> + | ( LocalResourceMaybeAttr (subshell_dir, None) + , (LocalResourceMultiAttr _ | RemoteResource _) ) -> ( [ target ] , { entrypoint = None; attribute = None; subshell_dir = Some subshell_dir } ) - | LocalResourceMaybeAttr (subshell_dir, None), RemoteResource uri -> - ( [ uri ] - , { entrypoint = None; attribute = None; subshell_dir = Some subshell_dir } ) | _ -> Uri.parse_targets_tr original_args, default_target) (*****************************) (* Three or more args passed *) diff --git a/lib/cmd.ml b/lib/cmd.ml index 828847c..a8b3e7c 100644 --- a/lib/cmd.ml +++ b/lib/cmd.ml @@ -1,28 +1,85 @@ (** Functions and operators used in running commands *) module Cmd = struct - open Bos + open Util.Util - (** Construct a command builder - - Example: - Cmd.builder "nix" |>+ \[ "flake" "show" "--json" \] - *) - let builder cmd = Cmd.v cmd + type strategy = + { workdir : string + ; primary : Bos.Cmd.t + ; fallback : Bos.Cmd.t option + } (** Pipe-arg operator, used in adding arguments to a command *) let ( |>+ ) cmd = function | [] -> cmd - | [ arg ] -> Cmd.add_arg cmd arg - | args -> List.fold_left (fun cmd arg -> Cmd.add_arg cmd arg) cmd args + | [ arg ] -> Bos.Cmd.add_arg cmd arg + | args -> List.fold_left (fun cmd arg -> Bos.Cmd.add_arg cmd arg) cmd args + ;; + + let nix_develop entrypoint attribute force_experimental_features = + Bos.Cmd.v "nix" + |>+ [ "develop" ] @ [ Uri.sprintf_uri_attr_opt entrypoint attribute ] + |>+ Option.value ~default:[] force_experimental_features + |>+ [ "--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 ] ;; - (** Convert a command into a string *) - let to_string cmd = Cmd.to_string cmd + let nix_shell installables force_experimental_features = + Bos.Cmd.v "nix" + |>+ [ "shell" ] + |>+ installables + |>+ Option.value ~default:[] force_experimental_features + ;; - (** Run a command + let legacy_nix_shell_from_installables installables = + (* Need to combine/validate that the installables given are all Nixpkgs *) + Bos.Cmd.v "nix-shell" + |>+ [ "--packages" ] @ installables + |>+ [ "--command"; Unix.shell ] + ;; - Example: - Cmd.run (Cmd.builder "nix" |>+ \[ "show-config" "--json" \]) - *) - let run cmd = OS.Cmd.run cmd + let print_strategy ({ workdir; primary; fallback } : strategy) = + print_string + (Printf.sprintf + "'cd' '%s'\n%s\n%s" + workdir + (Bos.Cmd.to_string primary) + (Option.value ~default:"" (Option.map Bos.Cmd.to_string fallback))) + ;; + + let execute_strategy ({ workdir; primary; fallback } : strategy) = + Unix.cd workdir; + match Bos.OS.Cmd.run_status primary with + | Ok (`Exited 0) -> () (* success, nothing else to do *) + | Ok (`Exited code | `Signaled code) -> + (* primary failed *) + (match fallback with + | Some fallback -> + (* show primary error but don't exit *) + Printf.eprintf "primary command failed (exit %d), trying fallback\n%!" code; + (match Bos.OS.Cmd.run_status fallback with + | Ok (`Exited 0) -> () + | Ok (`Exited code | `Signaled code) -> exit code + | Error (`Msg msg) -> + prerr_endline msg; + exit 1) + | None -> exit code) + | Error (`Msg msg) -> + (* primary couldn't even be spawned *) + prerr_endline msg; + (match fallback with + | Some fallback -> + (match Bos.OS.Cmd.run_status fallback with + | Ok (`Exited 0) -> () + | Ok (`Exited code | `Signaled code) -> exit code + | Error (`Msg msg) -> + prerr_endline msg; + exit 1) + | None -> exit 1) + ;; end diff --git a/lib/util.ml b/lib/util.ml index e466eca..a5b02a2 100644 --- a/lib/util.ml +++ b/lib/util.ml @@ -40,6 +40,12 @@ module Util = struct module Uri = struct (* *) + (** A local reference to nixpkgs, eg. {nixpkgs#...} or {pkgs#...} (which resolves to the former) *) + type nixpkgs = + { uri : string + ; installables : string list + } + (** URI variants, like {/path/to/flake#drv} or {github:NixOS/nixpkgs#drv} *) type uri = (* A path with up to one attribute, eg. /path/to/resouce or /path/to/resource#... *) @@ -48,6 +54,8 @@ module Util = struct | LocalResourceMultiAttr of string * string (* A remote resource, eg. github:NixOS/nixpkgs *) | RemoteResource of string + (* A local reference to nixpkgs, eg. nixpkgs#... or pkgs#... (which resolves to the former) *) + | Nixpkgs of nixpkgs (** Format a uri and attribute into a string *) let sprintf_uri_attr path attr = Printf.sprintf "%s#%s" path attr @@ -65,17 +73,38 @@ module Util = struct | LocalResourceMaybeAttr (path, attr_opt) -> sprintf_uri_attr_opt path attr_opt | LocalResourceMultiAttr (path, attr) -> sprintf_uri_attr path attr | RemoteResource uri -> uri + | Nixpkgs { uri; _ } -> uri ;; (** Parse target argument for optional attribute selection *) let parse_target target = let parse_uri uri attr_opt = + let is_multiattr maybe_multiattr = + String.starts_with ~prefix:"{" maybe_multiattr + && String.ends_with ~suffix:"}" maybe_multiattr + in match String.split_on_char ':' uri with - | [ path ] -> - let path = Unix.realpath path - and is_multiattr maybe_multiattr = - String.starts_with ~prefix:"{" maybe_multiattr + | [ "nixpkgs" ] | [ "pkgs" ] -> + let parse_installables attr_opt = + match attr_opt with + | Some attr -> + if is_multiattr attr + then ( + match String.split_on_char '{' attr with + | [ _; rhs ] -> + (match String.split_on_char '}' rhs with + | [ lhs; _ ] -> String.split_on_char ',' lhs + | _ -> []) + | _ -> []) + else [ attr ] + | None -> [] in + Nixpkgs + { uri = sprintf_uri_attr_opt "nixpkgs" attr_opt + ; installables = parse_installables attr_opt + } + | [ path ] -> + let path = Unix.realpath path in (match attr_opt with | Some attr -> if is_multiattr attr @@ -91,15 +120,24 @@ module Util = struct Error.handle_ns_error "invalid uri or attribute selection syntax: %s\n%!" target ;; - (** Parse target arguments recursively, returning a list of strings. + (** Parse target arguments recursively, returning a list of {!type:uri}. This function is tail recursive optimized. *) let parse_targets_tr targets = let rec parse_targets acc = function | [] -> acc - | target :: remaining -> - parse_targets (uri_to_string (parse_target target) :: acc) remaining + | target :: remaining -> parse_targets (parse_target target :: acc) remaining in parse_targets [] targets ;; + + let combine_installables_tr installables = + let rec combine_installables acc = function + | [] -> Some acc + | Nixpkgs { installables; _ } :: remaining -> + combine_installables (acc @ installables) remaining + | _ -> None + in + combine_installables [] installables + ;; end end diff --git a/test/dune b/test/dune index 979cd4b..3acffcd 100644 --- a/test/dune +++ b/test/dune @@ -2,7 +2,12 @@ (test (name test_ns) - (deps test_ns src/flake/flake.nix src/shell/shell.nix) + (deps + test_ns + src/flake/flake.nix + src/shell/shell.nix + src/flake_shell/flake.nix + src/flake_shell/shell.nix) (flags (:standard))) ;; Rule to compile the Rust test file into a binary diff --git a/test/src/flake_shell/flake.nix b/test/src/flake_shell/flake.nix new file mode 100644 index 0000000..2550caa --- /dev/null +++ b/test/src/flake_shell/flake.nix @@ -0,0 +1,12 @@ +{ + inputs.nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + outputs = { self, nixpkgs }: + let + inherit (nixpkgs.lib) genAttrs; + inherit (nixpkgs.lib.systems) flakeExposed; + eachSystem = f: genAttrs flakeExposed (system: f (import nixpkgs { inherit system; })); + in + { + packages = eachSystem (pkgs: { default = pkgs.hello; }); + }; +} diff --git a/test/src/flake_shell/shell.nix b/test/src/flake_shell/shell.nix new file mode 100644 index 0000000..e586841 --- /dev/null +++ b/test/src/flake_shell/shell.nix @@ -0,0 +1,6 @@ +{ pkgs ? import { } }: +pkgs.mkShell { + buildInputs = builtins.attrValues { + inherit (pkgs) hello; + }; +} diff --git a/test/test_ns.rs b/test/test_ns.rs index d4f8ff1..edaa50b 100644 --- a/test/test_ns.rs +++ b/test/test_ns.rs @@ -23,20 +23,32 @@ fn flake_dir() -> path::PathBuf { .join("src") .join("flake") .canonicalize() - .expect("failed to canonicalize path to ns binary") + .expect("failed to canonicalize path to flake") } fn shell_dir() -> path::PathBuf { dune_test_dir() .join("src") .join("shell") .canonicalize() - .expect("failed to canonicalize path to ns binary") + .expect("failed to canonicalize path to shell") +} +fn flake_shell_dir() -> path::PathBuf { + dune_test_dir() + .join("src") + .join("flake_shell") + .canonicalize() + .expect("failed to canonicalize path to flake_shell") } -fn assert_stdout_eq(stdout: &[u8], expected: &[&str]) { +fn assert_stdout_eq(stdout: &[u8], expected: &[&[&str]]) { let stdout = String::from_utf8_lossy(stdout); - let stdout = stdout.replace('\'', ""); - let stdout: Vec<&str> = stdout.split_whitespace().collect(); + let stdout: Vec> = stdout + .split('\n') + .map(|cmd| { + let cmd = cmd.replace('\'', ""); + cmd.split_whitespace().map(|cmd| cmd.to_string()).collect() + }) + .collect(); if expected != stdout.as_slice() { panic!( @@ -61,11 +73,15 @@ mod nix_develop_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "develop", - &flake_dir().to_string_lossy(), - "--command", - env_shell(), + &["cd", &flake_dir().to_string_lossy()], + &[ + "nix", + "develop", + &flake_dir().to_string_lossy(), + "--command", + env_shell(), + ], + &[], ], ); } @@ -85,15 +101,19 @@ mod nix_develop_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "develop", - &flake_dir().to_string_lossy(), - "--extra-experimental-features", - "flakes", - "--extra-experimental-features", - "nix-command", - "--command", - env_shell(), + &["cd", &flake_dir().to_string_lossy()], + &[ + "nix", + "develop", + &flake_dir().to_string_lossy(), + "--extra-experimental-features", + "flakes", + "--extra-experimental-features", + "nix-command", + "--command", + env_shell(), + ], + &[], ], ); } @@ -109,7 +129,11 @@ mod nix_develop_tests { assert!(output.status.success()); assert_stdout_eq( &output.stdout, - &["nix", "develop", &flake_uri, "--command", env_shell()], + &[ + &["cd", &flake_dir().to_string_lossy()], + &["nix", "develop", &flake_uri, "--command", env_shell()], + &[], + ], ); } @@ -125,15 +149,19 @@ mod nix_develop_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "develop", - &flake_uri, - "--extra-experimental-features", - "flakes", - "--extra-experimental-features", - "nix-command", - "--command", - env_shell(), + &["cd", &flake_dir().to_string_lossy()], + &[ + "nix", + "develop", + &flake_uri, + "--extra-experimental-features", + "flakes", + "--extra-experimental-features", + "nix-command", + "--command", + env_shell(), + ], + &[], ], ); } @@ -149,11 +177,15 @@ mod nix_develop_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "develop", - &flake_dir().to_string_lossy(), - "--command", - env_shell(), + &["cd", &dune_test_dir().to_string_lossy()], + &[ + "nix", + "develop", + &flake_dir().to_string_lossy(), + "--command", + env_shell(), + ], + &[], ], ); } @@ -174,15 +206,19 @@ mod nix_develop_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "develop", - &flake_dir().to_string_lossy(), - "--extra-experimental-features", - "flakes", - "--extra-experimental-features", - "nix-command", - "--command", - env_shell(), + &["cd", &dune_test_dir().to_string_lossy()], + &[ + "nix", + "develop", + &flake_dir().to_string_lossy(), + "--extra-experimental-features", + "flakes", + "--extra-experimental-features", + "nix-command", + "--command", + env_shell(), + ], + &[], ], ); } @@ -198,7 +234,11 @@ mod nix_develop_tests { assert!(output.status.success()); assert_stdout_eq( &output.stdout, - &["nix", "develop", &flake_uri, "--command", env_shell()], + &[ + &["cd", &dune_test_dir().to_string_lossy()], + &["nix", "develop", &flake_uri, "--command", env_shell()], + &[], + ], ); } @@ -214,15 +254,48 @@ mod nix_develop_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "develop", - &flake_uri, - "--extra-experimental-features", - "flakes", - "--extra-experimental-features", - "nix-command", - "--command", - env_shell(), + &["cd", &dune_test_dir().to_string_lossy()], + &[ + "nix", + "develop", + &flake_uri, + "--extra-experimental-features", + "flakes", + "--extra-experimental-features", + "nix-command", + "--command", + env_shell(), + ], + &[], + ], + ); + } + + #[test] + fn flake_and_shell_fallback() { + let output = process::Command::new(ns()) + .args([flake_shell_dir().as_os_str(), "--printcmd".as_ref()]) + .output() + .expect("failed to get command output"); + + assert!(output.status.success()); + assert_stdout_eq( + &output.stdout, + &[ + &["cd", &flake_shell_dir().to_string_lossy()], + &[ + "nix", + "develop", + &flake_shell_dir().to_string_lossy(), + "--command", + env_shell(), + ], + &[ + "nix-shell", + &flake_shell_dir().to_string_lossy(), + "--command", + env_shell(), + ], ], ); } @@ -242,10 +315,14 @@ mod legacy_nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix-shell", - &shell_dir().to_string_lossy(), - "--command", - env_shell(), + &["cd", &shell_dir().to_string_lossy()], + &[ + "nix-shell", + &shell_dir().to_string_lossy(), + "--command", + env_shell(), + ], + &[], ], ); } @@ -265,10 +342,14 @@ mod legacy_nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix-shell", - &shell_dir().to_string_lossy(), - "--command", - env_shell(), + &["cd", &shell_dir().to_string_lossy()], + &[ + "nix-shell", + &shell_dir().to_string_lossy(), + "--command", + env_shell(), + ], + &[], ], ); } @@ -285,12 +366,16 @@ mod legacy_nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix-shell", - "--attr", - "default", - &shell_dir().to_string_lossy(), - "--command", - env_shell(), + &["cd", &shell_dir().to_string_lossy()], + &[ + "nix-shell", + "--attr", + "default", + &shell_dir().to_string_lossy(), + "--command", + env_shell(), + ], + &[], ], ); } @@ -307,12 +392,16 @@ mod legacy_nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix-shell", - "--attr", - "default", - &shell_dir().to_string_lossy(), - "--command", - env_shell(), + &["cd", &shell_dir().to_string_lossy()], + &[ + "nix-shell", + "--attr", + "default", + &shell_dir().to_string_lossy(), + "--command", + env_shell(), + ], + &[], ], ); } @@ -330,7 +419,14 @@ mod nix_shell_tests { .expect("failed to get command output"); assert!(output.status.success()); - assert_stdout_eq(&output.stdout, &["nix", "shell", &flake_uri]); + assert_stdout_eq( + &output.stdout, + &[ + &["cd", &dune_test_dir().to_string_lossy()], + &["nix", "shell", &flake_uri], + &[], + ], + ); } #[test] @@ -345,13 +441,17 @@ mod nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "shell", - &flake_uri, - "--extra-experimental-features", - "flakes", - "--extra-experimental-features", - "nix-command", + &["cd", &dune_test_dir().to_string_lossy()], + &[ + "nix", + "shell", + &flake_uri, + "--extra-experimental-features", + "flakes", + "--extra-experimental-features", + "nix-command", + ], + &[], ], ); } @@ -371,7 +471,11 @@ mod nix_shell_tests { assert!(output.status.success()); assert_stdout_eq( &output.stdout, - &["nix", "shell", &flake_uri, &flake_dir().to_string_lossy()], + &[ + &["cd", &dune_test_dir().to_string_lossy()], + &["nix", "shell", &flake_uri, &flake_dir().to_string_lossy()], + &[], + ], ); } @@ -392,14 +496,18 @@ mod nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "shell", - &flake_uri, - &flake_dir().to_string_lossy(), - "--extra-experimental-features", - "flakes", - "--extra-experimental-features", - "nix-command", + &["cd", &dune_test_dir().to_string_lossy()], + &[ + "nix", + "shell", + &flake_uri, + &flake_dir().to_string_lossy(), + "--extra-experimental-features", + "flakes", + "--extra-experimental-features", + "nix-command", + ], + &[], ], ); } @@ -413,7 +521,14 @@ mod nix_shell_tests { .expect("failed to get command output"); assert!(output.status.success()); - assert_stdout_eq(&output.stdout, &["nix", "shell", &flake_uri, &flake_uri]); + assert_stdout_eq( + &output.stdout, + &[ + &["cd", &dune_test_dir().to_string_lossy()], + &["nix", "shell", &flake_uri, &flake_uri], + &[], + ], + ); } #[test] @@ -428,14 +543,18 @@ mod nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "shell", - &flake_uri, - &flake_uri, - "--extra-experimental-features", - "flakes", - "--extra-experimental-features", - "nix-command", + &["cd", &dune_test_dir().to_string_lossy()], + &[ + "nix", + "shell", + &flake_uri, + &flake_uri, + "--extra-experimental-features", + "flakes", + "--extra-experimental-features", + "nix-command", + ], + &[], ], ); } @@ -449,7 +568,14 @@ mod nix_shell_tests { .expect("failed to get command output"); assert!(output.status.success()); - assert_stdout_eq(&output.stdout, &["nix", "shell", &flake_uri]); + assert_stdout_eq( + &output.stdout, + &[ + &["cd", &dune_test_dir().to_string_lossy()], + &["nix", "shell", &flake_uri], + &[], + ], + ); } #[test] @@ -464,13 +590,17 @@ mod nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "shell", - &flake_uri, - "--extra-experimental-features", - "flakes", - "--extra-experimental-features", - "nix-command", + &["cd", &dune_test_dir().to_string_lossy()], + &[ + "nix", + "shell", + &flake_uri, + "--extra-experimental-features", + "flakes", + "--extra-experimental-features", + "nix-command", + ], + &[], ], ); } @@ -490,7 +620,11 @@ mod nix_shell_tests { assert!(output.status.success()); assert_stdout_eq( &output.stdout, - &["nix", "shell", &flake_uri, &flake_dir().to_string_lossy()], + &[ + &["cd", &dune_test_dir().to_string_lossy()], + &["nix", "shell", &flake_uri, &flake_dir().to_string_lossy()], + &[], + ], ); } @@ -511,14 +645,18 @@ mod nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "shell", - &flake_uri, - &flake_dir().to_string_lossy(), - "--extra-experimental-features", - "flakes", - "--extra-experimental-features", - "nix-command", + &["cd", &dune_test_dir().to_string_lossy()], + &[ + "nix", + "shell", + &flake_uri, + &flake_dir().to_string_lossy(), + "--extra-experimental-features", + "flakes", + "--extra-experimental-features", + "nix-command", + ], + &[], ], ); } @@ -532,7 +670,14 @@ mod nix_shell_tests { .expect("failed to get command output"); assert!(output.status.success()); - assert_stdout_eq(&output.stdout, &["nix", "shell", &flake_uri, &flake_uri]); + assert_stdout_eq( + &output.stdout, + &[ + &["cd", &dune_test_dir().to_string_lossy()], + &["nix", "shell", &flake_uri, &flake_uri], + &[], + ], + ); } #[test] @@ -547,14 +692,18 @@ mod nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "shell", - &flake_uri, - &flake_uri, - "--extra-experimental-features", - "flakes", - "--extra-experimental-features", - "nix-command", + &["cd", &dune_test_dir().to_string_lossy()], + &[ + "nix", + "shell", + &flake_uri, + &flake_uri, + "--extra-experimental-features", + "flakes", + "--extra-experimental-features", + "nix-command", + ], + &[], ], ); } @@ -569,7 +718,14 @@ mod nix_shell_tests { .expect("failed to get command output"); assert!(output.status.success()); - assert_stdout_eq(&output.stdout, &["nix", "shell", &flake_uri, remote_uri]); + assert_stdout_eq( + &output.stdout, + &[ + &["cd", &dune_test_dir().to_string_lossy()], + &["nix", "shell", &flake_uri, remote_uri], + &[], + ], + ); } #[test] @@ -585,14 +741,18 @@ mod nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "shell", - &flake_uri, - remote_uri, - "--extra-experimental-features", - "flakes", - "--extra-experimental-features", - "nix-command", + &["cd", &dune_test_dir().to_string_lossy()], + &[ + "nix", + "shell", + &flake_uri, + remote_uri, + "--extra-experimental-features", + "flakes", + "--extra-experimental-features", + "nix-command", + ], + &[], ], ); } @@ -615,11 +775,15 @@ mod nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "shell", - remote_uri, - &flake_uri, - &flake_dir().to_string_lossy(), + &["cd", &dune_test_dir().to_string_lossy()], + &[ + "nix", + "shell", + remote_uri, + &flake_uri, + &flake_dir().to_string_lossy(), + ], + &[], ], ); } @@ -643,15 +807,19 @@ mod nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "shell", - remote_uri, - &flake_uri, - &flake_dir().to_string_lossy(), - "--extra-experimental-features", - "flakes", - "--extra-experimental-features", - "nix-command", + &["cd", &dune_test_dir().to_string_lossy()], + &[ + "nix", + "shell", + remote_uri, + &flake_uri, + &flake_dir().to_string_lossy(), + "--extra-experimental-features", + "flakes", + "--extra-experimental-features", + "nix-command", + ], + &[], ], ); } @@ -668,7 +836,11 @@ mod nix_shell_tests { assert!(output.status.success()); assert_stdout_eq( &output.stdout, - &["nix", "shell", remote_uri, &flake_uri, &flake_uri], + &[ + &["cd", &dune_test_dir().to_string_lossy()], + &["nix", "shell", remote_uri, &flake_uri, &flake_uri], + &[], + ], ); } @@ -685,15 +857,19 @@ mod nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "shell", - remote_uri, - &flake_uri, - &flake_uri, - "--extra-experimental-features", - "flakes", - "--extra-experimental-features", - "nix-command", + &["cd", &dune_test_dir().to_string_lossy()], + &[ + "nix", + "shell", + remote_uri, + &flake_uri, + &flake_uri, + "--extra-experimental-features", + "flakes", + "--extra-experimental-features", + "nix-command", + ], + &[], ], ); } @@ -708,7 +884,14 @@ mod nix_shell_tests { .expect("failed to get command output"); assert!(output.status.success()); - assert_stdout_eq(&output.stdout, &["nix", "shell", &flake_uri, remote_uri]); + assert_stdout_eq( + &output.stdout, + &[ + &["cd", &dune_test_dir().to_string_lossy()], + &["nix", "shell", &flake_uri, remote_uri], + &[], + ], + ); } #[test] @@ -724,14 +907,18 @@ mod nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "shell", - &flake_uri, - remote_uri, - "--extra-experimental-features", - "flakes", - "--extra-experimental-features", - "nix-command", + &["cd", &dune_test_dir().to_string_lossy()], + &[ + "nix", + "shell", + &flake_uri, + remote_uri, + "--extra-experimental-features", + "flakes", + "--extra-experimental-features", + "nix-command", + ], + &[], ], ); } @@ -754,11 +941,15 @@ mod nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "shell", - remote_uri, - &flake_uri, - &flake_dir().to_string_lossy(), + &["cd", &dune_test_dir().to_string_lossy()], + &[ + "nix", + "shell", + remote_uri, + &flake_uri, + &flake_dir().to_string_lossy(), + ], + &[], ], ); } @@ -782,15 +973,19 @@ mod nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "shell", - remote_uri, - &flake_uri, - &flake_dir().to_string_lossy(), - "--extra-experimental-features", - "flakes", - "--extra-experimental-features", - "nix-command", + &["cd", &dune_test_dir().to_string_lossy()], + &[ + "nix", + "shell", + remote_uri, + &flake_uri, + &flake_dir().to_string_lossy(), + "--extra-experimental-features", + "flakes", + "--extra-experimental-features", + "nix-command", + ], + &[], ], ); } @@ -807,7 +1002,11 @@ mod nix_shell_tests { assert!(output.status.success()); assert_stdout_eq( &output.stdout, - &["nix", "shell", remote_uri, &flake_uri, &flake_uri], + &[ + &["cd", &dune_test_dir().to_string_lossy()], + &["nix", "shell", remote_uri, &flake_uri, &flake_uri], + &[], + ], ); } @@ -824,15 +1023,65 @@ mod nix_shell_tests { assert_stdout_eq( &output.stdout, &[ - "nix", - "shell", - remote_uri, - &flake_uri, - &flake_uri, - "--extra-experimental-features", - "flakes", - "--extra-experimental-features", - "nix-command", + &["cd", &dune_test_dir().to_string_lossy()], + &[ + "nix", + "shell", + remote_uri, + &flake_uri, + &flake_uri, + "--extra-experimental-features", + "flakes", + "--extra-experimental-features", + "nix-command", + ], + &[], + ], + ); + } + + #[test] + fn nixpkgs_single_attr() { + let nixpkgs = "nixpkgs#hello"; + let output = process::Command::new(ns()) + .args([nixpkgs, "--printcmd"]) + .output() + .expect("failed to get command output"); + + assert!(output.status.success()); + assert_stdout_eq( + &output.stdout, + &[ + &["cd", &dune_test_dir().to_string_lossy()], + &["nix", "shell", nixpkgs], + &["nix-shell", "--packages", "hello", "--command", env_shell()], + ], + ); + } + + #[test] + fn nixpkgs_multi_attr() { + let nixpkgs = "nixpkgs#{hello,cowsay,pipes-rs}"; + let output = process::Command::new(ns()) + .args([nixpkgs, "--printcmd"]) + .output() + .expect("failed to get command output"); + + assert!(output.status.success()); + assert_stdout_eq( + &output.stdout, + &[ + &["cd", &dune_test_dir().to_string_lossy()], + &["nix", "shell", nixpkgs], + &[ + "nix-shell", + "--packages", + "hello", + "cowsay", + "pipes-rs", + "--command", + env_shell(), + ], ], ); }