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

@ -54,10 +54,13 @@ pub fn parse_int() {
assert!(expressions.len() == 1);
assert!(matches!(
expressions[0],
PipelineElement::Expression(Expression {
expr: Expr::Int(3),
..
})
PipelineElement::Expression(
_,
Expression {
expr: Expr::Int(3),
..
}
)
))
}
@ -72,7 +75,7 @@ pub fn parse_binary_with_hex_format() {
assert!(block.len() == 1);
let expressions = &block[0];
assert!(expressions.len() == 1);
if let PipelineElement::Expression(expr) = &expressions[0] {
if let PipelineElement::Expression(_, expr) = &expressions[0] {
assert_eq!(expr.expr, Expr::Binary(vec![0x13]))
} else {
panic!("Not an expression")
@ -90,7 +93,7 @@ pub fn parse_binary_with_incomplete_hex_format() {
assert!(block.len() == 1);
let expressions = &block[0];
assert!(expressions.len() == 1);
if let PipelineElement::Expression(expr) = &expressions[0] {
if let PipelineElement::Expression(_, expr) = &expressions[0] {
assert_eq!(expr.expr, Expr::Binary(vec![0x03]))
} else {
panic!("Not an expression")
@ -108,7 +111,7 @@ pub fn parse_binary_with_binary_format() {
assert!(block.len() == 1);
let expressions = &block[0];
assert!(expressions.len() == 1);
if let PipelineElement::Expression(expr) = &expressions[0] {
if let PipelineElement::Expression(_, expr) = &expressions[0] {
assert_eq!(expr.expr, Expr::Binary(vec![0b10101000]))
} else {
panic!("Not an expression")
@ -126,7 +129,7 @@ pub fn parse_binary_with_incomplete_binary_format() {
assert!(block.len() == 1);
let expressions = &block[0];
assert!(expressions.len() == 1);
if let PipelineElement::Expression(expr) = &expressions[0] {
if let PipelineElement::Expression(_, expr) = &expressions[0] {
assert_eq!(expr.expr, Expr::Binary(vec![0b00000010]))
} else {
panic!("Not an expression")
@ -144,7 +147,7 @@ pub fn parse_binary_with_octal_format() {
assert!(block.len() == 1);
let expressions = &block[0];
assert!(expressions.len() == 1);
if let PipelineElement::Expression(expr) = &expressions[0] {
if let PipelineElement::Expression(_, expr) = &expressions[0] {
assert_eq!(expr.expr, Expr::Binary(vec![0o250]))
} else {
panic!("Not an expression")
@ -162,7 +165,7 @@ pub fn parse_binary_with_incomplete_octal_format() {
assert!(block.len() == 1);
let expressions = &block[0];
assert!(expressions.len() == 1);
if let PipelineElement::Expression(expr) = &expressions[0] {
if let PipelineElement::Expression(_, expr) = &expressions[0] {
assert_eq!(expr.expr, Expr::Binary(vec![0o2]))
} else {
panic!("Not an expression")
@ -180,7 +183,7 @@ pub fn parse_binary_with_invalid_octal_format() {
assert!(block.len() == 1);
let expressions = &block[0];
assert!(expressions.len() == 1);
if let PipelineElement::Expression(expr) = &expressions[0] {
if let PipelineElement::Expression(_, expr) = &expressions[0] {
assert!(!matches!(&expr.expr, Expr::Binary(_)))
} else {
panic!("Not an expression")
@ -200,7 +203,7 @@ pub fn parse_binary_with_multi_byte_char() {
assert!(block.len() == 1);
let expressions = &block[0];
assert!(expressions.len() == 1);
if let PipelineElement::Expression(expr) = &expressions[0] {
if let PipelineElement::Expression(_, expr) = &expressions[0] {
assert!(!matches!(&expr.expr, Expr::Binary(_)))
} else {
panic!("Not an expression")
@ -218,7 +221,7 @@ pub fn parse_string() {
assert!(block.len() == 1);
let expressions = &block[0];
assert!(expressions.len() == 1);
if let PipelineElement::Expression(expr) = &expressions[0] {
if let PipelineElement::Expression(_, expr) = &expressions[0] {
assert_eq!(expr.expr, Expr::String("hello nushell".to_string()))
} else {
panic!("Not an expression")
@ -242,7 +245,7 @@ pub fn parse_escaped_string() {
assert!(block.len() == 1);
let expressions = &block[0];
assert!(expressions.len() == 1);
if let PipelineElement::Expression(expr) = &expressions[0] {
if let PipelineElement::Expression(_, expr) = &expressions[0] {
assert_eq!(expr.expr, Expr::String("hello nushell".to_string()))
} else {
panic!("Not an expression")
@ -265,10 +268,13 @@ pub fn parse_call() {
let expressions = &block[0];
assert_eq!(expressions.len(), 1);
if let PipelineElement::Expression(Expression {
expr: Expr::Call(call),
..
}) = &expressions[0]
if let PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) = &expressions[0]
{
assert_eq!(call.decl_id, 0);
}
@ -371,10 +377,13 @@ fn test_nothing_comparisson_eq() {
assert!(expressions.len() == 1);
assert!(matches!(
&expressions[0],
PipelineElement::Expression(Expression {
expr: Expr::BinaryOp(..),
..
})
PipelineElement::Expression(
_,
Expression {
expr: Expr::BinaryOp(..),
..
}
)
))
}
@ -391,10 +400,13 @@ fn test_nothing_comparisson_neq() {
assert!(expressions.len() == 1);
assert!(matches!(
&expressions[0],
PipelineElement::Expression(Expression {
expr: Expr::BinaryOp(..),
..
})
PipelineElement::Expression(
_,
Expression {
expr: Expr::BinaryOp(..),
..
}
)
))
}
@ -416,18 +428,21 @@ mod range {
assert!(expressions.len() == 1);
assert!(matches!(
expressions[0],
PipelineElement::Expression(Expression {
expr: Expr::Range(
Some(_),
None,
Some(_),
RangeOperator {
inclusion: RangeInclusion::Inclusive,
..
}
),
..
})
PipelineElement::Expression(
_,
Expression {
expr: Expr::Range(
Some(_),
None,
Some(_),
RangeOperator {
inclusion: RangeInclusion::Inclusive,
..
}
),
..
}
)
))
}
@ -445,18 +460,21 @@ mod range {
assert!(expressions.len() == 1);
assert!(matches!(
expressions[0],
PipelineElement::Expression(Expression {
expr: Expr::Range(
Some(_),
None,
Some(_),
RangeOperator {
inclusion: RangeInclusion::RightExclusive,
..
}
),
..
})
PipelineElement::Expression(
_,
Expression {
expr: Expr::Range(
Some(_),
None,
Some(_),
RangeOperator {
inclusion: RangeInclusion::RightExclusive,
..
}
),
..
}
)
))
}
@ -474,18 +492,21 @@ mod range {
assert!(expressions.len() == 1);
assert!(matches!(
expressions[0],
PipelineElement::Expression(Expression {
expr: Expr::Range(
Some(_),
None,
Some(_),
RangeOperator {
inclusion: RangeInclusion::Inclusive,
..
}
),
..
})
PipelineElement::Expression(
_,
Expression {
expr: Expr::Range(
Some(_),
None,
Some(_),
RangeOperator {
inclusion: RangeInclusion::Inclusive,
..
}
),
..
}
)
))
}
@ -503,18 +524,21 @@ mod range {
assert!(expressions.len() == 1);
assert!(matches!(
expressions[0],
PipelineElement::Expression(Expression {
expr: Expr::Range(
Some(_),
None,
Some(_),
RangeOperator {
inclusion: RangeInclusion::RightExclusive,
..
}
),
..
})
PipelineElement::Expression(
_,
Expression {
expr: Expr::Range(
Some(_),
None,
Some(_),
RangeOperator {
inclusion: RangeInclusion::RightExclusive,
..
}
),
..
}
)
))
}
@ -534,18 +558,21 @@ mod range {
assert!(expressions.len() == 1);
assert!(matches!(
expressions[0],
PipelineElement::Expression(Expression {
expr: Expr::Range(
Some(_),
None,
Some(_),
RangeOperator {
inclusion: RangeInclusion::Inclusive,
..
}
),
..
})
PipelineElement::Expression(
_,
Expression {
expr: Expr::Range(
Some(_),
None,
Some(_),
RangeOperator {
inclusion: RangeInclusion::Inclusive,
..
}
),
..
}
)
))
}
@ -571,18 +598,21 @@ mod range {
assert!(expressions.len() == 1);
assert!(matches!(
expressions[0],
PipelineElement::Expression(Expression {
expr: Expr::Range(
Some(_),
None,
Some(_),
RangeOperator {
inclusion: RangeInclusion::RightExclusive,
..
}
),
..
})
PipelineElement::Expression(
_,
Expression {
expr: Expr::Range(
Some(_),
None,
Some(_),
RangeOperator {
inclusion: RangeInclusion::RightExclusive,
..
}
),
..
}
)
))
}
@ -600,18 +630,21 @@ mod range {
assert!(expressions.len() == 1);
assert!(matches!(
expressions[0],
PipelineElement::Expression(Expression {
expr: Expr::Range(
Some(_),
None,
None,
RangeOperator {
inclusion: RangeInclusion::Inclusive,
..
}
),
..
})
PipelineElement::Expression(
_,
Expression {
expr: Expr::Range(
Some(_),
None,
None,
RangeOperator {
inclusion: RangeInclusion::Inclusive,
..
}
),
..
}
)
))
}
@ -629,18 +662,21 @@ mod range {
assert!(expressions.len() == 1);
assert!(matches!(
expressions[0],
PipelineElement::Expression(Expression {
expr: Expr::Range(
None,
None,
Some(_),
RangeOperator {
inclusion: RangeInclusion::Inclusive,
..
}
),
..
})
PipelineElement::Expression(
_,
Expression {
expr: Expr::Range(
None,
None,
Some(_),
RangeOperator {
inclusion: RangeInclusion::Inclusive,
..
}
),
..
}
)
))
}
@ -658,18 +694,21 @@ mod range {
assert!(expressions.len() == 1);
assert!(matches!(
expressions[0],
PipelineElement::Expression(Expression {
expr: Expr::Range(
Some(_),
None,
Some(_),
RangeOperator {
inclusion: RangeInclusion::Inclusive,
..
}
),
..
})
PipelineElement::Expression(
_,
Expression {
expr: Expr::Range(
Some(_),
None,
Some(_),
RangeOperator {
inclusion: RangeInclusion::Inclusive,
..
}
),
..
}
)
))
}
@ -687,18 +726,21 @@ mod range {
assert!(expressions.len() == 1);
assert!(matches!(
expressions[0],
PipelineElement::Expression(Expression {
expr: Expr::Range(
Some(_),
Some(_),
Some(_),
RangeOperator {
inclusion: RangeInclusion::Inclusive,
..
}
),
..
})
PipelineElement::Expression(
_,
Expression {
expr: Expr::Range(
Some(_),
Some(_),
Some(_),
RangeOperator {
inclusion: RangeInclusion::Inclusive,
..
}
),
..
}
)
))
}
@ -1032,10 +1074,13 @@ mod input_types {
assert!(expressions.len() == 3);
match &expressions[0] {
PipelineElement::Expression(Expression {
expr: Expr::Call(call),
..
}) => {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set
.find_decl(b"ls", &Type::Any)
.expect("Error merging delta");
@ -1045,10 +1090,13 @@ mod input_types {
}
match &expressions[1] {
PipelineElement::Expression(Expression {
expr: Expr::Call(call),
..
}) => {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set.find_decl(b"to-custom", &Type::Any).unwrap();
assert_eq!(call.decl_id, expected_id)
}
@ -1056,10 +1104,13 @@ mod input_types {
}
match &expressions[2] {
PipelineElement::Expression(Expression {
expr: Expr::Call(call),
..
}) => {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set
.find_decl(b"group-by", &Type::Custom("custom".into()))
.unwrap();
@ -1085,10 +1136,13 @@ mod input_types {
let expressions = &block[2];
match &expressions[1] {
PipelineElement::Expression(Expression {
expr: Expr::Call(call),
..
}) => {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set
.find_decl(b"agg", &Type::Custom("custom".into()))
.unwrap();
@ -1113,10 +1167,13 @@ mod input_types {
let expressions = &block[1];
match &expressions[1] {
PipelineElement::Expression(Expression {
expr: Expr::Call(call),
..
}) => {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set
.find_decl(b"agg", &Type::Custom("custom".into()))
.unwrap();
@ -1142,10 +1199,13 @@ mod input_types {
let expressions = &block[1];
match &expressions[1] {
PipelineElement::Expression(Expression {
expr: Expr::Call(call),
..
}) => {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set.find_decl(b"to-custom", &Type::Any).unwrap();
assert_eq!(call.decl_id, expected_id)
}
@ -1154,10 +1214,13 @@ mod input_types {
let expressions = &block[2];
match &expressions[1] {
PipelineElement::Expression(Expression {
expr: Expr::Call(call),
..
}) => {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set.find_decl(b"to-custom", &Type::Any).unwrap();
assert_eq!(call.decl_id, expected_id)
}
@ -1182,10 +1245,13 @@ mod input_types {
assert!(expressions.len() == 2);
match &expressions[0] {
PipelineElement::Expression(Expression {
expr: Expr::Call(call),
..
}) => {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set.find_decl(b"ls", &Type::Any).unwrap();
assert_eq!(call.decl_id, expected_id)
}
@ -1193,10 +1259,13 @@ mod input_types {
}
match &expressions[1] {
PipelineElement::Expression(Expression {
expr: Expr::Call(call),
..
}) => {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set.find_decl(b"group-by", &Type::Any).unwrap();
assert_eq!(call.decl_id, expected_id)
}
@ -1221,10 +1290,13 @@ mod input_types {
let expressions = &block[0];
match &expressions[3] {
PipelineElement::Expression(Expression {
expr: Expr::Call(call),
..
}) => {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let arg = &call.arguments[0];
match arg {
Argument::Positional(a) => match &a.expr {
@ -1236,10 +1308,13 @@ mod input_types {
assert!(expressions.len() == 2);
match &expressions[1] {
PipelineElement::Expression(Expression {
expr: Expr::Call(call),
..
}) => {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let working_set = StateWorkingSet::new(&engine_state);
let expected_id =
working_set.find_decl(b"min", &Type::Any).unwrap();
@ -1274,10 +1349,13 @@ mod input_types {
let expressions = &block[0];
match &expressions[2] {
PipelineElement::Expression(Expression {
expr: Expr::Call(call),
..
}) => {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set
.find_decl(b"with-column", &Type::Custom("custom".into()))
.unwrap();
@ -1287,10 +1365,13 @@ mod input_types {
}
match &expressions[3] {
PipelineElement::Expression(Expression {
expr: Expr::Call(call),
..
}) => {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set
.find_decl(b"collect", &Type::Custom("custom".into()))
.unwrap();