Stdout/Stderr redirection (#7185)

This adds new pipeline connectors called out> and err> which redirect either stdout or stderr to a file. You can also use out+err> (or err+out>) to redirect both streams into a file.
This commit is contained in:
JT
2022-11-23 07:26:13 +13:00
committed by GitHub
parent c9f9078726
commit 74a73f9838
15 changed files with 856 additions and 346 deletions

View File

@ -2,38 +2,50 @@ use std::ops::{Index, IndexMut};
use crate::{ast::Expression, engine::StateWorkingSet, Span, VarId};
#[derive(Debug, Clone)]
pub enum Redirection {
Stdout,
Stderr,
StdoutAndStderr,
}
// Note: Span in the below is for the span of the connector not the whole element
#[derive(Debug, Clone)]
pub enum PipelineElement {
Expression(Expression),
Redirect(Expression),
And(Expression),
Or(Expression),
Expression(Option<Span>, Expression),
Redirection(Span, Redirection, Expression),
And(Span, Expression),
Or(Span, Expression),
}
impl PipelineElement {
pub fn span(&self) -> Span {
match self {
PipelineElement::Expression(expression)
| PipelineElement::Redirect(expression)
| PipelineElement::And(expression)
| PipelineElement::Or(expression) => expression.span,
PipelineElement::Expression(None, expression) => expression.span,
PipelineElement::Expression(Some(span), expression)
| PipelineElement::Redirection(span, _, expression)
| PipelineElement::And(span, expression)
| PipelineElement::Or(span, expression) => Span {
start: span.start,
end: expression.span.end,
},
}
}
pub fn has_in_variable(&self, working_set: &StateWorkingSet) -> bool {
match self {
PipelineElement::Expression(expression)
| PipelineElement::Redirect(expression)
| PipelineElement::And(expression)
| PipelineElement::Or(expression) => expression.has_in_variable(working_set),
PipelineElement::Expression(_, expression)
| PipelineElement::Redirection(_, _, expression)
| PipelineElement::And(_, expression)
| PipelineElement::Or(_, expression) => expression.has_in_variable(working_set),
}
}
pub fn replace_in_variable(&mut self, working_set: &mut StateWorkingSet, new_var_id: VarId) {
match self {
PipelineElement::Expression(expression)
| PipelineElement::Redirect(expression)
| PipelineElement::And(expression)
| PipelineElement::Or(expression) => {
PipelineElement::Expression(_, expression)
| PipelineElement::Redirection(_, _, expression)
| PipelineElement::And(_, expression)
| PipelineElement::Or(_, expression) => {
expression.replace_in_variable(working_set, new_var_id)
}
}
@ -46,10 +58,10 @@ impl PipelineElement {
new_span: Span,
) {
match self {
PipelineElement::Expression(expression)
| PipelineElement::Redirect(expression)
| PipelineElement::And(expression)
| PipelineElement::Or(expression) => {
PipelineElement::Expression(_, expression)
| PipelineElement::Redirection(_, _, expression)
| PipelineElement::And(_, expression)
| PipelineElement::Or(_, expression) => {
expression.replace_span(working_set, replaced, new_span)
}
}
@ -76,7 +88,10 @@ impl Pipeline {
Self {
elements: expressions
.into_iter()
.map(PipelineElement::Expression)
.enumerate()
.map(|(idx, x)| {
PipelineElement::Expression(if idx == 0 { None } else { Some(x.span) }, x)
})
.collect(),
}
}

View File

@ -53,6 +53,20 @@ impl RawStream {
Ok(Spanned { item: output, span })
}
pub fn chain(self, stream: RawStream) -> RawStream {
RawStream {
stream: Box::new(self.stream.chain(stream.stream)),
leftover: self
.leftover
.into_iter()
.chain(stream.leftover.into_iter())
.collect(),
ctrlc: self.ctrlc,
is_binary: self.is_binary,
span: self.span,
}
}
}
impl Debug for RawStream {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {