ci_manager/err_parse/yocto/
util.rs1use crate::*;
2
3#[derive(
4 Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Display, EnumString, EnumIter,
5)]
6pub enum YoctoFailureKind {
7 #[strum(serialize = "do_build")]
9 DoBuild,
10 #[strum(serialize = "do_compile")]
11 DoCompile,
12 #[strum(serialize = "do_compile_ptest_base")]
13 DoCompilePtestBase,
14 #[strum(serialize = "do_configure")]
15 DoConfigure,
16 #[strum(serialize = "do_configure_ptest_base")]
17 DoConfigurePtestBase,
18 #[strum(serialize = "do_deploy")]
19 DoDeploy,
20 #[strum(serialize = "do_fetch")]
22 DoFetch,
23 #[strum(serialize = "do_rootfs")]
24 DoRootFs,
25 #[strum(serialize = "do_image")]
26 DoImage,
27 #[default]
29 #[strum(serialize = "misc")]
30 Misc,
31}
32
33impl YoctoFailureKind {
34 pub fn parse_from_logfilename(fname: &str) -> Result<Self> {
48 for variant in YoctoFailureKind::iter() {
49 let variant_as_str = variant.to_string();
50 if fname.contains(&variant_as_str) {
51 return Ok(variant);
52 }
53 }
54 bail!("Could not determine task from input: {fname}")
55 }
56}
57
58pub fn yocto_error_summary(log: &str) -> Result<String> {
60 const YOCTO_ERROR_SUMMARY_SIGNATURE: &str = "--- Error summary ---";
61 let error_summary = log
62 .split(YOCTO_ERROR_SUMMARY_SIGNATURE)
63 .collect::<Vec<&str>>()
64 .pop()
65 .context("No error summary found")?;
66 Ok(error_summary.trim().to_string())
67}
68
69pub fn trim_trailing_just_recipes(log: &str) -> Result<String> {
72 let trimmed = log
73 .lines()
74 .rev()
75 .skip_while(|line| {
76 line.starts_with("error: Recipe ")
77 || line.starts_with("##[error]Process completed with exit code")
79 })
80 .collect::<Vec<&str>>()
81 .iter()
82 .rev()
83 .fold(String::with_capacity(log.len()), |acc, line| {
84 acc + line + "\n"
85 });
86 Ok(trimmed)
87}
88
89pub fn find_yocto_failure_log_str(log: &str) -> Result<&str> {
106 let log_file_line = log
107 .lines()
108 .find(|line| line.contains("Logfile of failure stored in"))
109 .context("No log file line found")?;
110
111 Ok(log_file_line)
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117 use pretty_assertions::assert_eq;
118 use std::str::FromStr;
119
120 const ERROR_SUMMARY_TEST_STR: &str = r#"ERROR: sqlite3-native-3_3.43.2-r0 do_fetch: Bitbake Fetcher Error: MalformedUrl('${SOURCE_MIRROR_URL}')
121 ERROR: Logfile of failure stored in: /app/yocto/build/tmp/work/x86_64-linux/sqlite3-native/3.43.2/temp/log.do_fetch.21616
122 ERROR: Task (virtual:native:/app/yocto/build/../poky/meta/recipes-support/sqlite/sqlite3_3.43.2.bb:do_fetch) failed with exit code '1'
123
124 2024-02-11 00:09:04 - ERROR - Command "/app/yocto/poky/bitbake/bin/bitbake -c build test-template-ci-xilinx-image package-index" failed with error 1"#;
125
126 #[test]
127 fn test_determine_yocto_error_kind() {
128 let task = "do_build";
129 assert_eq!(
130 YoctoFailureKind::from_str(task).unwrap(),
131 YoctoFailureKind::DoBuild
132 );
133 }
134
135 #[test]
136 fn test_yocto_error_from_error_message() {
137 let log_file_line = ERROR_SUMMARY_TEST_STR
139 .lines()
140 .find(|line| line.contains("Logfile of failure stored in"))
141 .ok_or("No log file line found")
142 .unwrap();
143 dbg!(log_file_line);
144 let logfile_path = log_file_line
146 .split("Logfile of failure stored in: ")
147 .collect::<Vec<&str>>()
148 .pop()
149 .ok_or("No log file found");
150
151 let path = std::path::PathBuf::from(logfile_path.unwrap());
152 let fname = path.file_stem().unwrap().to_str().unwrap();
153
154 let yocto_failure = YoctoFailureKind::parse_from_logfilename(fname).unwrap();
155 assert_eq!(yocto_failure, YoctoFailureKind::DoFetch);
156 }
157
158 const TEST_NOT_TRIMMED_YOCTO_ERROR_SUMMARY: &str = r#"ERROR: sqlite3-native-3_3.43.2-r0 do_fetch: Bitbake Fetcher Error: MalformedUrl('${SOURCE_MIRROR_URL}')
159ERROR: Logfile of failure stored in: /app/yocto/build/tmp/work/x86_64-linux/sqlite3-native/3.43.2/temp/log.do_fetch.21665
160ERROR: Task (virtual:native:/app/yocto/build/../poky/meta/recipes-support/sqlite/sqlite3_3.43.2.bb:do_fetch) failed with exit code '1'
161
1622024-02-16 12:45:43 - ERROR - Command "/app/yocto/poky/bitbake/bin/bitbake -c build test-template-ci-xilinx-image package-index" failed with error 1
163error: Recipe `in-container-build-ci-image` failed on line 31 with exit code 2
164error: Recipe `run-in-docker` failed with exit code 2
165error: Recipe `build-ci-image` failed with exit code 2"#;
166
167 const TEST_EXPECT_TRIMMED_YOCTO_ERROR_SUMMARY: &str = r#"ERROR: sqlite3-native-3_3.43.2-r0 do_fetch: Bitbake Fetcher Error: MalformedUrl('${SOURCE_MIRROR_URL}')
168ERROR: Logfile of failure stored in: /app/yocto/build/tmp/work/x86_64-linux/sqlite3-native/3.43.2/temp/log.do_fetch.21665
169ERROR: Task (virtual:native:/app/yocto/build/../poky/meta/recipes-support/sqlite/sqlite3_3.43.2.bb:do_fetch) failed with exit code '1'
170
1712024-02-16 12:45:43 - ERROR - Command "/app/yocto/poky/bitbake/bin/bitbake -c build test-template-ci-xilinx-image package-index" failed with error 1
172"#;
173
174 #[test]
175 pub fn test_trim_yocto_error_summary() {
176 let trimmed = trim_trailing_just_recipes(TEST_NOT_TRIMMED_YOCTO_ERROR_SUMMARY).unwrap();
177 eprintln!("{trimmed}");
178 assert_eq!(trimmed, TEST_EXPECT_TRIMMED_YOCTO_ERROR_SUMMARY);
179 }
180}