Skip to content

Commit 7478213

Browse files
committed
allow outputting for set command
1 parent efaecb7 commit 7478213

File tree

2 files changed

+92
-20
lines changed

2 files changed

+92
-20
lines changed

src/shell/commands/set.rs

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,39 +22,64 @@ impl ShellCommand for SetCommand {
2222
}
2323

2424
fn execute_set(context: &mut ShellCommandContext) -> ExecuteResult {
25-
let mut changes = Vec::new();
2625
let args: Vec<String> = context
2726
.args
2827
.iter()
2928
.filter_map(|a| a.to_str().map(|s| s.to_string()))
3029
.collect();
3130

31+
// no arguments - in bash this would list all shell variables
32+
// for now, just return success
33+
if args.is_empty() {
34+
return ExecuteResult::from_exit_code(0);
35+
}
36+
37+
// set -o (list options in human-readable format)
38+
if args.len() == 1 && args[0] == "-o" {
39+
let opts = context.state.shell_options();
40+
let _ = context.stdout.write_line(&format!(
41+
"pipefail\t{}",
42+
if opts.contains(ShellOptions::PIPEFAIL) {
43+
"on"
44+
} else {
45+
"off"
46+
}
47+
));
48+
return ExecuteResult::from_exit_code(0);
49+
}
50+
51+
// set +o (output commands to recreate current settings)
52+
if args.len() == 1 && args[0] == "+o" {
53+
let opts = context.state.shell_options();
54+
let _ = context.stdout.write_line(&format!(
55+
"set {} pipefail",
56+
if opts.contains(ShellOptions::PIPEFAIL) {
57+
"-o"
58+
} else {
59+
"+o"
60+
}
61+
));
62+
return ExecuteResult::from_exit_code(0);
63+
}
64+
65+
// parse option changes: set -o opt1 -o opt2 +o opt3 ...
66+
let mut changes = Vec::new();
3267
let mut i = 0;
3368
while i < args.len() {
3469
let arg = &args[i];
35-
if arg == "-o" || arg == "+o" {
70+
if (arg == "-o" || arg == "+o") && i + 1 < args.len() {
3671
let enable = arg == "-o";
37-
if i + 1 < args.len() {
38-
let option_name = &args[i + 1];
39-
match option_name.as_str() {
40-
"pipefail" => {
41-
changes.push(EnvChange::SetOption(ShellOptions::PIPEFAIL, enable));
42-
}
43-
_ => {
44-
let _ = context
45-
.stderr
46-
.write_line(&format!("set: unknown option: {}", option_name));
47-
return ExecuteResult::from_exit_code(1);
48-
}
49-
}
72+
let option_name = &args[i + 1];
73+
if let Some(option) = parse_option_name(option_name) {
74+
changes.push(EnvChange::SetOption(option, enable));
5075
i += 2;
5176
} else {
52-
// No option name provided - in bash this would list options
53-
// For now, just return success
54-
i += 1;
77+
let _ = context
78+
.stderr
79+
.write_line(&format!("set: unknown option: {}", option_name));
80+
return ExecuteResult::from_exit_code(1);
5581
}
5682
} else {
57-
// unknown argument
5883
let _ = context
5984
.stderr
6085
.write_line(&format!("set: invalid option: {}", arg));
@@ -64,3 +89,10 @@ fn execute_set(context: &mut ShellCommandContext) -> ExecuteResult {
6489

6590
ExecuteResult::Continue(0, changes, Vec::new())
6691
}
92+
93+
fn parse_option_name(name: &str) -> Option<ShellOptions> {
94+
match name {
95+
"pipefail" => Some(ShellOptions::PIPEFAIL),
96+
_ => None,
97+
}
98+
}

tests/integration_test.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2003,13 +2003,53 @@ async fn pipefail_option() {
20032003
.run()
20042004
.await;
20052005

2006-
// invalid argument
2006+
// invalid option
20072007
TestBuilder::new()
20082008
.command("set -x")
20092009
.assert_stderr("set: invalid option: -x\n")
20102010
.assert_exit_code(1)
20112011
.run()
20122012
.await;
2013+
2014+
// invalid option (non-option argument)
2015+
TestBuilder::new()
2016+
.command("set foo")
2017+
.assert_stderr("set: invalid option: foo\n")
2018+
.assert_exit_code(1)
2019+
.run()
2020+
.await;
2021+
2022+
// set -o (list options, readable format)
2023+
TestBuilder::new()
2024+
.command("set -o")
2025+
.assert_stdout("pipefail\toff\n")
2026+
.assert_exit_code(0)
2027+
.run()
2028+
.await;
2029+
2030+
// set -o after enabling pipefail
2031+
TestBuilder::new()
2032+
.command("set -o pipefail && set -o")
2033+
.assert_stdout("pipefail\ton\n")
2034+
.assert_exit_code(0)
2035+
.run()
2036+
.await;
2037+
2038+
// set +o (list options, reusable format)
2039+
TestBuilder::new()
2040+
.command("set +o")
2041+
.assert_stdout("set +o pipefail\n")
2042+
.assert_exit_code(0)
2043+
.run()
2044+
.await;
2045+
2046+
// set +o after enabling pipefail
2047+
TestBuilder::new()
2048+
.command("set -o pipefail && set +o")
2049+
.assert_stdout("set -o pipefail\n")
2050+
.assert_exit_code(0)
2051+
.run()
2052+
.await;
20132053
}
20142054

20152055
#[tokio::test]

0 commit comments

Comments
 (0)