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)); |             .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