Loops return external stream when external command failed. (#8646)

This commit is contained in:
WindSoilder 2023-04-06 01:38:04 +08:00 committed by GitHub
parent 1fcb98289a
commit 54a18991ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 83 additions and 4 deletions

View file

@ -122,7 +122,9 @@ impl Command for For {
Ok(pipeline) => {
let exit_code = pipeline.print(&engine_state, stack, false, false)?;
if exit_code != 0 {
break;
return Ok(PipelineData::new_external_stream_with_only_exit_code(
exit_code,
));
}
}
}
@ -164,7 +166,9 @@ impl Command for For {
Ok(pipeline) => {
let exit_code = pipeline.drain_with_exit_code()?;
if exit_code != 0 {
break;
return Ok(PipelineData::new_external_stream_with_only_exit_code(
exit_code,
));
}
}
}

View file

@ -69,7 +69,9 @@ impl Command for Loop {
Ok(pipeline) => {
let exit_code = pipeline.drain_with_exit_code()?;
if exit_code != 0 {
break;
return Ok(PipelineData::new_external_stream_with_only_exit_code(
exit_code,
));
}
}
}

View file

@ -79,7 +79,11 @@ impl Command for While {
Ok(pipeline) => {
let exit_code = pipeline.drain_with_exit_code()?;
if exit_code != 0 {
break;
return Ok(
PipelineData::new_external_stream_with_only_exit_code(
exit_code,
),
);
}
}
}

View file

@ -28,3 +28,27 @@ fn for_break_on_external_failed() {
// so our output will be `1`
assert_eq!(actual.out, "1");
}
#[test]
fn failed_for_should_break_running() {
let actual = nu!(
cwd: ".",
r#"
for i in 1..2 {
nu --testbin fail
}
print 3"#
);
assert!(!actual.out.contains('3'));
let actual = nu!(
cwd: ".",
r#"
let x = [1 2]
for i in $x {
nu --testbin fail
}
print 3"#
);
assert!(!actual.out.contains('3'));
}

View file

@ -40,3 +40,22 @@ fn loop_break_on_external_failed() {
// so our output will be `1`.
assert_eq!(actual.out, "1");
}
#[test]
fn failed_loop_should_break_running() {
let actual = nu!(
cwd: ".",
r#"
mut total = 0;
loop {
if $total == 3 {
break;
} else {
$total += 1;
}
nu --testbin fail;
}
print 3"#
);
assert!(!actual.out.contains('3'));
}

View file

@ -31,3 +31,12 @@ fn while_break_on_external_failed() {
// so our output will be `1`
assert_eq!(actual.out, "1");
}
#[test]
fn failed_while_should_break_running() {
let actual = nu!(
cwd: ".",
"mut total = 0; while $total < 2 { $total = $total + 1; nu --testbin fail }; print 3"
);
assert!(!actual.out.contains('3'));
}

View file

@ -72,6 +72,23 @@ impl PipelineData {
PipelineData::Value(Value::Nothing { span }, metadata)
}
/// create a `PipelineData::ExternalStream` with proper exit_code
///
/// It's useful to break running without raising error at user level.
pub fn new_external_stream_with_only_exit_code(exit_code: i64) -> PipelineData {
PipelineData::ExternalStream {
stdout: None,
stderr: None,
exit_code: Some(ListStream::from_stream(
[Value::int(exit_code, Span::unknown())].into_iter(),
None,
)),
span: Span::unknown(),
metadata: None,
trim_end_newline: false,
}
}
pub fn empty() -> PipelineData {
PipelineData::Empty
}