pub(crate) fn read_contents(
    root: &Utf8Path,
    rel_paths: impl IntoIterator<Item = impl AsRef<Utf8Path>>,
) -> Result<(Utf8PathBuf, String)> {
    let mut paths_tried_str = String::new();
    for path in rel_paths {
        let abs_path = root.join(path);
        match std::fs::read_to_string(&abs_path) {
            Ok(contents) => return Ok((abs_path, contents)),
            Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
                // The path wasn't found -- continue to the next one.
                paths_tried_str.push_str("  - ");
                paths_tried_str.push_str(abs_path.as_str());
                paths_tried_str.push('\n');
                continue;
            }
            Err(err) => {
                return Err(err)
                    .wrap_err_with(|| format!("error reading contents at {}", abs_path));
            }
        }
    }

    bail!("none of these paths were found:\n{}", paths_tried_str)
}
Read the contents of the first file that matches and is present. Errors out.
tools/cargo-hakari/src/helpers.rs