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