Skip to content

Commit e5e93e4

Browse files
Stream stdout and stderr (#699)
Bazel outputs its final summary to stdout, but progress logs to stderr. With stdout>stderr, we end up logging the summary above the progress. Even worse, since we pipe it to a variable before printing, we end up sitting there doing nothing while waiting for the subcommand to print, and then dump the whole thing to the screen. This is fine if you're letting it run and not watching, but is a spooky experience if you are watching. Thus, we switch to passing both streams out directly, which also nicely interleaves them the way bazel expects.
1 parent 14e493e commit e5e93e4

File tree

2 files changed

+36
-17
lines changed

2 files changed

+36
-17
lines changed

cli-tests/src/test.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -613,9 +613,9 @@ async fn test_command_can_print_subcommand_output_with_special_characters() {
613613
.command()
614614
.assert()
615615
.success()
616-
.stderr(predicate::str::contains("Firstline"))
617-
.stderr(predicate::str::contains("AfterNewline"))
618-
.stderr(predicate::str::contains(" indented"));
616+
.stdout(predicate::str::contains("Firstline"))
617+
.stdout(predicate::str::contains("AfterNewline"))
618+
.stdout(predicate::str::contains("\r\tindented"));
619619
}
620620

621621
#[tokio::test(flavor = "multi_thread")]
@@ -640,7 +640,7 @@ async fn test_command_can_print_subcommand_output_with_faux_html() {
640640
.command()
641641
.assert()
642642
.success()
643-
.stderr(predicate::str::contains(
643+
.stdout(predicate::str::contains(
644644
"<head>This breaks superconsole</head>",
645645
));
646646
}

cli/src/test_command.rs

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,22 @@ use crate::{
2121
upload_command::{run_upload, UploadArgs, UploadRunResult},
2222
};
2323

24+
enum RunOutput {
25+
Title,
26+
}
27+
impl EndOutput for RunOutput {
28+
fn output(&self) -> anyhow::Result<Vec<Line>> {
29+
match self {
30+
RunOutput::Title => Ok(vec![
31+
Line::from_iter([Span::new_styled(
32+
String::from("📒 Test command outputs").attribute(Attribute::Bold),
33+
)?]),
34+
Line::default(),
35+
]),
36+
}
37+
}
38+
}
39+
2440
#[derive(Args, Clone, Debug)]
2541
pub struct TestArgs {
2642
#[command(flatten)]
@@ -80,14 +96,14 @@ impl EndOutput for TestRunResult {
8096
Line::default(),
8197
]);
8298

83-
for stdout_line in lines_of(self.command_stdout.clone()) {
84-
output.push(Line::from_iter([Span::new_unstyled_lossy(stdout_line)]));
99+
for stderr_line in lines_of(self.command_stderr.clone()) {
100+
output.push(Line::from_iter([Span::new_unstyled_lossy(stderr_line)]));
85101
}
86102

87103
output.push(Line::default());
88104

89-
for stderr_line in lines_of(self.command_stderr.clone()) {
90-
output.push(Line::from_iter([Span::new_unstyled_lossy(stderr_line)]));
105+
for stdout_line in lines_of(self.command_stdout.clone()) {
106+
output.push(Line::from_iter([Span::new_unstyled_lossy(stdout_line)]));
91107
}
92108

93109
Ok(output)
@@ -102,12 +118,7 @@ pub async fn run_test(
102118
render_sender: Sender<DisplayMessage>,
103119
) -> anyhow::Result<UploadRunResult> {
104120
let token = upload_args.token.clone();
105-
let mut test_run_result = run_test_command(&command).await?;
106-
let run_result_ptr = Arc::new(test_run_result.clone());
107-
send_message(
108-
DisplayMessage::Final(run_result_ptr, String::from("test output")),
109-
&render_sender,
110-
);
121+
let mut test_run_result = run_test_command(&command, render_sender.clone()).await?;
111122
let test_context = gather_initial_test_context(
112123
upload_args.clone(),
113124
gather_debug_props(env::args().collect::<Vec<String>>(), token),
@@ -140,8 +151,16 @@ pub async fn run_test(
140151
}
141152
}
142153

143-
pub async fn run_test_command<T: AsRef<str>>(command: &[T]) -> anyhow::Result<TestRunResult> {
154+
pub async fn run_test_command<T: AsRef<str>>(
155+
command: &[T],
156+
render_sender: Sender<DisplayMessage>,
157+
) -> anyhow::Result<TestRunResult> {
144158
let exec_start = SystemTime::now();
159+
let title_ptr = Arc::new(RunOutput::Title);
160+
send_message(
161+
DisplayMessage::Final(title_ptr, String::from("test command title")),
162+
&render_sender,
163+
);
145164
let child = Command::new(command.first().map(|s| s.as_ref()).unwrap_or_default())
146165
.args(
147166
command
@@ -150,8 +169,8 @@ pub async fn run_test_command<T: AsRef<str>>(command: &[T]) -> anyhow::Result<Te
150169
.map(|s| s.as_ref())
151170
.collect::<Vec<_>>(),
152171
)
153-
.stdout(Stdio::piped())
154-
.stderr(Stdio::piped())
172+
.stdout(Stdio::inherit())
173+
.stderr(Stdio::inherit())
155174
.spawn()?;
156175
let exit_result = child.wait_with_output().map_err(|e| {
157176
tracing::warn!("Error waiting for execution: {}", e);

0 commit comments

Comments
 (0)