If `input`, write it to `child`'s stdin while also reading `child`'s stdout and stderr, then wait on `child` and return its status and output. This was lifted from `std::process::Child::wait_with_output` and modified to also write to stdin.
(
mut child: process::Child,
input: Option<Vec<u8>>,
timeout: Option<std::time::Duration>,
)
| 454 | /// This was lifted from `std::process::Child::wait_with_output` and modified |
| 455 | /// to also write to stdin. |
| 456 | fn wait_with_input_output( |
| 457 | mut child: process::Child, |
| 458 | input: Option<Vec<u8>>, |
| 459 | timeout: Option<std::time::Duration>, |
| 460 | ) -> io::Result<process::Output> { |
| 461 | #![allow(clippy::unwrap_used, reason = "changes behavior in some tests")] |
| 462 | |
| 463 | fn read<R>(mut input: R) -> std::thread::JoinHandle<io::Result<Vec<u8>>> |
| 464 | where |
| 465 | R: Read + Send + 'static, |
| 466 | { |
| 467 | std::thread::spawn(move || { |
| 468 | let mut ret = Vec::new(); |
| 469 | input.read_to_end(&mut ret).map(|_| ret) |
| 470 | }) |
| 471 | } |
| 472 | |
| 473 | let stdin = input.and_then(|i| { |
| 474 | child |
| 475 | .stdin |
| 476 | .take() |
| 477 | .map(|mut stdin| std::thread::spawn(move || stdin.write_all(&i))) |
| 478 | }); |
| 479 | let stdout = child.stdout.take().map(read); |
| 480 | let stderr = child.stderr.take().map(read); |
| 481 | |
| 482 | // Finish writing stdin before waiting, because waiting drops stdin. |
| 483 | stdin.and_then(|t| t.join().unwrap().ok()); |
| 484 | let status = if let Some(timeout) = timeout { |
| 485 | wait_timeout::ChildExt::wait_timeout(&mut child, timeout) |
| 486 | .transpose() |
| 487 | .unwrap_or_else(|| { |
| 488 | let _ = child.kill(); |
| 489 | child.wait() |
| 490 | }) |
| 491 | } else { |
| 492 | child.wait() |
| 493 | }?; |
| 494 | |
| 495 | let stdout = stdout |
| 496 | .and_then(|t| t.join().unwrap().ok()) |
| 497 | .unwrap_or_default(); |
| 498 | let stderr = stderr |
| 499 | .and_then(|t| t.join().unwrap().ok()) |
| 500 | .unwrap_or_default(); |
| 501 | |
| 502 | Ok(process::Output { |
| 503 | status, |
| 504 | stdout, |
| 505 | stderr, |
| 506 | }) |
| 507 | } |
| 508 | |
| 509 | fn spawn(&mut self) -> io::Result<process::Child> { |
| 510 | // stdout/stderr should only be piped for `output` according to `process::Command::new`. |