opentitanlib/util/
printer.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use anyhow::Result;
6use std::io::Read;
7use std::sync::{Arc, Mutex};
8
9// If the logger is configured to use the module's path, the log message will always
10// look like `[<timestamp> INFO ...util::printer] <message>` which is inconvenient
11// because we loose the source of the message.
12// However, if the logger is configured to print the target instead of the module path
13// then it will look like `[<timestamp> INFO <target>] <message>`. Since the default
14// target is the module's path, this allows for a non-breaking change by configuring
15// the logger to always print the target instead of the module.
16
17// Accumulates output from a process's `stdout`.
18pub fn accumulate(stdout: impl Read, target: &str, accumulator: Arc<Mutex<String>>) {
19    if let Err(e) = worker(stdout, target, accumulator) {
20        log::error!("accumulate error: {:?}", e);
21    }
22}
23
24fn worker(mut stdout: impl Read, target: &str, accumulator: Arc<Mutex<String>>) -> Result<()> {
25    let mut s = String::default();
26    loop {
27        read(&mut stdout, &mut s)?;
28        let mut lines = s.split('\n').collect::<Vec<&str>>();
29        let next = if !s.ends_with('\n') {
30            // If we didn't read a complete line at the end, save it for the
31            // next read.
32            lines.pop()
33        } else {
34            None
35        };
36        for line in lines {
37            // see comment at the top of this module
38            log::info!(target: target, "{}", line.trim_end_matches('\r'));
39        }
40        accumulator.lock().unwrap().push_str(&s);
41        s = next.unwrap_or("").to_string();
42    }
43}
44
45fn read(stdout: &mut impl Read, s: &mut String) -> Result<()> {
46    let mut buf = [0u8; 256];
47    let n = stdout.read(&mut buf)?;
48    s.push_str(&String::from_utf8_lossy(&buf[..n]));
49    Ok(())
50}