From efc3a539ed771fcd9ec53a8dc231bc7268224000 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Wed, 25 Sep 2024 01:36:15 -0700 Subject: [PATCH] support redirecting subprocesses' stdout/stderr to print!() so it gets captured for rust tests --- Cargo.lock | 73 +++++++++++++------ Cargo.toml | 1 + crates/fayalite/Cargo.toml | 1 + crates/fayalite/src/cli.rs | 33 ++++++++- crates/fayalite/src/util.rs | 1 + .../fayalite/src/util/streaming_read_utf8.rs | 31 ++++++++ 6 files changed, 116 insertions(+), 24 deletions(-) create mode 100644 crates/fayalite/src/util/streaming_read_utf8.rs diff --git a/Cargo.lock b/Cargo.lock index 1c17ac7..1c237af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,7 +56,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -66,7 +66,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -218,7 +218,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -249,6 +249,7 @@ dependencies = [ "hashbrown", "num-bigint", "num-traits", + "os_pipe", "serde", "serde_json", "trybuild", @@ -334,7 +335,7 @@ version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -413,6 +414,16 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "os_pipe" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "prettyplease" version = "0.2.20" @@ -457,7 +468,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -541,7 +552,7 @@ dependencies = [ "cfg-if", "fastrand", "rustix", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -665,14 +676,24 @@ dependencies = [ ] [[package]] -name = "windows-targets" -version = "0.52.4" +name = "windows-sys" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -681,45 +702,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winsafe" diff --git a/Cargo.toml b/Cargo.toml index 9ee7445..15d13b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ hashbrown = "0.14.3" indexmap = { version = "2.2.6", features = ["serde"] } num-bigint = "0.4.4" num-traits = "0.2.16" +os_pipe = "1.2.1" prettyplease = "0.2.20" proc-macro2 = "1.0.83" quote = "1.0.36" diff --git a/crates/fayalite/Cargo.toml b/crates/fayalite/Cargo.toml index 55a29ad..2306e7a 100644 --- a/crates/fayalite/Cargo.toml +++ b/crates/fayalite/Cargo.toml @@ -21,6 +21,7 @@ fayalite-proc-macros.workspace = true hashbrown.workspace = true num-bigint.workspace = true num-traits.workspace = true +os_pipe.workspace = true serde_json.workspace = true serde.workspace = true which.workspace = true diff --git a/crates/fayalite/src/cli.rs b/crates/fayalite/src/cli.rs index d1bbfb1..1dbf85f 100644 --- a/crates/fayalite/src/cli.rs +++ b/crates/fayalite/src/cli.rs @@ -5,6 +5,7 @@ use crate::{ firrtl, intern::Interned, module::Module, + util::streaming_read_utf8::streaming_read_utf8, }; use clap::{ builder::{OsStringValueParser, TypedValueParser}, @@ -51,6 +52,8 @@ pub struct BaseArgs { /// the stem of the generated main output file, e.g. to get foo.v, pass --file-stem=foo #[arg(long)] pub file_stem: Option, + #[arg(skip = false)] + pub redirect_output_for_rust_test: bool, } impl BaseArgs { @@ -60,6 +63,34 @@ impl BaseArgs { top_fir_file_stem: self.file_stem.clone(), } } + /// handles possibly redirecting the command's output for Rust tests + pub fn run_external_command( + &self, + mut command: process::Command, + ) -> io::Result { + if self.redirect_output_for_rust_test { + let (reader, writer) = os_pipe::pipe()?; + let mut reader = io::BufReader::new(reader); + command.stderr(writer.try_clone()?); + command.stdout(writer); // must not leave writer around after spawning child + command.stdin(process::Stdio::null()); + let mut child = command.spawn()?; + drop(command); // close writers + Ok(loop { + let status = child.try_wait()?; + streaming_read_utf8(&mut reader, |s| { + // use print! so output goes to Rust test output capture + print!("{s}"); + io::Result::Ok(()) + })?; + if let Some(status) = status { + break status; + } + }) + } else { + command.status() + } + } } #[derive(Parser, Debug, Clone)] @@ -188,7 +219,7 @@ impl VerilogArgs { } cmd.args(&self.firtool_extra_args); cmd.current_dir(&self.firrtl.base.output); - let status = cmd.status()?; + let status = self.firrtl.base.run_external_command(cmd)?; if status.success() { Ok(output) } else { diff --git a/crates/fayalite/src/util.rs b/crates/fayalite/src/util.rs index 5b97e3b..95f5793 100644 --- a/crates/fayalite/src/util.rs +++ b/crates/fayalite/src/util.rs @@ -6,6 +6,7 @@ mod const_cmp; mod const_usize; mod misc; mod scoped_ref; +pub(crate) mod streaming_read_utf8; #[doc(inline)] pub use const_bool::{ConstBool, ConstBoolDispatch, ConstBoolDispatchTag, GenericConstBool}; diff --git a/crates/fayalite/src/util/streaming_read_utf8.rs b/crates/fayalite/src/util/streaming_read_utf8.rs new file mode 100644 index 0000000..bd8bdc8 --- /dev/null +++ b/crates/fayalite/src/util/streaming_read_utf8.rs @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information +use std::{ + io::{self, BufRead}, + str, +}; + +pub(crate) fn streaming_read_utf8>( + reader: R, + mut callback: impl FnMut(&str) -> Result<(), E>, +) -> Result<(), E> { + let mut buf = [0; 4]; + let mut buf_len = 0; + for byte in reader.bytes() { + buf[buf_len] = byte?; + buf_len += 1; + match str::from_utf8(&buf[..buf_len]) { + Ok(buf) => { + callback(buf)?; + buf_len = 0; + } + Err(e) => { + if e.error_len().is_some() { + callback("\u{FFFD}")?; // replacement character + buf_len = 0; + } + } + } + } + Ok(()) +}