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_engine::command_prelude::*;
use nu_protocol::ByteStreamSource;
#[derive(Clone)] #[derive(Clone)]
pub struct Print; 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, engine_state: &EngineState,
stack: &mut Stack, stack: &mut Stack,
call: &Call, call: &Call,
input: PipelineData, mut input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let args: Vec<Value> = call.rest(engine_state, stack, 0)?; let args: Vec<Value> = call.rest(engine_state, stack, 0)?;
let no_newline = call.has_flag(engine_state, stack, "no-newline")?; 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() { } 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 { if raw {
input.print_raw(engine_state, no_newline, to_stderr)?; input.print_raw(engine_state, no_newline, to_stderr)?;
} else { } else {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,6 +6,14 @@ use pretty_assertions::assert_eq;
#[test] #[test]
fn doesnt_break_on_utf8() { fn doesnt_break_on_utf8() {
let actual = nu!("echo ö"); let actual = nu!("echo ö");
assert_eq!(actual.out, "ö", "'{}' should contain ö", actual.out); 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");
}