From 7673439537fa96ba00085cbdae29003fecf08019 Mon Sep 17 00:00:00 2001 From: prsabahrami Date: Wed, 27 Nov 2024 16:24:40 -0500 Subject: [PATCH] Added support for set -e --- Cargo.lock | 76 ++++++++++++------- crates/deno_task_shell/Cargo.toml | 4 +- crates/deno_task_shell/src/shell/command.rs | 4 +- .../src/shell/commands/args.rs | 24 ++++-- .../src/shell/commands/cp_mv.rs | 4 +- .../src/shell/commands/head.rs | 2 +- .../src/shell/commands/mkdir.rs | 4 +- .../deno_task_shell/src/shell/commands/mod.rs | 3 + .../deno_task_shell/src/shell/commands/pwd.rs | 4 +- .../deno_task_shell/src/shell/commands/rm.rs | 10 +-- .../src/shell/commands/sleep.rs | 2 +- .../src/shell/commands/xargs.rs | 5 +- crates/deno_task_shell/src/shell/execute.rs | 3 + crates/deno_task_shell/src/shell/mod.rs | 4 + crates/deno_task_shell/src/shell/types.rs | 26 ++++++- crates/shell/src/commands/mod.rs | 6 ++ crates/shell/src/commands/set.rs | 42 ++++++++++ 17 files changed, 169 insertions(+), 54 deletions(-) create mode 100644 crates/shell/src/commands/set.rs diff --git a/Cargo.lock b/Cargo.lock index 2fc05aa..e0d255f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -319,7 +319,7 @@ dependencies = [ "serde", "serde_json", "tempfile", - "thiserror", + "thiserror 2.0.3", "tokio", "tokio-util", ] @@ -444,9 +444,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -459,9 +459,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -469,15 +469,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -486,15 +486,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -503,21 +503,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -731,7 +731,7 @@ dependencies = [ "supports-unicode", "terminal_size", "textwrap", - "thiserror", + "thiserror 1.0.64", "unicode-width", ] @@ -939,7 +939,7 @@ dependencies = [ "miette", "serde", "serde_json", - "thiserror", + "thiserror 1.0.64", "ucd-trie", ] @@ -1023,9 +1023,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -1066,7 +1066,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -1315,9 +1315,9 @@ checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" [[package]] name = "syn" -version = "2.0.77" +version = "2.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" dependencies = [ "proc-macro2", "quote", @@ -1378,7 +1378,16 @@ version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.64", +] + +[[package]] +name = "thiserror" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +dependencies = [ + "thiserror-impl 2.0.3", ] [[package]] @@ -1392,6 +1401,17 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror-impl" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tokio" version = "1.40.0" diff --git a/crates/deno_task_shell/Cargo.toml b/crates/deno_task_shell/Cargo.toml index 458a4ac..36d55cb 100644 --- a/crates/deno_task_shell/Cargo.toml +++ b/crates/deno_task_shell/Cargo.toml @@ -15,14 +15,14 @@ shell = ["futures", "glob", "os_pipe", "path-dedot", "tokio", "tokio-util"] serialization = ["serde"] [dependencies] -futures = { version = "0.3.30", optional = true } +futures = { version = "0.3.31", optional = true } glob = { version = "0.3.1", optional = true } path-dedot = { version = "3.1.1", optional = true } tokio = { version = "1", features = ["fs", "io-std", "io-util", "macros", "process", "rt-multi-thread", "sync", "time"], optional = true } tokio-util = { version = "0.7.12", optional = true } os_pipe = { version = "1.2.1", optional = true } serde = { version = "1", features = ["derive"], optional = true } -thiserror = "1.0.63" +thiserror = "2.0.3" pest = { version="2.7.13", features = ["miette-error"] } pest_derive = "2.7.12" dirs = "5.0.1" diff --git a/crates/deno_task_shell/src/shell/command.rs b/crates/deno_task_shell/src/shell/command.rs index 1e62a89..4bf5f64 100644 --- a/crates/deno_task_shell/src/shell/command.rs +++ b/crates/deno_task_shell/src/shell/command.rs @@ -153,10 +153,10 @@ async fn resolve_command<'a>( } } - return Ok(ResolvedCommand { + Ok(ResolvedCommand { command_name: CommandName::Resolved(command_path), args: Cow::Borrowed(original_args), - }); + }) } async fn parse_shebang_args( diff --git a/crates/deno_task_shell/src/shell/commands/args.rs b/crates/deno_task_shell/src/shell/commands/args.rs index fff34c5..5c2a022 100644 --- a/crates/deno_task_shell/src/shell/commands/args.rs +++ b/crates/deno_task_shell/src/shell/commands/args.rs @@ -5,7 +5,8 @@ use miette::Result; #[derive(Debug, PartialEq, Eq)] pub enum ArgKind<'a> { - ShortFlag(char), + PlusShortFlag(char), + MinusShortFlag(char), LongFlag(&'a str), Arg(&'a str), } @@ -19,9 +20,12 @@ impl<'a> ArgKind<'a> { ArgKind::LongFlag(name) => { bail!("unsupported flag: --{}", name) } - ArgKind::ShortFlag(name) => { + ArgKind::MinusShortFlag(name) => { bail!("unsupported flag: -{}", name) } + ArgKind::PlusShortFlag(name) => { + bail!("unsupported flag: +{}", name) + } } } } @@ -43,7 +47,15 @@ pub fn parse_arg_kinds(flags: &[String]) -> Vec { result.push(ArgKind::Arg(arg)); } else { for c in flags.chars() { - result.push(ArgKind::ShortFlag(c)); + result.push(ArgKind::MinusShortFlag(c)); + } + } + } else if let Some(flags) = arg.strip_prefix('+') { + if flags.parse::().is_ok() { + result.push(ArgKind::Arg(arg)); + } else { + for c in flags.chars() { + result.push(ArgKind::PlusShortFlag(c)); } } } else { @@ -76,9 +88,9 @@ mod test { assert_eq!( args, vec![ - ArgKind::ShortFlag('f'), - ArgKind::ShortFlag('a'), - ArgKind::ShortFlag('b'), + ArgKind::MinusShortFlag('f'), + ArgKind::MinusShortFlag('a'), + ArgKind::MinusShortFlag('b'), ArgKind::LongFlag("force"), ArgKind::Arg("testing"), ArgKind::Arg("other"), diff --git a/crates/deno_task_shell/src/shell/commands/cp_mv.rs b/crates/deno_task_shell/src/shell/commands/cp_mv.rs index 83fff6a..2d98edd 100644 --- a/crates/deno_task_shell/src/shell/commands/cp_mv.rs +++ b/crates/deno_task_shell/src/shell/commands/cp_mv.rs @@ -150,8 +150,8 @@ fn parse_cp_args(cwd: &Path, args: Vec) -> Result { paths.push(arg); } ArgKind::LongFlag("recursive") - | ArgKind::ShortFlag('r') - | ArgKind::ShortFlag('R') => { + | ArgKind::MinusShortFlag('r') + | ArgKind::MinusShortFlag('R') => { recursive = true; } _ => arg.bail_unsupported()?, diff --git a/crates/deno_task_shell/src/shell/commands/head.rs b/crates/deno_task_shell/src/shell/commands/head.rs index c0a9344..e425b3f 100644 --- a/crates/deno_task_shell/src/shell/commands/head.rs +++ b/crates/deno_task_shell/src/shell/commands/head.rs @@ -130,7 +130,7 @@ fn parse_args(args: Vec) -> Result { // TODO: support multiple files bail!("only one file is supported for now"); } - ArgKind::ShortFlag('n') => match iterator.next() { + ArgKind::MinusShortFlag('n') => match iterator.next() { Some(ArgKind::Arg(arg)) => { lines = Some(arg.parse::().into_diagnostic()?); } diff --git a/crates/deno_task_shell/src/shell/commands/mkdir.rs b/crates/deno_task_shell/src/shell/commands/mkdir.rs index 5d8d90f..badde86 100644 --- a/crates/deno_task_shell/src/shell/commands/mkdir.rs +++ b/crates/deno_task_shell/src/shell/commands/mkdir.rs @@ -75,13 +75,13 @@ fn parse_args(args: Vec) -> Result { for arg in parse_arg_kinds(&args) { match arg { - ArgKind::LongFlag("parents") | ArgKind::ShortFlag('p') => { + ArgKind::LongFlag("parents") | ArgKind::MinusShortFlag('p') => { result.parents = true; } ArgKind::Arg(path) => { result.paths.push(path.to_string()); } - ArgKind::LongFlag(_) | ArgKind::ShortFlag(_) => arg.bail_unsupported()?, + ArgKind::LongFlag(_) | ArgKind::MinusShortFlag(_) | ArgKind::PlusShortFlag(_)=> arg.bail_unsupported()?, } } diff --git a/crates/deno_task_shell/src/shell/commands/mod.rs b/crates/deno_task_shell/src/shell/commands/mod.rs index 028392c..b9cfff8 100644 --- a/crates/deno_task_shell/src/shell/commands/mod.rs +++ b/crates/deno_task_shell/src/shell/commands/mod.rs @@ -23,6 +23,9 @@ use futures::future::LocalBoxFuture; pub use executable::ExecutableCommand; +pub use args::parse_arg_kinds; +pub use args::ArgKind; + use super::types::ExecuteResult; use super::types::FutureExecuteResult; use super::types::ShellPipeReader; diff --git a/crates/deno_task_shell/src/shell/commands/pwd.rs b/crates/deno_task_shell/src/shell/commands/pwd.rs index bb6e933..c80b79f 100644 --- a/crates/deno_task_shell/src/shell/commands/pwd.rs +++ b/crates/deno_task_shell/src/shell/commands/pwd.rs @@ -54,10 +54,10 @@ fn parse_args(args: Vec) -> Result { let mut logical = false; for arg in parse_arg_kinds(&args) { match arg { - ArgKind::ShortFlag('L') => { + ArgKind::MinusShortFlag('L') => { logical = true; } - ArgKind::ShortFlag('P') => { + ArgKind::MinusShortFlag('P') => { // ignore, this is the default } ArgKind::Arg(_) => { diff --git a/crates/deno_task_shell/src/shell/commands/rm.rs b/crates/deno_task_shell/src/shell/commands/rm.rs index 77cf9c3..e69c355 100644 --- a/crates/deno_task_shell/src/shell/commands/rm.rs +++ b/crates/deno_task_shell/src/shell/commands/rm.rs @@ -95,20 +95,20 @@ fn parse_args(args: Vec) -> Result { for arg in parse_arg_kinds(&args) { match arg { ArgKind::LongFlag("recursive") - | ArgKind::ShortFlag('r') - | ArgKind::ShortFlag('R') => { + | ArgKind::MinusShortFlag('r') + | ArgKind::MinusShortFlag('R') => { result.recursive = true; } - ArgKind::LongFlag("dir") | ArgKind::ShortFlag('d') => { + ArgKind::LongFlag("dir") | ArgKind::MinusShortFlag('d') => { result.dir = true; } - ArgKind::LongFlag("force") | ArgKind::ShortFlag('f') => { + ArgKind::LongFlag("force") | ArgKind::MinusShortFlag('f') => { result.force = true; } ArgKind::Arg(path) => { result.paths.push(path.to_string()); } - ArgKind::LongFlag(_) | ArgKind::ShortFlag(_) => arg.bail_unsupported()?, + ArgKind::LongFlag(_) | ArgKind::MinusShortFlag(_) | ArgKind::PlusShortFlag(_) => arg.bail_unsupported()?, } } diff --git a/crates/deno_task_shell/src/shell/commands/sleep.rs b/crates/deno_task_shell/src/shell/commands/sleep.rs index b86d92d..0a5b3f2 100644 --- a/crates/deno_task_shell/src/shell/commands/sleep.rs +++ b/crates/deno_task_shell/src/shell/commands/sleep.rs @@ -86,7 +86,7 @@ fn parse_args(args: Vec) -> Result { bail!("error parsing argument '{}' to number: {}", arg, err); } }, - ArgKind::LongFlag(_) | ArgKind::ShortFlag(_) => arg.bail_unsupported()?, + ArgKind::LongFlag(_) | ArgKind::MinusShortFlag(_) | ArgKind::PlusShortFlag(_) => arg.bail_unsupported()?, } } if !had_value { diff --git a/crates/deno_task_shell/src/shell/commands/xargs.rs b/crates/deno_task_shell/src/shell/commands/xargs.rs index 11e3609..4df530d 100644 --- a/crates/deno_task_shell/src/shell/commands/xargs.rs +++ b/crates/deno_task_shell/src/shell/commands/xargs.rs @@ -176,8 +176,9 @@ fn parse_args(args: Vec) -> Result { ArgKind::Arg(arg) => { initial_args.push(arg.to_string()); } - ArgKind::ShortFlag(f) => initial_args.push(format!("-{f}")), + ArgKind::MinusShortFlag(f) => initial_args.push(format!("-{f}")), ArgKind::LongFlag(f) => initial_args.push(format!("--{f}")), + _ => continue } } } @@ -185,7 +186,7 @@ fn parse_args(args: Vec) -> Result { ArgKind::LongFlag("null") => { is_null_delimited = true; } - ArgKind::ShortFlag('d') => match iterator.next() { + ArgKind::MinusShortFlag('d') => match iterator.next() { Some(ArgKind::Arg(arg)) => { delimiter = Some(parse_delimiter(arg)?); } diff --git a/crates/deno_task_shell/src/shell/execute.rs b/crates/deno_task_shell/src/shell/execute.rs index 930a746..f298c82 100644 --- a/crates/deno_task_shell/src/shell/execute.rs +++ b/crates/deno_task_shell/src/shell/execute.rs @@ -193,6 +193,9 @@ pub fn execute_sequential_list( async_handles.extend(handles); // use the final sequential item's exit code final_exit_code = exit_code; + if state.exit_on_error() && exit_code != 0 { + break; + } } } } diff --git a/crates/deno_task_shell/src/shell/mod.rs b/crates/deno_task_shell/src/shell/mod.rs index df180b3..5c92708 100644 --- a/crates/deno_task_shell/src/shell/mod.rs +++ b/crates/deno_task_shell/src/shell/mod.rs @@ -16,6 +16,10 @@ pub use types::FutureExecuteResult; pub use types::ShellPipeReader; pub use types::ShellPipeWriter; pub use types::ShellState; +pub use types::ShellOptions; + +pub use commands::parse_arg_kinds; +pub use commands::ArgKind; pub mod fs_util; diff --git a/crates/deno_task_shell/src/shell/types.rs b/crates/deno_task_shell/src/shell/types.rs index 61ed704..5873e11 100644 --- a/crates/deno_task_shell/src/shell/types.rs +++ b/crates/deno_task_shell/src/shell/types.rs @@ -47,6 +47,8 @@ pub struct ShellState { git_branch: String, // Contents of `$git_root/.git/HEAD` last_command_cd: bool, // Was last command a `cd` (thus git_branch is current)? last_command_exit_code: i32, // Exit code of the last command + // The shell options to be modified using `set` command + shell_options: HashMap, } impl ShellState { @@ -70,6 +72,7 @@ impl ShellState { git_branch: String::new(), last_command_cd: false, last_command_exit_code: 0, + shell_options: HashMap::new(), }; // ensure the data is normalized for (name, value) in env_vars { @@ -197,6 +200,14 @@ impl ShellState { }; } + pub fn set_shell_option(&mut self, option: ShellOptions, value: bool) { + self.shell_options.insert(option, value); + } + + pub fn exit_on_error(&mut self) -> bool { + matches!(self.shell_options.get(&ShellOptions::ExitOnError), Some(true)) + } + pub fn apply_changes(&mut self, changes: &[EnvChange]) { self.last_command_cd = false; for change in changes { @@ -236,6 +247,9 @@ impl ShellState { EnvChange::UnAliasCommand(alias) => { self.alias.remove(alias); } + EnvChange::SetShellOptions(option, value) => { + self.set_shell_option(*option, *value); + } } } @@ -308,6 +322,16 @@ pub enum EnvChange { UnsetVar(String), /// Set the current working directory to the new Path Cd(PathBuf), + /// `set -ex` + SetShellOptions(ShellOptions, bool) +} + +#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug, PartialOrd)] +pub enum ShellOptions { + /// If set, the shell will exit on the first error argument `-e` + ExitOnError, + /// If set, the shell print a trace of simple commands when they are invoked `-x` + PrintTrace, } pub type FutureExecuteResult = LocalBoxFuture<'static, ExecuteResult>; @@ -319,7 +343,7 @@ pub const CANCELLATION_EXIT_CODE: i32 = 130; #[derive(Debug)] pub enum ExecuteResult { Exit(i32, Vec>), - Continue(i32, Vec, Vec>), + Continue(i32, Vec, Vec>) } impl ExecuteResult { diff --git a/crates/shell/src/commands/mod.rs b/crates/shell/src/commands/mod.rs index 86f16db..54dd062 100644 --- a/crates/shell/src/commands/mod.rs +++ b/crates/shell/src/commands/mod.rs @@ -11,11 +11,13 @@ pub mod date; pub mod touch; pub mod uname; pub mod which; +pub mod set; pub use date::DateCommand; pub use touch::TouchCommand; pub use uname::UnameCommand; pub use which::WhichCommand; +pub use set::SetCommand; pub struct LsCommand; @@ -56,6 +58,10 @@ pub fn get_commands() -> HashMap> { "date".to_string(), Rc::new(DateCommand) as Rc, ), + ( + "set".to_string(), + Rc::new(SetCommand) as Rc + ) ]) } diff --git a/crates/shell/src/commands/set.rs b/crates/shell/src/commands/set.rs new file mode 100644 index 0000000..369107d --- /dev/null +++ b/crates/shell/src/commands/set.rs @@ -0,0 +1,42 @@ +// Copyright 2018-2024 the Deno authors. MIT license. + +use futures::future::LocalBoxFuture; +use miette::bail; +use miette::Result; + +use deno_task_shell::{ExecuteResult, EnvChange, ShellCommandContext, ShellCommand, ArgKind, parse_arg_kinds, ShellOptions}; + +pub struct SetCommand; + +impl ShellCommand for SetCommand { + fn execute( + &self, + mut context: ShellCommandContext, + ) -> LocalBoxFuture<'static, ExecuteResult> { + let result = match execute_set(context.args) { + Ok((code, env_changes)) => ExecuteResult::Continue(code, env_changes, Vec::new()), + Err(err) => { + context.stderr.write_line(&format!("set: {err}")).unwrap(); + ExecuteResult::Exit(2, Vec::new()) + } + }; + Box::pin(futures::future::ready(result)) + } +} + +fn execute_set(args: Vec) -> Result<(i32, Vec)> { + let args = parse_arg_kinds(&args); + let mut env_changes = Vec::new(); + for arg in args { + match arg { + ArgKind::MinusShortFlag('e') => { + env_changes.push(EnvChange::SetShellOptions(ShellOptions::ExitOnError, true)); + } + ArgKind::PlusShortFlag('e') => { + env_changes.push(EnvChange::SetShellOptions(ShellOptions::ExitOnError, false)); + } + _ => bail!(format!("Unsupported argument: {:?}", arg)), + } + } + Ok((0, env_changes)) +}