forked from libre-chip/fayalite
support redirecting subprocesses' stdout/stderr to print!() so it gets captured for rust tests
This commit is contained in:
parent
f32c0a7863
commit
efc3a539ed
6 changed files with 116 additions and 24 deletions
|
@ -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
|
||||
|
|
|
@ -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<String>,
|
||||
#[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<process::ExitStatus> {
|
||||
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 {
|
||||
|
|
|
@ -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};
|
||||
|
|
31
crates/fayalite/src/util/streaming_read_utf8.rs
Normal file
31
crates/fayalite/src/util/streaming_read_utf8.rs
Normal file
|
@ -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<R: BufRead, E: From<io::Error>>(
|
||||
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(())
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue