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))
+}