Skip to content

Commit 175858c

Browse files
authored
206 sourcing a file will lose the current path value (#248)
* exit shell upon exit command * fix source issue with exit * update subshell behaviour * fix: update ExecuteResult handling in while loop and subshell execution * run fmt
1 parent 1405935 commit 175858c

File tree

8 files changed

+77
-54
lines changed

8 files changed

+77
-54
lines changed

crates/deno_task_shell/src/shell/commands/exit.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ impl ShellCommand for ExitCommand {
1919
mut context: ShellCommandContext,
2020
) -> LocalBoxFuture<'static, ExecuteResult> {
2121
let result = match execute_exit(context.args) {
22-
Ok(code) => ExecuteResult::Exit(code, Vec::new()),
22+
Ok(code) => ExecuteResult::Exit(code, Vec::new(), Vec::new()),
2323
Err(err) => {
2424
context.stderr.write_line(&format!("exit: {err}")).unwrap();
25-
ExecuteResult::Exit(2, Vec::new())
25+
ExecuteResult::Exit(2, Vec::new(), Vec::new())
2626
}
2727
};
2828
Box::pin(futures::future::ready(result))

crates/deno_task_shell/src/shell/execute.rs

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ pub async fn execute_with_pipes(
136136
.await;
137137

138138
match result {
139-
ExecuteResult::Exit(code, _) => code,
139+
ExecuteResult::Exit(code, _, _) => code,
140140
ExecuteResult::Continue(exit_code, _, _) => exit_code,
141141
}
142142
}
@@ -191,7 +191,10 @@ pub fn execute_sequential_list(
191191
)
192192
.await;
193193
match result {
194-
ExecuteResult::Exit(exit_code, handles) => {
194+
ExecuteResult::Exit(exit_code, changes, handles) => {
195+
state.apply_changes(&changes);
196+
state.set_shell_var("?", &exit_code.to_string());
197+
final_changes.extend(changes);
195198
async_handles.extend(handles);
196199
final_exit_code = exit_code;
197200
was_exit = true;
@@ -223,7 +226,7 @@ pub fn execute_sequential_list(
223226
}
224227

225228
if was_exit {
226-
ExecuteResult::Exit(final_exit_code, async_handles)
229+
ExecuteResult::Exit(final_exit_code, final_changes, async_handles)
227230
} else {
228231
ExecuteResult::Continue(
229232
final_exit_code,
@@ -305,7 +308,7 @@ fn execute_sequence(
305308
)
306309
.await;
307310
let (exit_code, mut async_handles) = match first_result {
308-
ExecuteResult::Exit(_, _) => return first_result,
311+
ExecuteResult::Exit(_, _, _) => return first_result,
309312
ExecuteResult::Continue(
310313
exit_code,
311314
sub_changes,
@@ -340,9 +343,10 @@ fn execute_sequence(
340343
execute_sequence(next, state, stdin, stdout, stderr)
341344
.await;
342345
match next_result {
343-
ExecuteResult::Exit(code, sub_handles) => {
346+
ExecuteResult::Exit(code, sub_changes, sub_handles) => {
347+
changes.extend(sub_changes);
344348
async_handles.extend(sub_handles);
345-
ExecuteResult::Exit(code, async_handles)
349+
ExecuteResult::Exit(code, changes, async_handles)
346350
}
347351
ExecuteResult::Continue(
348352
exit_code,
@@ -382,8 +386,8 @@ async fn execute_pipeline(
382386
.await;
383387
if pipeline.negated {
384388
match result {
385-
ExecuteResult::Exit(code, handles) => {
386-
ExecuteResult::Exit(code, handles)
389+
ExecuteResult::Exit(code, changes, handles) => {
390+
ExecuteResult::Exit(code, changes, handles)
387391
}
388392
ExecuteResult::Continue(code, changes, handles) => {
389393
let new_code = if code == 0 { 1 } else { 0 };
@@ -617,8 +621,8 @@ async fn execute_command(
617621
CommandInner::Subshell(list) => {
618622
// Here the state can be changed but we can not pass by reference
619623
match execute_subshell(list, state, stdin, stdout, stderr).await {
620-
ExecuteResult::Exit(code, handles) => {
621-
ExecuteResult::Exit(code, handles)
624+
ExecuteResult::Exit(code, _, handles) => {
625+
ExecuteResult::Exit(code, changes, handles)
622626
}
623627
ExecuteResult::Continue(code, _, handles) => {
624628
ExecuteResult::Continue(code, changes, handles)
@@ -705,7 +709,9 @@ async fn execute_while_clause(
705709
.await;
706710

707711
match exec_result {
708-
ExecuteResult::Exit(code, handles) => {
712+
ExecuteResult::Exit(code, env_changes, handles) => {
713+
state.apply_changes(&env_changes);
714+
changes.extend(env_changes);
709715
async_handles.extend(handles);
710716
last_exit_code = code;
711717
break;
@@ -730,7 +736,7 @@ async fn execute_while_clause(
730736
state.apply_changes(&changes);
731737

732738
if state.exit_on_error() && last_exit_code != 0 {
733-
ExecuteResult::Exit(last_exit_code, async_handles)
739+
ExecuteResult::Exit(last_exit_code, changes, async_handles)
734740
} else {
735741
ExecuteResult::Continue(last_exit_code, changes, async_handles)
736742
}
@@ -776,7 +782,8 @@ async fn execute_for_clause(
776782
.await;
777783

778784
match result {
779-
ExecuteResult::Exit(code, handles) => {
785+
ExecuteResult::Exit(code, env_changes, handles) => {
786+
changes.extend(env_changes);
780787
async_handles.extend(handles);
781788
last_exit_code = code;
782789
break;
@@ -792,7 +799,7 @@ async fn execute_for_clause(
792799
state.apply_changes(&changes);
793800

794801
if state.exit_on_error() && last_exit_code != 0 {
795-
ExecuteResult::Exit(last_exit_code, async_handles)
802+
ExecuteResult::Exit(last_exit_code, changes, async_handles)
796803
} else {
797804
ExecuteResult::Continue(last_exit_code, changes, async_handles)
798805
}
@@ -1077,7 +1084,8 @@ async fn execute_pipe_sequence(
10771084
let mut changes: Vec<EnvChange> = changes.into_iter().flatten().collect();
10781085

10791086
match last_result {
1080-
ExecuteResult::Exit(code, mut handles) => {
1087+
ExecuteResult::Exit(code, env_changes, mut handles) => {
1088+
changes.extend(env_changes);
10811089
handles.extend(all_handles);
10821090
ExecuteResult::Continue(code, changes, handles)
10831091
}
@@ -1108,9 +1116,9 @@ async fn execute_subshell(
11081116
.await;
11091117

11101118
match result {
1111-
ExecuteResult::Exit(code, handles) => {
1119+
ExecuteResult::Exit(code, env_changes, handles) => {
11121120
// sub shells do not cause an exit
1113-
ExecuteResult::Continue(code, Vec::new(), handles)
1121+
ExecuteResult::Continue(code, env_changes, handles)
11141122
}
11151123
ExecuteResult::Continue(code, env_changes, handles) => {
11161124
// env changes are not propagated
@@ -1155,8 +1163,9 @@ async fn execute_if_clause(
11551163
)
11561164
.await;
11571165
match exec_result {
1158-
ExecuteResult::Exit(code, handles) => {
1159-
return ExecuteResult::Exit(code, handles);
1166+
ExecuteResult::Exit(code, env_changes, handles) => {
1167+
changes.extend(env_changes);
1168+
return ExecuteResult::Exit(code, changes, handles);
11601169
}
11611170
ExecuteResult::Continue(code, env_changes, handles) => {
11621171
changes.extend(env_changes);
@@ -1186,8 +1195,11 @@ async fn execute_if_clause(
11861195
)
11871196
.await;
11881197
match exec_result {
1189-
ExecuteResult::Exit(code, handles) => {
1190-
return ExecuteResult::Exit(code, handles);
1198+
ExecuteResult::Exit(code, env_changes, handles) => {
1199+
changes.extend(env_changes);
1200+
return ExecuteResult::Exit(
1201+
code, changes, handles,
1202+
);
11911203
}
11921204
ExecuteResult::Continue(
11931205
code,
@@ -1438,8 +1450,9 @@ async fn execute_simple_command(
14381450

14391451
let result = execute_command_args(args, state, stdin, stdout, stderr).await;
14401452
match result {
1441-
ExecuteResult::Exit(code, handles) => {
1442-
ExecuteResult::Exit(code, handles)
1453+
ExecuteResult::Exit(code, env_changes, handles) => {
1454+
changes.extend(env_changes);
1455+
ExecuteResult::Exit(code, changes, handles)
14431456
}
14441457
ExecuteResult::Continue(code, env_changes, handles) => {
14451458
changes.extend(env_changes);

crates/deno_task_shell/src/shell/types.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -389,13 +389,13 @@ pub const CANCELLATION_EXIT_CODE: i32 = 130;
389389

390390
#[derive(Debug)]
391391
pub enum ExecuteResult {
392-
Exit(i32, Vec<JoinHandle<i32>>),
392+
Exit(i32, Vec<EnvChange>, Vec<JoinHandle<i32>>),
393393
Continue(i32, Vec<EnvChange>, Vec<JoinHandle<i32>>),
394394
}
395395

396396
impl ExecuteResult {
397397
pub fn for_cancellation() -> ExecuteResult {
398-
ExecuteResult::Exit(CANCELLATION_EXIT_CODE, Vec::new())
398+
ExecuteResult::Exit(CANCELLATION_EXIT_CODE, Vec::new(), Vec::new())
399399
}
400400

401401
pub fn from_exit_code(exit_code: i32) -> ExecuteResult {
@@ -404,7 +404,7 @@ impl ExecuteResult {
404404

405405
pub fn into_exit_code_and_handles(self) -> (i32, Vec<JoinHandle<i32>>) {
406406
match self {
407-
ExecuteResult::Exit(code, handles) => (code, handles),
407+
ExecuteResult::Exit(code, _, handles) => (code, handles),
408408
ExecuteResult::Continue(code, _, handles) => (code, handles),
409409
}
410410
}
@@ -415,7 +415,7 @@ impl ExecuteResult {
415415

416416
pub fn into_changes(self) -> Vec<EnvChange> {
417417
match self {
418-
ExecuteResult::Exit(_, _) => Vec::new(),
418+
ExecuteResult::Exit(_, changes, _) => changes,
419419
ExecuteResult::Continue(_, changes, _) => changes,
420420
}
421421
}
@@ -424,10 +424,17 @@ impl ExecuteResult {
424424
self,
425425
) -> (Vec<JoinHandle<i32>>, Vec<EnvChange>) {
426426
match self {
427-
ExecuteResult::Exit(_, handles) => (handles, Vec::new()),
427+
ExecuteResult::Exit(_, changes, handles) => (handles, changes),
428428
ExecuteResult::Continue(_, changes, handles) => (handles, changes),
429429
}
430430
}
431+
432+
pub fn exit_code(&self) -> i32 {
433+
match self {
434+
ExecuteResult::Exit(code, _, _) => *code,
435+
ExecuteResult::Continue(code, _, _) => *code,
436+
}
437+
}
431438
}
432439

433440
/// Reader side of a pipe.

crates/shell/src/commands/set.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ impl ShellCommand for SetCommand {
1717
Ok((code, env_changes)) => ExecuteResult::Continue(code, env_changes, Vec::new()),
1818
Err(err) => {
1919
context.stderr.write_line(&format!("set: {err}")).unwrap();
20-
ExecuteResult::Exit(2, Vec::new())
20+
ExecuteResult::Exit(2, Vec::new(), Vec::new())
2121
}
2222
};
2323
Box::pin(futures::future::ready(result))

crates/shell/src/execute.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub async fn execute_inner(
2020
stderr.write_all(format!("Filename: {:?}\n", filename).as_bytes())?;
2121
}
2222
stderr.write_all(format!("Syntax error: {:?}", e).as_bytes())?;
23-
return Ok(ExecuteResult::Exit(1, vec![]));
23+
return Ok(ExecuteResult::Exit(1, vec![], vec![]));
2424
}
2525

2626
// spawn a sequential list and pipe its output to the environment
@@ -41,18 +41,18 @@ pub async fn execute(
4141
text: &str,
4242
filename: Option<String>,
4343
state: &mut ShellState,
44-
) -> miette::Result<i32> {
44+
) -> miette::Result<ExecuteResult> {
4545
let result = execute_inner(text, filename, state.clone()).await?;
4646

47-
match result {
48-
ExecuteResult::Continue(exit_code, changes, _) => {
49-
// set CWD to the last command's CWD
50-
state.apply_changes(&changes);
51-
std::env::set_current_dir(state.cwd())
52-
.into_diagnostic()
53-
.context("Failed to set CWD")?;
54-
Ok(exit_code)
55-
}
56-
ExecuteResult::Exit(exit_code, _) => Ok(exit_code),
57-
}
47+
let changes = match &result {
48+
ExecuteResult::Exit(_, changes, _) => changes,
49+
ExecuteResult::Continue(_, changes, _) => changes,
50+
};
51+
// set CWD to the last command's CWD
52+
state.apply_changes(changes);
53+
std::env::set_current_dir(state.cwd())
54+
.into_diagnostic()
55+
.context("Failed to set CWD")?;
56+
57+
Ok(result)
5858
}

crates/shell/src/main.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::path::PathBuf;
44

55
use clap::Parser;
66
use deno_task_shell::parser::debug_parse;
7+
use deno_task_shell::ExecuteResult;
78
use deno_task_shell::ShellState;
89
use miette::Context;
910
use miette::IntoDiagnostic;
@@ -73,14 +74,14 @@ async fn init_state(norc: bool, var_args: &[String]) -> miette::Result<ShellStat
7374
let shellrc_file = home_dir.join(".shellrc");
7475
if !norc && shellrc_file.exists() {
7576
let line = format!("source '{}'", shellrc_file.to_string_lossy());
76-
let prev_exit_code = execute(
77+
let result = execute(
7778
&line,
7879
Some(shellrc_file.as_path().display().to_string()),
7980
&mut state,
8081
)
8182
.await
8283
.context("Failed to source ~/.shellrc")?;
83-
state.set_last_command_exit_code(prev_exit_code);
84+
state.set_last_command_exit_code(result.exit_code());
8485
}
8586
}
8687

@@ -183,15 +184,13 @@ async fn interactive(state: Option<ShellState>, norc: bool, args: &[String]) ->
183184
rl.add_history_entry(line.as_str()).into_diagnostic()?;
184185

185186
// Process the input (here we just echo it back)
186-
let prev_exit_code = execute(&line, None, &mut state)
187+
let result = execute(&line, None, &mut state)
187188
.await
188189
.context("Failed to execute")?;
189-
state.set_last_command_exit_code(prev_exit_code);
190+
state.set_last_command_exit_code(result.exit_code());
190191

191-
// Check for exit command
192-
if line.trim().eq_ignore_ascii_case("exit") {
193-
println!("Exiting...");
194-
break;
192+
if let ExecuteResult::Exit(exit_code, _, _) = result {
193+
std::process::exit(exit_code);
195194
}
196195
}
197196
Err(ReadlineError::Interrupted) => {
@@ -235,13 +234,13 @@ async fn main() -> miette::Result<()> {
235234
return Ok(());
236235
}
237236

238-
let exit_code = execute(&script_text, filename, &mut state).await?;
237+
let result = execute(&script_text, filename, &mut state).await?;
239238

240239
if options.interact {
241240
interactive(Some(state), options.norc, &options.args).await?;
242241
}
243242

244-
std::process::exit(exit_code);
243+
std::process::exit(result.exit_code());
245244
}
246245
}
247246
}

crates/tests/test-data/source.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
> export FOO='TESTVALUE' && source $CARGO_MANIFEST_DIR/../../scripts/exit.sh && echo $FOO
2+

scripts/exit.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
echo "Hello World"
2+
exit

0 commit comments

Comments
 (0)