use crate::config::Result;
use crate::ssh::VmSession;
pub const ERROR_PATTERNS: &[&str] = &[
"error[E", "error:", "FAILED", "panic", "fatal error", "unresolved external symbol", "LNK", "cannot find -l", "linker .* not found", "mise ERROR", ];
pub fn dump_build_log_errors(session: &mut VmSession) -> Result<String> {
let log_content = match crate::ssh::exec(session, "cat ~/.testbed-build/build.log 2>/dev/null || echo 'NO_LOG'") {
Ok(output) => output,
Err(_) => return Ok("No build log available".to_string()),
};
if log_content.trim() == "NO_LOG" {
return Ok("No build log available".to_string());
}
extract_errors(&log_content)
}
pub fn extract_errors(log: &str) -> Result<String> {
let lines: Vec<&str> = log.lines().collect();
let mut errors = Vec::new();
for (i, line) in lines.iter().enumerate() {
if ERROR_PATTERNS.iter().any(|p| {
if p.contains(".*") {
let parts: Vec<&str> = p.split(".*").collect();
parts.len() == 2 && line.contains(parts[0]) && line.contains(parts[1])
} else {
line.contains(p)
}
}) {
let start = i.saturating_sub(2);
let context: Vec<&str> = lines[start..=i].to_vec();
errors.push(context.join("\n"));
}
}
if errors.is_empty() {
return Ok("No error patterns found in build log".to_string());
}
errors.dedup();
let output = errors[..errors.len().min(20)].join("\n---\n");
Ok(format!("Build errors ({} found):\n---\n{}", errors.len(), output))
}