From c9dcd2f770c4571ef84c3fb9e420bf5db69f7905 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Wed, 21 Feb 2024 21:19:04 +0100 Subject: [PATCH] Add the --shell flag --- README.md | 2 ++ src/cli.rs | 14 +++++++++++++- src/cli/flags.rs | 1 + src/cli/parser.rs | 5 +++++ src/config.rs | 13 +++++++++---- src/server.rs | 2 +- tests/args.rs | 5 +++++ tests/common/mod.rs | 26 ++++++++++++++++++++++++++ 8 files changed, 62 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7f5e73a..e7fc95f 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,8 @@ cargo fixture -x sh This will ready the fixture and then enter a shell, in which you can inspect whether the fixture environment is prepared correctly, interact with it, or even run `cargo test` and interact with the environment post-tests. +Alternatively, the shorthand `cargo fixture --shell` can be used, which is equivalent to `cargo fixture -x "$SHELL"`. + ### Platform support Async runtime: [Tokio](https://tokio.rs/), [smol](https://docs.rs/smol). diff --git a/src/cli.rs b/src/cli.rs index 347e790..a6fb86b 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,6 +1,6 @@ use std::{env, ffi::OsString, process}; -use anyhow::Result; +use anyhow::{bail, Result}; use crate::logger::LogLevel; @@ -15,6 +15,7 @@ def_flags!( --fixture [name] parse_value(fixture_name) r#"Name of the fixture setup test (default: "fixture")"#, -A --arg [arg] append_value_raw(fixture_args) "Pass an argument to the fixture test binary (can be used multiple times)", -x --exec [args...] take_remaining(exec) "Instead of running cargo test [args...], run the specified command and pass it all remaining arguments", + --shell set_flag(shell) "Instead of running cargo test, run $SHELL", -L [level] parse_value(log_level) "Stderr logging level (choices: off, info, debug, trace, default: info)", -h --help help "Print help", --version version "Print version", @@ -55,6 +56,7 @@ pub struct Cli { pub fixture_name: String, pub fixture_args: Vec, pub exec: Vec, + pub shell: bool, pub log_level: LogLevel, pub cargo_common_all: Vec, pub cargo_common_test: Vec, @@ -63,6 +65,14 @@ pub struct Cli { } impl Cli { + pub fn check_conflicts(self) -> Result { + if self.shell && !self.exec.is_empty() { + bail!("--shell and -x/--exec cannot be used at the same time"); + } + + Ok(self) + } + fn unknown_flag(&mut self, flag: OsString) { self.cargo_test_args.push(flag); } @@ -74,6 +84,7 @@ impl Default for Cli { fixture_name: "fixture".to_string(), fixture_args: vec![], exec: vec![], + shell: false, log_level: LogLevel::default(), cargo_common_all: vec![], cargo_common_test: vec![], @@ -86,6 +97,7 @@ impl Default for Cli { pub fn parse() -> Result { Parser::new(FLAGS, CARGO_FLAGS, env::args_os()) .parse() + .and_then(|cli| cli.check_conflicts().map_err(parser::Error::Parsing)) .map_err(|err| { let usage = Parser::usage(); if err.severity() == 0 { diff --git a/src/cli/flags.rs b/src/cli/flags.rs index 0063595..5556ecb 100644 --- a/src/cli/flags.rs +++ b/src/cli/flags.rs @@ -91,6 +91,7 @@ macro_rules! def_flags { }; // Actions + (@action set_flag($field:ident)) => { &|parser| { parser.set_flag(|cli| { &mut cli.$field }) } }; (@action parse_value($field:ident)) => { &|parser| { parser.parse_value(|cli| { &mut cli.$field }) } }; (@action append_value_raw($field:ident)) => { &|parser| { parser.append_value_raw(|cli| { &mut cli.$field }) } }; (@action forward($field:ident)) => { &|parser| { parser.forward(|cli| { &mut cli.$field }) } }; diff --git a/src/cli/parser.rs b/src/cli/parser.rs index b6300e9..300d00b 100644 --- a/src/cli/parser.rs +++ b/src/cli/parser.rs @@ -341,6 +341,11 @@ impl Parser { // flag parse fns + pub fn set_flag(&mut self, field: impl Fn(&mut Cli) -> &mut bool) -> ParseResult<()> { + *field(&mut self.cli) = true; + Ok(()) + } + pub fn parse_value(&mut self, field: impl Fn(&mut Cli) -> &mut T) -> ParseResult<()> where T: FromStr, diff --git a/src/config.rs b/src/config.rs index 04ed33b..297deec 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,7 +7,7 @@ use std::{ mod cargo_meta; -use anyhow::Result; +use anyhow::{anyhow, Result}; use log::debug; use self::cargo_meta::CargoMetadata; @@ -80,8 +80,13 @@ impl Config { extra_test_args: Vec, extra_harness_args: Vec, replace_exec: Vec, - ) -> Command { - let mut cmd = if let Some(exec) = self.cli.exec.first() { + ) -> Result { + let mut cmd = if self.cli.shell { + let sh = env::var_os("SHELL").ok_or_else(|| { + anyhow!("The environment variable $SHELL is not set, needed by --shell") + })?; + Command::new(sh) + } else if let Some(exec) = self.cli.exec.first() { let mut cmd = Command::new(exec); cmd.args(&self.cli.exec[1..]); cmd @@ -106,6 +111,6 @@ impl Config { cmd.env("CARGO_FIXTURE_SOCKET", &self.socket_path); - cmd + Ok(cmd) } } diff --git a/src/server.rs b/src/server.rs index 62c10cc..9d032b4 100644 --- a/src/server.rs +++ b/src/server.rs @@ -187,7 +187,7 @@ impl FixtureConnection { let replace_exec = mem::take(&mut self.replace_exec); let test_cmd = self .config - .test_cmd(extra_test_args, extra_harness_args, replace_exec); + .test_cmd(extra_test_args, extra_harness_args, replace_exec)?; info!("running {}", test_cmd.display()); let status = test_cmd .into_smol(Stdio::inherit(), Stdio::inherit(), Stdio::inherit()) diff --git a/tests/args.rs b/tests/args.rs index ff0808a..f103beb 100644 --- a/tests/args.rs +++ b/tests/args.rs @@ -160,3 +160,8 @@ fn args() { &["exec-cli-arg1", "exec-cli-arg2"], ); } + +#[test] +fn shell() { + cargo_fixture().run_assert_shell(); +} diff --git a/tests/common/mod.rs b/tests/common/mod.rs index b08a222..8bf1737 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -161,6 +161,32 @@ impl CargoFixture { ); } + pub fn run_assert_shell(mut self) { + let print_args_exe = self.print_args_exe(); + + let report = self + .cmd + .args([ + "-L", + "debug", + "--fixture", + "fixture_args", + "-A", + "report", + "--shell", + ]) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .env("SHELL", &print_args_exe) + .output() + .unwrap() + .parse_args_report(); + + assert!(report.fixture_args.is_empty(), "{report:?}"); + assert_eq!(report.test_args, &[print_args_exe.as_str()], "{report:?}"); + } + pub fn print_args_exe(&mut self) -> String { self.print_args_exe .get_or_insert_with(|| {