Fix non-zero exit code errors in middle of pipeline (#13899)

# Description
Fixes #13868. Should come after #13885.

# User-Facing Changes
Bug fix.

# Tests + Formatting
Added a test.
This commit is contained in:
Ian Manske 2024-10-02 04:04:18 -07:00 committed by GitHub
parent 475aa4f1dd
commit f03ba6793e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 37 additions and 8 deletions

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::ByteStreamSource;
#[derive(Clone)]
pub struct Print;
@ -50,7 +51,7 @@ Since this command has no output, there is no point in piping it with other comm
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
mut input: PipelineData,
) -> Result<PipelineData, ShellError> {
let args: Vec<Value> = call.rest(engine_state, stack, 0)?;
let no_newline = call.has_flag(engine_state, stack, "no-newline")?;
@ -69,6 +70,11 @@ Since this command has no output, there is no point in piping it with other comm
}
}
} else if !input.is_nothing() {
if let PipelineData::ByteStream(stream, _) = &mut input {
if let ByteStreamSource::Child(child) = stream.source_mut() {
child.ignore_error(true);
}
}
if raw {
input.print_raw(engine_state, no_newline, to_stderr)?;
} else {

View File

@ -147,6 +147,7 @@ impl Command for Do {
None
};
child.ignore_error(false);
child.wait()?;
let mut child = ChildProcess::from_raw(None, None, None, span);
@ -172,7 +173,7 @@ impl Command for Do {
) =>
{
if let ByteStreamSource::Child(child) = stream.source_mut() {
child.ignore_error();
child.ignore_error(true);
}
Ok(PipelineData::ByteStream(stream, metadata))
}

View File

@ -1,5 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::{engine::StateWorkingSet, OutDest};
use nu_protocol::{engine::StateWorkingSet, ByteStreamSource, OutDest};
#[derive(Clone)]
pub struct Ignore;
@ -32,8 +32,13 @@ impl Command for Ignore {
_engine_state: &EngineState,
_stack: &mut Stack,
_call: &Call,
input: PipelineData,
mut input: PipelineData,
) -> Result<PipelineData, ShellError> {
if let PipelineData::ByteStream(stream, _) = &mut input {
if let ByteStreamSource::Child(child) = stream.source_mut() {
child.ignore_error(true);
}
}
input.drain()?;
Ok(PipelineData::empty())
}

View File

@ -182,6 +182,8 @@ impl Command for Save {
}
(None, None) => {}
};
child.wait()?;
}
}

View File

@ -180,12 +180,19 @@ impl Command for External {
}
// Wrap the output into a `PipelineData::ByteStream`.
let child = ChildProcess::new(
let mut child = ChildProcess::new(
child,
merged_stream,
matches!(stderr, OutDest::Pipe),
call.head,
)?;
if matches!(stdout, OutDest::Pipe | OutDest::PipeSeparate)
|| matches!(stderr, OutDest::Pipe | OutDest::PipeSeparate)
{
child.ignore_error(true);
}
Ok(PipelineData::ByteStream(
ByteStream::child(child, call.head),
None,

View File

@ -202,8 +202,8 @@ impl ChildProcess {
}
}
pub fn ignore_error(&mut self) -> &mut Self {
self.ignore_error = true;
pub fn ignore_error(&mut self, ignore: bool) -> &mut Self {
self.ignore_error = ignore;
self
}

View File

@ -6,6 +6,14 @@ use pretty_assertions::assert_eq;
#[test]
fn doesnt_break_on_utf8() {
let actual = nu!("echo ö");
assert_eq!(actual.out, "ö", "'{}' should contain ö", actual.out);
}
#[test]
fn non_zero_exit_code_in_middle_of_pipeline_ignored() {
let actual = nu!("nu -c 'print a b; exit 42' | collect");
assert_eq!(actual.out, "ab");
let actual = nu!("nu -c 'print a b; exit 42' | nu --stdin -c 'collect'");
assert_eq!(actual.out, "ab");
}