Find all included bom files recursively
This commit is contained in:
		
							parent
							
								
									614b958082
								
							
						
					
					
						commit
						6f81a58a03
					
				| @ -206,3 +206,68 @@ impl BomManagement { | ||||
|             .for_each(|(src, dest)| copy_shared_object(src, dest, dry_run)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// This function will return all included bom files in the order to deal with.
 | ||||
| /// This function operates in such a way: It starts from putting the root bom into a queue,
 | ||||
| /// In each iteration of the loop, it will fetch the first bom from the head of the queue,
 | ||||
| /// Then it find all included files of the bom file. The all included bom files will put into the queue as well as a vector(sorted boms).
 | ||||
| /// The loop will end if there's no more elements in the queue.
 | ||||
| /// There is also a max_iteration bound. If the loop exceeds the bound and the queue is not empty, the function will abort the program.
 | ||||
| /// Because excess of the bound often means there's a reference cycles in the bom tree, which is an invalid case.
 | ||||
| /// After we visit all boms in the queue, we will get all boms sorted in the order of being included in the vector.
 | ||||
| /// Then we will remove redudant boms in the vector. For a bom file that may exist more than one time,
 | ||||
| /// only the last one will be kept in the final result. To remove redundancy, we will reverse the vector,
 | ||||
| /// and only keep the first one for each duplicate bom.
 | ||||
| fn find_all_included_bom_files(bom_file: &str, included_dirs: &Vec<String>) -> Vec<String> { | ||||
|     let mut boms = VecDeque::new(); | ||||
|     let mut sorted_boms = Vec::new(); | ||||
|     const MAX_ITERATION: usize = 100; | ||||
| 
 | ||||
|     boms.push_back(bom_file.to_string()); | ||||
|     sorted_boms.push(bom_file.to_string()); | ||||
|     for _ in 0..MAX_ITERATION { | ||||
|         if boms.is_empty() { | ||||
|             break; | ||||
|         } | ||||
|         // This unwrap can never fail
 | ||||
|         let current_bom = boms.pop_front().unwrap(); | ||||
|         let bom = Bom::from_yaml_file(¤t_bom); | ||||
|         // find includes for current bom
 | ||||
|         if let Some(includes) = bom.includes { | ||||
|             includes.into_iter().for_each(|include| { | ||||
|                 let included_bom_file = | ||||
|                     find_included_bom_file(&include, ¤t_bom, included_dirs); | ||||
|                 boms.push_back(included_bom_file.clone()); | ||||
|                 sorted_boms.push(included_bom_file); | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|     if !boms.is_empty() { | ||||
|         // The iteration exceeds the MAX_ITERATION and there still are elements in the queue.
 | ||||
|         error!("The bom file number exceeds the MAX_ITERATION bound. Please check if there is including cycle."); | ||||
|         std::process::exit(INVALID_BOM_FILE_ERROR); | ||||
|     } | ||||
|     // remove redundant boms in sorted boms
 | ||||
|     sorted_boms.reverse(); | ||||
|     let mut res = remove_redundant_items_in_vec(&sorted_boms, Vec::new().iter()); | ||||
|     res.reverse(); | ||||
|     res | ||||
| } | ||||
| 
 | ||||
| // remove redundant items in a vec. For duplicate items, only the first item will be reserved
 | ||||
| fn remove_redundant_items_in_vec<T>(raw: &Vec<T>, excludes: Iter<'_, T>) -> Vec<T> | ||||
| where | ||||
|     T: Hash + Eq + Clone, | ||||
| { | ||||
|     let mut exists = HashSet::new(); | ||||
|     for item in excludes { | ||||
|         exists.insert(item.clone()); | ||||
|     } | ||||
|     let mut res = Vec::new(); | ||||
|     for item in raw { | ||||
|         if exists.insert(item.clone()) { | ||||
|             res.push(item.clone()); | ||||
|         } | ||||
|     } | ||||
|     res | ||||
| } | ||||
|  | ||||
							
								
								
									
										45
									
								
								tools/copy_bom/src/util.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										45
									
								
								tools/copy_bom/src/util.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| use crate::error::{ | ||||
|     COPY_DIR_ERROR, COPY_FILE_ERROR, CREATE_DIR_ERROR, CREATE_SYMLINK_ERROR, FILE_NOT_EXISTS_ERROR, | ||||
|     INCORRECT_HASH_ERROR, | ||||
| }; | ||||
| use data_encoding::HEXUPPER; | ||||
| use regex::Regex; | ||||
| use sha2::{Digest, Sha256}; | ||||
| use std::collections::{HashMap, HashSet}; | ||||
| use std::path::PathBuf; | ||||
| use std::process::{Command, Output}; | ||||
| use std::vec; | ||||
| 
 | ||||
| /// find an included file in the file system. If we can find the bom file, return the path
 | ||||
| /// otherwise, the process exit with error
 | ||||
| /// if included dir is relative path, if will be viewed as path relative to the `current` path (where we execute command)
 | ||||
| pub fn find_included_bom_file( | ||||
|     included_file: &str, | ||||
|     bom_file: &str, | ||||
|     included_dirs: &Vec<String>, | ||||
| ) -> String { | ||||
|     let bom_file_path = PathBuf::from(bom_file); | ||||
|     let bom_file_dir_path = bom_file_path | ||||
|         .parent() | ||||
|         .map_or(PathBuf::from("."), |p| p.to_path_buf()); | ||||
|     // first, we find the included bom file in the current dir of the bom file
 | ||||
|     let included_file_path = bom_file_dir_path.join(included_file); | ||||
|     if included_file_path.is_file() { | ||||
|         return included_file_path.to_string_lossy().to_string(); | ||||
|     } | ||||
|     // Then, we find the bom file in each included dir.
 | ||||
|     for included_dir in included_dirs { | ||||
|         let included_dir_path = std::env::current_dir().unwrap().join(included_dir); | ||||
|         let included_file_path = included_dir_path.join(included_file); | ||||
|         if included_file_path.is_file() { | ||||
|             return included_file_path.to_string_lossy().to_string(); | ||||
|         } | ||||
|     } | ||||
|     // fail to find the bom file
 | ||||
|     error!( | ||||
|         "cannot find included bom file {} in {}.", | ||||
|         included_file, bom_file | ||||
|     ); | ||||
|     std::process::exit(FILE_NOT_EXISTS_ERROR); | ||||
| } | ||||
| 
 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user