-
-
Notifications
You must be signed in to change notification settings - Fork 101
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
While adding tests for the libtestjson output, I noticed that my assumption that stdout/stderr ordering would be _mostly_ correct except in "extreme" scenarios was...completely wrong. With even the most simple mixed stdout/stderr output (no multithreading, no unbuffered output, no huge single writes) that the ordering of the output was wrong on my machine more often than not. After playing around with the idea of using a pseudo terminal, similar to how alacritty or other terminal emulators work, I checked the even easier case of...just passing the same file descriptor for both stdout and stderr...which works. Committing this in a separate branch so that I can push and add the Windows implementation before merging this back to the combined output branch.
- Loading branch information
1 parent
8a22794
commit 3a61f35
Showing
7 changed files
with
346 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
use crate::test_output::CaptureStrategy; | ||
use std::process::Stdio; | ||
use tokio::process::{Child as TokioChild, ChildStdout as Pipe}; | ||
|
||
cfg_if::cfg_if! { | ||
if #[cfg(unix)] { | ||
#[path = "unix.rs"] | ||
mod unix; | ||
use unix as os; | ||
} else if #[cfg(windows)] { | ||
#[path = "windows.rs"] | ||
mod windows; | ||
use windows as os; | ||
} else { | ||
compile_error!("unsupported target platform"); | ||
} | ||
} | ||
|
||
pub enum Output { | ||
Split { stdout: Pipe, stderr: Pipe }, | ||
Combined(Pipe), | ||
} | ||
|
||
pub struct Child { | ||
pub child: TokioChild, | ||
pub output: Option<Output>, | ||
} | ||
|
||
impl std::ops::Deref for Child { | ||
type Target = TokioChild; | ||
|
||
fn deref(&self) -> &Self::Target { | ||
&self.child | ||
} | ||
} | ||
|
||
impl std::ops::DerefMut for Child { | ||
fn deref_mut(&mut self) -> &mut Self::Target { | ||
&mut self.child | ||
} | ||
} | ||
|
||
pub(super) fn spawn( | ||
mut cmd: std::process::Command, | ||
strategy: CaptureStrategy, | ||
) -> std::io::Result<Child> { | ||
cmd.stdin(Stdio::null()); | ||
|
||
let state = match strategy { | ||
CaptureStrategy::None => None, | ||
CaptureStrategy::Split => { | ||
cmd.stdout(Stdio::piped()).stderr(Stdio::piped()); | ||
None | ||
} | ||
CaptureStrategy::Combined => Some(os::setup_io(&mut cmd)?), | ||
}; | ||
|
||
let mut cmd: tokio::process::Command = cmd.into(); | ||
let mut child = cmd.spawn()?; | ||
|
||
let output = match strategy { | ||
CaptureStrategy::None => None, | ||
CaptureStrategy::Split => { | ||
let stdout = child.stdout.take().expect("stdout was set"); | ||
let stderr = child.stderr.take().expect("stderr was set"); | ||
let stderr = os::stderr_to_stdout(stderr)?; | ||
|
||
Some(Output::Split { stdout, stderr }) | ||
} | ||
CaptureStrategy::Combined => { | ||
// It doesn't matter which stream we take since they are both the same | ||
// handle, so we take the easy one | ||
Some(Output::Combined(os::state_to_stdout( | ||
state.expect("state was set"), | ||
)?)) | ||
} | ||
}; | ||
|
||
Ok(Child { child, output }) | ||
} |
Oops, something went wrong.