Hi,
I'm currently writing a wrapper around some nix
commands. Some of these can run for a while, and their only output for large stretches of time is a sort of animated status, looking something like this:
and updating in real time. Depending on the task and machine, this can take 30min+, making it really nice to have something on screen indicating progress, esp. since it's sometimes not clear how long things will take before running the command.
Unfortunately, and for some godforsaken reason I will never understand, nix outputs this to stderr
. I say "unfortunately" because I need to do some filtering on stderr
.
Something like this:
pub(crate) fn run_filtered(&self) -> Result<()> {
let (command, args) = self.get_final_args();
let mut child = Command::new(command)
.args(args)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()?;
Ok(())
}
works perfectly for the first requirement (output everything, incl. the "animated" status), but of course does not allow me to filter anything.
On the other hand, something like
pub(crate) async fn run_filtered(&self) -> Result<()> {
let (command, args) = self.get_final_args();
let mut child = Command::new(command)
.args(args)
.stdout(Stdio::inherit())
.stderr(Stdio::piped())
.spawn()?;
const NEWLINE: u8 = 0xa;
let mut lines = BufReader::new(child.stderr.take().unwrap());
loop {
let mut line = Vec::new();
let len = lines.read_until(NEWLINE, &mut line).await?;
let line = String::from_utf8_lossy(&line);
if len == 0 {
break;
}
// ...do the filtering...
println!("{}", line); // same for print!()
}
Ok(())
}
does the filtering nicely, but I completely loose the "animated" parts (screen just stays blank). I assume this is due to reading until the newline symbol, when the animation is probably just outputting a \r
to update, but replacing the 0xa
with 0xd
or b'\r'
just stops output altogether.
I'm still relatively new to rust, and feel like I've hit my current limit here. If someone could point me in the right direction, I'd really appreciate it