diff --git a/src/cli.rs b/src/cli.rs index f8f9e1c..dbafe30 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -284,6 +284,14 @@ pub struct CommonOpts { #[clap(long)] pub kill_process_tree: bool, + /// Abort shawl if ctrl-C or ctrl-Break is received unexpectedly. + /// Use this when running shawl directly from a terminal so that Ctrl+C stops it. + /// Or if you expect shawl to handle those ctrl c. + /// Using this as a service means that, when the service or the child receive ctrl c, + /// it may throw an STACK_BUFFER_OVERRUN error to windows + #[clap(long)] + pub interactive: bool, + /// Command to run as a service #[clap(required(true), last(true))] pub command: Vec, @@ -974,6 +982,23 @@ speculate::speculate! { ); } + it "accepts --interactive" { + check_args( + &["shawl", "run", "--interactive", "--", "foo"], + Cli { + sub: Subcommand::Run { + name: s("Shawl"), + cwd: None, + common: CommonOpts { + interactive: true, + command: vec![s("foo")], + ..Default::default() + } + } + }, + ); + } + it "accepts --env" { check_args( &["shawl", "add", "--env", "FOO=bar", "--name", "foo", "--", "foo"], diff --git a/src/control.rs b/src/control.rs index 2255f15..445d62a 100644 --- a/src/control.rs +++ b/src/control.rs @@ -144,6 +144,9 @@ fn construct_shawl_run_args(name: &str, cwd: &Option, opts: &CommonOpts) if opts.kill_process_tree { shawl_args.push("--kill-process-tree".to_string()); } + if opts.interactive { + shawl_args.push("--interactive".to_string()); + } shawl_args } @@ -600,6 +603,20 @@ speculate::speculate! { vec!["run", "--name", "shawl", "--kill-process-tree"], ); } + + it "handles --interactive" { + assert_eq!( + construct_shawl_run_args( + &s("shawl"), + &None, + &CommonOpts { + interactive: true, + ..Default::default() + } + ), + vec!["run", "--name", "shawl", "--interactive"], + ); + } } describe "prepare_command" { diff --git a/src/service.rs b/src/service.rs index 07ed6c2..73bb1f4 100644 --- a/src/service.rs +++ b/src/service.rs @@ -88,12 +88,13 @@ pub fn run_service(start_arguments: Vec) -> windows_service: }; let pass = &opts.pass.unwrap_or_else(|| vec![0]); let stop_timeout = &opts.stop_timeout.unwrap_or(3000_u64); + let interactive = opts.interactive; let mut service_exit_code = ServiceExitCode::NO_ERROR; let ignore_ctrlc = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)); let ignore_ctrlc2 = ignore_ctrlc.clone(); ctrlc::set_handler(move || { - if !ignore_ctrlc2.load(std::sync::atomic::Ordering::SeqCst) { + if interactive && !ignore_ctrlc2.load(std::sync::atomic::Ordering::SeqCst) { std::process::abort(); } })