From 531683314649b8ee2cb35de5799ee756fa55e758 Mon Sep 17 00:00:00 2001 From: Chris Olszewski Date: Thu, 13 Feb 2025 18:16:52 -0500 Subject: [PATCH] fix(tui): replay all logs sent to tui with forced crlf --- .../src/task_graph/visitor/output.rs | 2 +- crates/turborepo-ui/src/lib.rs | 2 +- crates/turborepo-ui/src/logs.rs | 75 ++++++++++++++++++- 3 files changed, 76 insertions(+), 3 deletions(-) diff --git a/crates/turborepo-lib/src/task_graph/visitor/output.rs b/crates/turborepo-lib/src/task_graph/visitor/output.rs index 958b94efa3667..1aca5b1f8bbc4 100644 --- a/crates/turborepo-lib/src/task_graph/visitor/output.rs +++ b/crates/turborepo-lib/src/task_graph/visitor/output.rs @@ -94,7 +94,7 @@ impl CacheOutput for TaskCacheOutput { let writer = direct.output_prefixed_writer(); turborepo_ui::replay_logs(writer, log_file) } - TaskCacheOutput::UI(task) => turborepo_ui::replay_logs(task, log_file), + TaskCacheOutput::UI(task) => turborepo_ui::replay_logs_with_crlf(task, log_file), } } } diff --git a/crates/turborepo-ui/src/lib.rs b/crates/turborepo-ui/src/lib.rs index f11c4bad65a26..beb417bdd3110 100644 --- a/crates/turborepo-ui/src/lib.rs +++ b/crates/turborepo-ui/src/lib.rs @@ -23,7 +23,7 @@ use thiserror::Error; pub use crate::{ color_selector::ColorSelector, line::LineWriter, - logs::{replay_logs, LogWriter}, + logs::{replay_logs, replay_logs_with_crlf, LogWriter}, output::{OutputClient, OutputClientBehavior, OutputSink, OutputWriter}, prefixed::{PrefixedUI, PrefixedWriter}, tui::{TaskTable, TerminalPane}, diff --git a/crates/turborepo-ui/src/logs.rs b/crates/turborepo-ui/src/logs.rs index 0c4cb5ae339ce..ad49082be9f13 100644 --- a/crates/turborepo-ui/src/logs.rs +++ b/crates/turborepo-ui/src/logs.rs @@ -119,6 +119,48 @@ pub fn replay_logs( Ok(()) } +/// Replay logs, but enforce crlf line endings +// TODO: refactor to share code with `replay_logs` +pub fn replay_logs_with_crlf( + mut output: W, + log_file_name: &AbsoluteSystemPath, +) -> Result<(), Error> { + debug!("start replaying logs"); + + let log_file = File::open(log_file_name).map_err(|err| { + warn!("error opening log file: {:?}", err); + Error::CannotReadLogs(err) + })?; + + let mut log_reader = BufReader::new(log_file); + + let mut buffer = Vec::new(); + loop { + let num_bytes = log_reader + .read_until(b'\n', &mut buffer) + .map_err(Error::CannotReadLogs)?; + if num_bytes == 0 { + break; + } + + let line_without_lf = buffer.strip_suffix(b"\n").unwrap_or(&buffer); + let line_without_crlf = line_without_lf + .strip_suffix(b"\r") + .unwrap_or(line_without_lf); + + output + .write_all(line_without_crlf) + .map_err(Error::CannotReadLogs)?; + output.write_all(b"\r\n").map_err(Error::CannotReadLogs)?; + + buffer.clear(); + } + + debug!("finish replaying logs"); + + Ok(()) +} + #[cfg(test)] mod tests { use std::{fs, io::Write}; @@ -128,7 +170,8 @@ mod tests { use turbopath::AbsoluteSystemPathBuf; use crate::{ - logs::replay_logs, ColorConfig, LogWriter, PrefixedUI, PrefixedWriter, BOLD, CYAN, + logs::replay_logs, replay_logs_with_crlf, ColorConfig, LogWriter, PrefixedUI, + PrefixedWriter, BOLD, CYAN, }; #[test] @@ -207,4 +250,34 @@ mod tests { assert_eq!(output, [b'>', 0, 159, 146, 150, b'\n']); Ok(()) } + + #[test] + fn test_replay_logs_crlf() -> Result<()> { + let dir = tempdir()?; + let log_file_path = AbsoluteSystemPathBuf::try_from(dir.path().join("test.txt"))?; + fs::write(&log_file_path, "\none fish\ntwo fish\nred fish\nblue fish")?; + let mut output = Vec::new(); + replay_logs_with_crlf(&mut output, &log_file_path)?; + let output_str = std::str::from_utf8(&output)?; + assert_eq!( + output_str, + "\r\none fish\r\ntwo fish\r\nred fish\r\nblue fish\r\n" + ); + + Ok(()) + } + + #[test] + fn test_replay_logs_crlf_noop() -> Result<()> { + let dir = tempdir()?; + let log_file_path = AbsoluteSystemPathBuf::try_from(dir.path().join("test.txt"))?; + let contents = "\r\none fish\r\ntwo fish\r\nred fish\r\nblue fish\r\n"; + fs::write(&log_file_path, contents)?; + let mut output = Vec::new(); + replay_logs_with_crlf(&mut output, &log_file_path)?; + let output_str = std::str::from_utf8(&output)?; + assert_eq!(output_str, contents,); + + Ok(()) + } }