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