add check for error redirection for pipe error mode

This commit is contained in:
Devyn Cairns 2024-07-08 15:14:31 -07:00
parent 38884eec73
commit 5c5db1bd54
5 changed files with 33 additions and 3 deletions

View File

@ -172,6 +172,7 @@ impl BlockBuilder {
Instruction::PushParserInfo { name: _, info: _ } => Ok(()), Instruction::PushParserInfo { name: _, info: _ } => Ok(()),
Instruction::RedirectOut { mode: _ } => Ok(()), Instruction::RedirectOut { mode: _ } => Ok(()),
Instruction::RedirectErr { mode: _ } => Ok(()), Instruction::RedirectErr { mode: _ } => Ok(()),
Instruction::CheckErrRedirected { src } => allocate(&[*src], &[*src]),
Instruction::OpenFile { Instruction::OpenFile {
file_num: _, file_num: _,
path, path,

View File

@ -133,6 +133,12 @@ pub(crate) fn finish_redirection(
}) => { }) => {
builder.push(Instruction::CloseFile { file_num }.into_spanned(span))?; builder.push(Instruction::CloseFile { file_num }.into_spanned(span))?;
} }
Some(Spanned {
item: RedirectMode::Pipe | RedirectMode::Capture,
span,
}) => {
builder.push(Instruction::CheckErrRedirected { src: out_reg }.into_spanned(span))?;
}
_ => (), _ => (),
} }

View File

@ -6,9 +6,9 @@ use nu_protocol::{
debugger::DebugContext, debugger::DebugContext,
engine::{Argument, Closure, EngineState, ErrorHandler, Matcher, Redirection, Stack}, engine::{Argument, Closure, EngineState, ErrorHandler, Matcher, Redirection, Stack},
ir::{Call, DataSlice, Instruction, IrAstRef, IrBlock, Literal, RedirectMode}, ir::{Call, DataSlice, Instruction, IrAstRef, IrBlock, Literal, RedirectMode},
record, DeclId, ErrSpan, Flag, IntoPipelineData, IntoSpanned, ListStream, OutDest, record, ByteStreamSource, DeclId, ErrSpan, Flag, IntoPipelineData, IntoSpanned, ListStream,
PipelineData, PositionalArg, Range, Record, RegId, ShellError, Signature, Span, Spanned, Value, OutDest, PipelineData, PositionalArg, Range, Record, RegId, ShellError, Signature, Span,
VarId, ENV_VARIABLE_ID, Spanned, Value, VarId, ENV_VARIABLE_ID,
}; };
use nu_utils::IgnoreCaseExt; use nu_utils::IgnoreCaseExt;
@ -394,6 +394,24 @@ fn eval_instruction<D: DebugContext>(
ctx.redirect_err = eval_redirection(ctx, mode, *span, RedirectionStream::Err)?; ctx.redirect_err = eval_redirection(ctx, mode, *span, RedirectionStream::Err)?;
Ok(Continue) Ok(Continue)
} }
Instruction::CheckErrRedirected { src } => {
let data = ctx.take_reg(*src);
match &data {
PipelineData::ByteStream(stream, _)
if matches!(stream.source(), ByteStreamSource::Child(_)) =>
{
ctx.put_reg(*src, data);
Ok(Continue)
}
_ => Err(ShellError::GenericError {
error: "Can't redirect stderr of internal command output".into(),
msg: "piping stderr only works on external commands".into(),
span: Some(*span),
help: None,
inner: vec![],
}),
}
}
Instruction::OpenFile { Instruction::OpenFile {
file_num, file_num,
path, path,

View File

@ -127,6 +127,9 @@ impl<'a> fmt::Display for FmtInstruction<'a> {
Instruction::RedirectErr { mode } => { Instruction::RedirectErr { mode } => {
write!(f, "{:WIDTH$} {mode}", "redirect-err") write!(f, "{:WIDTH$} {mode}", "redirect-err")
} }
Instruction::CheckErrRedirected { src } => {
write!(f, "{:WIDTH$} {src}", "check-err-redirected")
}
Instruction::OpenFile { Instruction::OpenFile {
file_num, file_num,
path, path,

View File

@ -144,6 +144,8 @@ pub enum Instruction {
/// ///
/// The register for a file redirection is not consumed. /// The register for a file redirection is not consumed.
RedirectErr { mode: RedirectMode }, RedirectErr { mode: RedirectMode },
/// Throw an error if stderr wasn't redirected in the given stream. `src` is preserved.
CheckErrRedirected { src: RegId },
/// Open a file for redirection, pushing it onto the file stack. /// Open a file for redirection, pushing it onto the file stack.
OpenFile { OpenFile {
file_num: u32, file_num: u32,