forked from extern/nushell
avoid freeze when capturing external stderr (#6700)
* avoid freeze when capturing external stderr * try replace from sh to bash * change description * fmt code
This commit is contained in:
@ -37,22 +37,9 @@ impl Command for Complete {
|
||||
let mut cols = vec![];
|
||||
let mut vals = vec![];
|
||||
|
||||
if let Some(stdout) = stdout {
|
||||
cols.push("stdout".to_string());
|
||||
let stdout = stdout.into_bytes()?;
|
||||
if let Ok(st) = String::from_utf8(stdout.item.clone()) {
|
||||
vals.push(Value::String {
|
||||
val: st,
|
||||
span: stdout.span,
|
||||
})
|
||||
} else {
|
||||
vals.push(Value::Binary {
|
||||
val: stdout.item,
|
||||
span: stdout.span,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// the order is important, we need to read
|
||||
// stderr, then stdout, then exit_code
|
||||
// because run_external generate them in this order.
|
||||
if let Some(stderr) = stderr {
|
||||
cols.push("stderr".to_string());
|
||||
let stderr = stderr.into_bytes()?;
|
||||
@ -69,6 +56,22 @@ impl Command for Complete {
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(stdout) = stdout {
|
||||
cols.push("stdout".to_string());
|
||||
let stdout = stdout.into_bytes()?;
|
||||
if let Ok(st) = String::from_utf8(stdout.item.clone()) {
|
||||
vals.push(Value::String {
|
||||
val: st,
|
||||
span: stdout.span,
|
||||
})
|
||||
} else {
|
||||
vals.push(Value::Binary {
|
||||
val: stdout.item,
|
||||
span: stdout.span,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(exit_code) = exit_code {
|
||||
let mut v: Vec<_> = exit_code.collect();
|
||||
|
||||
|
@ -337,6 +337,13 @@ impl ExternalCommand {
|
||||
let mut buf_read = BufReader::with_capacity(OUTPUT_BUFFER_SIZE, stderr);
|
||||
while let Ok(bytes) = buf_read.fill_buf() {
|
||||
if bytes.is_empty() {
|
||||
// drop stderr sender manually, so stderr message consumer
|
||||
// can make sure that there is no more stderr messages.
|
||||
//
|
||||
// and message consumer can continue to wait stdout message.
|
||||
// If we don't make manually drop, and external command produces many
|
||||
// stdout messages, relative message consumer will hang on so we'll get a deadlock.
|
||||
drop(stderr_tx);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -438,11 +445,15 @@ impl ExternalCommand {
|
||||
} else {
|
||||
None
|
||||
},
|
||||
stderr: Some(RawStream::new(
|
||||
Box::new(stderr_receiver),
|
||||
output_ctrlc.clone(),
|
||||
head,
|
||||
)),
|
||||
stderr: if redirect_stderr {
|
||||
Some(RawStream::new(
|
||||
Box::new(stderr_receiver),
|
||||
output_ctrlc.clone(),
|
||||
head,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
exit_code: Some(ListStream::from_stream(
|
||||
Box::new(exit_code_receiver),
|
||||
output_ctrlc,
|
||||
|
Reference in New Issue
Block a user