use crate::util::first_path_from_str;
use std::{io, path::PathBuf};
use super::BuildKind;
pub fn locate_failure_log(
kind: BuildKind,
log_file: Option<&PathBuf>,
) -> Result<(), Box<dyn std::error::Error>> {
let logfile_content: String = match log_file {
Some(file) => {
log::info!("Reading log file: {file:?}");
if !file.exists() {
return Err(format!("File: {file:?} does not exist",).into());
}
std::fs::read_to_string(file)?
},
None => {
log::info!("Reading log from stdin");
let stdin = io::stdin();
let mut handle = stdin.lock();
let mut buf = String::new();
io::Read::read_to_string(&mut handle, &mut buf)?;
buf
},
};
match kind {
BuildKind::Yocto => locate_yocto_failure_log(&logfile_content)?,
BuildKind::Other => todo!("This feature is not implemented yet!"),
}
Ok(())
}
pub fn locate_yocto_failure_log(logfile_content: &str) -> Result<(), Box<dyn std::error::Error>> {
use crate::err_msg_parse::yocto_err::util;
use std::io::Write;
log::trace!("Finding failure log in log file contents: {logfile_content}");
let error_summary = util::yocto_error_summary(logfile_content)?;
let error_summary = util::trim_trailing_just_recipes(&error_summary)?;
log::trace!("Trimmed error summary: {error_summary}");
let log_file_line = util::find_yocto_failure_log_str(&error_summary)?;
let path = logfile_path_from_str(log_file_line)?;
crate::macros::pipe_print!("{}", path.to_string_lossy())?;
Ok(())
}
pub fn logfile_path_from_str(s: &str) -> Result<PathBuf, Box<dyn std::error::Error>> {
let path = first_path_from_str(s)?;
log::debug!("Searching for logfile from path: {path:?}");
if path.exists() {
return canonicalize_if_file(path);
}
let mut parts = path.components().collect::<Vec<_>>();
log::debug!("File not found, looking for file using parts: {parts:?}");
for _ in 0..parts.len() {
parts.remove(0);
let tmp_path = parts.iter().collect::<PathBuf>();
log::debug!("Looking for file at path: {tmp_path:?}");
if tmp_path.exists() {
return canonicalize_if_file(tmp_path);
}
let tmp_path_from_root = PathBuf::from("/").join(tmp_path);
log::debug!("Looking for file at path: {tmp_path_from_root:?}");
if tmp_path_from_root.exists() {
return canonicalize_if_file(tmp_path_from_root);
}
}
Err(format!("No file found at path: {s}").into())
}
fn canonicalize_if_file(path: PathBuf) -> Result<PathBuf, Box<dyn std::error::Error>> {
if path.is_file() {
return Ok(path.canonicalize()?);
}
Err(format!("No file found at path: {path:?}").into())
}
#[cfg(test)]
mod tests {
use super::*;
use temp_dir::TempDir;
#[test]
fn test_logfile_path_from_str_simple() {
let dir = TempDir::new().unwrap();
let dir_file = dir.child("test.log");
let tmp_log_file = dir_file.as_path();
let test_log_str = format!(
"ERROR: Logfile of failure stored in: /app{real_location}",
real_location = tmp_log_file.to_string_lossy()
);
std::fs::write(tmp_log_file, &test_log_str).unwrap();
let path = logfile_path_from_str(&test_log_str).unwrap();
assert_eq!(path, tmp_log_file);
}
#[test]
fn test_logfile_path_from_str() {
let dir = TempDir::new().unwrap();
let real_path_str =
r#"yocto/build/tmp/work/x86_64-linux/sqlite3-native/3.43.2/temp/log.do_fetch.21616"#;
let path_to_log = dir.path().join(real_path_str);
std::fs::create_dir_all(path_to_log.parent().unwrap()).unwrap();
let test_log_str = format!(
r"other contents
ERROR: Logfile of failure stored in: /app{real_location} other contents
other contents",
real_location = &path_to_log.to_string_lossy()
);
std::fs::write(&path_to_log, &test_log_str).unwrap();
let path = logfile_path_from_str(&test_log_str).unwrap();
assert_eq!(path, path_to_log);
}
}