Revert "Throw out error if external command in subexpression is failed to run (#8204)" (#8475)

This reverts commit dec0a2517f.

It breaks programs like `fzf`

# Description

Fixes: #8472 
Fixes:  #8313
Reopen: #7690 

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# 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

> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```

# 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:
WindSoilder
2023-03-17 02:07:32 +08:00
committed by GitHub
parent 222c0f11c3
commit 31d9c0889c
3 changed files with 19 additions and 126 deletions

View File

@ -537,7 +537,7 @@ impl PipelineData {
// Only need ExternalStream without redirecting output.
// It indicates we have no more commands to execute currently.
if let PipelineData::ExternalStream {
stdout,
stdout: None,
stderr,
mut exit_code,
span,
@ -548,54 +548,22 @@ impl PipelineData {
let exit_code = exit_code.take();
// Note:
// use a thread to receive stderr message.
// Or we may get a deadlock if child process sends out too much bytes to stdout.
// In run-external's implementation detail, the result sender thread
// send out stderr message first, then stdout message, then exit_code.
//
// For example: in normal linux system, stdout pipe's limit is 65535 bytes.
// if child process sends out 65536 bytes, the process will be hanged because no consumer
// consumes the first 65535 bytes
// So we need a thread to receive stderr message, then the current thread can continue to consume
// stdout messages.
let stderr_handler = stderr.map(|stderr| {
let stderr_span = stderr.span;
let stderr_ctrlc = stderr.ctrlc.clone();
(
thread::Builder::new()
.name("stderr consumer".to_string())
.spawn(move || {
stderr
.into_bytes()
.map(|bytes| bytes.item)
.unwrap_or_default()
})
.expect("failed to create thread"),
stderr_span,
stderr_ctrlc,
)
});
let stdout = stdout.map(|stdout_stream| {
let stdout_ctrlc = stdout_stream.ctrlc.clone();
let stdout_span = stdout_stream.span;
let stdout_bytes = stdout_stream
// 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 = stderr_stream
.into_bytes()
.map(|bytes| bytes.item)
.unwrap_or_default();
RawStream::new(
Box::new(vec![Ok(stdout_bytes)].into_iter()),
stdout_ctrlc,
stdout_span,
None,
)
});
let stderr = stderr_handler.map(|(handler, stderr_span, stderr_ctrlc)| {
let stderr_bytes = handler
.join()
.map_err(|err| ShellError::ExternalCommand {
label: "Fail to receive external commands stderr message".to_string(),
help: format!("{err:?}"),
span: stderr_span,
})
.unwrap_or_default();
RawStream::new(
Box::new(vec![Ok(stderr_bytes)].into_iter()),
stderr_ctrlc,
@ -603,6 +571,7 @@ impl PipelineData {
None,
)
});
match exit_code {
Some(exit_code_stream) => {
let ctrlc = exit_code_stream.ctrlc.clone();
@ -615,7 +584,7 @@ impl PipelineData {
}
(
PipelineData::ExternalStream {
stdout,
stdout: None,
stderr,
exit_code: Some(ListStream::from_stream(exit_code.into_iter(), ctrlc)),
span,
@ -627,7 +596,7 @@ impl PipelineData {
}
None => (
PipelineData::ExternalStream {
stdout,
stdout: None,
stderr,
exit_code: None,
span,