mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 08:16:32 +02:00
refactor: introduce is_external_failed to PipelineData, and simplify try logic (#7476)
# Description Just spot that there are some duplicate code about checking external runs to failed, is pr is trying to refactor it and reduce lines of code # User-Facing Changes NaN # Tests + Formatting Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass # After Submitting If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date.
This commit is contained in:
@ -474,6 +474,91 @@ impl PipelineData {
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to catch external stream exit status and detect if it runs to failed.
|
||||
///
|
||||
/// This is useful to commands with semicolon, we can detect errors early to avoid
|
||||
/// commands after semicolon running.
|
||||
///
|
||||
/// Returns self and a flag indicates if the external stream runs to failed.
|
||||
/// If `self` is not Pipeline::ExternalStream, the flag will be false.
|
||||
pub fn is_external_failed(self) -> (Self, bool) {
|
||||
let mut failed_to_run = false;
|
||||
// Only need ExternalStream without redirecting output.
|
||||
// It indicates we have no more commands to execute currently.
|
||||
if let PipelineData::ExternalStream {
|
||||
stdout: None,
|
||||
stderr,
|
||||
mut exit_code,
|
||||
span,
|
||||
metadata,
|
||||
trim_end_newline,
|
||||
} = self
|
||||
{
|
||||
let exit_code = exit_code.take();
|
||||
|
||||
// Note:
|
||||
// In run-external's implementation detail, the result sender thread
|
||||
// send out stderr message first, then stdout message, then exit_code.
|
||||
//
|
||||
// In this clause, we already make sure that `stdout` is None
|
||||
// But not the case of `stderr`, so if `stderr` is not None
|
||||
// We need to consume stderr message before reading external commands' exit code.
|
||||
//
|
||||
// Or we'll never have a chance to read exit_code if stderr producer produce too much stderr message.
|
||||
// So we consume stderr stream and rebuild it.
|
||||
let stderr = stderr.map(|stderr_stream| {
|
||||
let stderr_ctrlc = stderr_stream.ctrlc.clone();
|
||||
let stderr_span = stderr_stream.span;
|
||||
let stderr_bytes = match stderr_stream.into_bytes() {
|
||||
Err(_) => vec![],
|
||||
Ok(bytes) => bytes.item,
|
||||
};
|
||||
RawStream::new(
|
||||
Box::new(vec![Ok(stderr_bytes)].into_iter()),
|
||||
stderr_ctrlc,
|
||||
stderr_span,
|
||||
)
|
||||
});
|
||||
|
||||
match exit_code {
|
||||
Some(exit_code_stream) => {
|
||||
let ctrlc = exit_code_stream.ctrlc.clone();
|
||||
let exit_code: Vec<Value> = exit_code_stream.into_iter().collect();
|
||||
if let Some(Value::Int { val: code, .. }) = exit_code.last() {
|
||||
// if exit_code is not 0, it indicates error occured, return back Err.
|
||||
if *code != 0 {
|
||||
failed_to_run = true;
|
||||
}
|
||||
}
|
||||
(
|
||||
PipelineData::ExternalStream {
|
||||
stdout: None,
|
||||
stderr,
|
||||
exit_code: Some(ListStream::from_stream(exit_code.into_iter(), ctrlc)),
|
||||
span,
|
||||
metadata,
|
||||
trim_end_newline,
|
||||
},
|
||||
failed_to_run,
|
||||
)
|
||||
}
|
||||
None => (
|
||||
PipelineData::ExternalStream {
|
||||
stdout: None,
|
||||
stderr,
|
||||
exit_code: None,
|
||||
span,
|
||||
metadata,
|
||||
trim_end_newline,
|
||||
},
|
||||
failed_to_run,
|
||||
),
|
||||
}
|
||||
} else {
|
||||
(self, false)
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume and print self data immediately.
|
||||
///
|
||||
/// `no_newline` controls if we need to attach newline character to output.
|
||||
|
Reference in New Issue
Block a user