mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-08 21:06:48 +00:00
214 lines
7.3 KiB
Rust
214 lines
7.3 KiB
Rust
use std::{collections::HashMap, fs::File, io::Read, ops::Add, process::Command, str::FromStr};
|
|
|
|
use json::JsonValue;
|
|
use proc_macro2::{Group, TokenStream};
|
|
use quote::{ToTokens, TokenStreamExt};
|
|
|
|
use crate::COMPONENT_FILE_NAME;
|
|
|
|
#[derive(Debug)]
|
|
pub struct ComponentInfo {
|
|
name: String,
|
|
path: String,
|
|
priority: u16,
|
|
}
|
|
|
|
impl ToTokens for ComponentInfo {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
let token = TokenStream::from_str(
|
|
format!("\"{}\",\"{}\",{}", self.name, self.path, self.priority).as_str(),
|
|
)
|
|
.unwrap();
|
|
tokens.append(Group::new(proc_macro2::Delimiter::Parenthesis, token));
|
|
}
|
|
}
|
|
|
|
/// Automatic generate all the component information
|
|
pub fn component_generate() -> Vec<ComponentInfo> {
|
|
// extract components information
|
|
let mut metadata = metadata();
|
|
|
|
let mut component_packages = vec![];
|
|
let workspace_root = metadata["workspace_root"].as_str().unwrap();
|
|
let workspace_root = String::from_str(workspace_root).unwrap().replace('\\', "/");
|
|
|
|
let comps_name = get_components_name(&workspace_root, &metadata["packages"]);
|
|
for package in metadata["packages"].members_mut() {
|
|
let name = package["name"].as_str().unwrap();
|
|
if comps_name.contains(&name.to_string()) {
|
|
// remove useless depend
|
|
let mut depends = JsonValue::Array(Vec::new());
|
|
loop {
|
|
let depend = package["dependencies"].pop();
|
|
if depend == JsonValue::Null {
|
|
break;
|
|
}
|
|
if comps_name.contains(&depend["name"].as_str().unwrap().to_string()) {
|
|
depends.push(depend).unwrap();
|
|
}
|
|
}
|
|
package["dependencies"] = depends;
|
|
component_packages.push(package);
|
|
}
|
|
}
|
|
|
|
// calculate priority
|
|
let mut mapping: HashMap<String, u16> = HashMap::new();
|
|
let mut component_packages_map: HashMap<String, &mut JsonValue> = HashMap::new();
|
|
for i in component_packages.iter_mut() {
|
|
component_packages_map.insert(i["name"].as_str().unwrap().to_string(), i);
|
|
}
|
|
|
|
for (name, package) in component_packages_map.iter() {
|
|
if mapping.contains_key(package["name"].as_str().unwrap()) {
|
|
continue;
|
|
}
|
|
calculate_priority(&mut mapping, &component_packages_map, name.clone());
|
|
}
|
|
drop(component_packages_map);
|
|
|
|
// priority calculation complete
|
|
let mut components_info = Vec::new();
|
|
for package in component_packages {
|
|
let temp_id = package["id"].as_str().unwrap();
|
|
// extract path, let's take `(path+file:///path/to/comps/pci)` as an example
|
|
let path = {
|
|
// use the last element, `pci)`
|
|
let mut paths: Vec<&str> = temp_id.split(&workspace_root).collect();
|
|
// remove the last character
|
|
let mut path1 = paths.pop().unwrap().to_string();
|
|
path1.pop();
|
|
if path1.starts_with('/') {
|
|
path1.remove(0);
|
|
}
|
|
path1
|
|
};
|
|
let component_info = ComponentInfo {
|
|
name: package["name"].as_str().unwrap().to_string(),
|
|
path: path.to_owned(),
|
|
priority: *mapping
|
|
.get(&package["name"].as_str().unwrap().to_string())
|
|
.unwrap(),
|
|
};
|
|
components_info.push(component_info)
|
|
}
|
|
components_info
|
|
}
|
|
|
|
/// Get the path to the Components.toml file
|
|
pub fn get_component_toml_path() -> TokenStream {
|
|
let metadata = metadata();
|
|
let workspace_root = metadata["workspace_root"].as_str().unwrap();
|
|
let mut workspace_root = String::from_str(workspace_root)
|
|
.unwrap()
|
|
.replace('\\', "/")
|
|
.add("/")
|
|
.add(COMPONENT_FILE_NAME)
|
|
.add("\"");
|
|
workspace_root.insert(0, '\"');
|
|
TokenStream::from_str(workspace_root.as_str()).unwrap()
|
|
}
|
|
|
|
fn is_component(package: &JsonValue) -> bool {
|
|
for depend in package["dependencies"].members() {
|
|
if depend["name"].as_str().unwrap() == "component" {
|
|
return true;
|
|
}
|
|
}
|
|
false
|
|
}
|
|
|
|
/// Get all the components name, this function will also check if the Components.toml contain all the components.
|
|
fn get_components_name(workspace_root: &String, packages: &JsonValue) -> Vec<String> {
|
|
let file_components_name = read_component_file(workspace_root);
|
|
let mut comps_name = Vec::new();
|
|
for package in packages.members() {
|
|
if is_component(package) {
|
|
if !file_components_name.contains(&package["name"].as_str().unwrap().to_string()) {
|
|
// if the package is in the workspace_root
|
|
if package["id"].as_str().unwrap().contains(workspace_root) {
|
|
panic!(
|
|
"Package {} in the workspace that not written in the {} file",
|
|
package["name"].as_str().unwrap(),
|
|
COMPONENT_FILE_NAME
|
|
);
|
|
}
|
|
}
|
|
comps_name.push(package["name"].as_str().unwrap().to_string());
|
|
}
|
|
}
|
|
comps_name
|
|
}
|
|
|
|
/// read component file, return all the components name
|
|
fn read_component_file(workspace_root: &str) -> Vec<String> {
|
|
let component_toml: toml::Value = {
|
|
let mut component_file_path = workspace_root.to_owned();
|
|
component_file_path.push('/');
|
|
component_file_path.push_str(COMPONENT_FILE_NAME);
|
|
let mut file = File::open(component_file_path)
|
|
.expect("Components.toml file not found, please check if the file exists");
|
|
let mut str_val = String::new();
|
|
file.read_to_string(&mut str_val).unwrap();
|
|
toml::from_str(&str_val).unwrap()
|
|
};
|
|
for (name, value) in component_toml.as_table().unwrap() {
|
|
if name.as_str() == "components" {
|
|
return value
|
|
.as_table()
|
|
.unwrap()
|
|
.values()
|
|
.map(|value| {
|
|
value
|
|
.as_table()
|
|
.unwrap()
|
|
.values()
|
|
.map(|str_val| str_val.as_str().unwrap().to_string())
|
|
.collect()
|
|
})
|
|
.collect();
|
|
}
|
|
}
|
|
panic!("Componets.toml file not valid")
|
|
}
|
|
|
|
/// calculate the priority of one node
|
|
fn calculate_priority(
|
|
prioritys: &mut HashMap<String, u16>,
|
|
package_mapping: &HashMap<String, &mut JsonValue>,
|
|
node_name: String,
|
|
) -> u16 {
|
|
if prioritys.contains_key(&node_name) {
|
|
return *prioritys.get(&node_name).unwrap();
|
|
}
|
|
|
|
let package = &package_mapping[&node_name];
|
|
let mut lowest_priority: u16 = 0;
|
|
for depends in package["dependencies"].members() {
|
|
lowest_priority = lowest_priority.max(
|
|
calculate_priority(
|
|
prioritys,
|
|
package_mapping,
|
|
depends["name"].as_str().unwrap().to_string(),
|
|
) + 1,
|
|
);
|
|
}
|
|
|
|
prioritys.insert(node_name.to_string(), lowest_priority);
|
|
lowest_priority
|
|
}
|
|
|
|
fn metadata() -> json::JsonValue {
|
|
let mut cmd = Command::new(std::env::var("CARGO").unwrap());
|
|
cmd.arg("metadata");
|
|
cmd.arg("--format-version").arg("1");
|
|
let output = cmd.output().unwrap();
|
|
|
|
if !output.status.success() {
|
|
panic!("cannot get metadata");
|
|
}
|
|
|
|
let output = String::from_utf8(output.stdout).unwrap();
|
|
json::parse(&output).unwrap()
|
|
}
|