You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

146 lines
3.9 KiB
Rust

use crate::unit::{UnitHandle, Unit};
use std::collections::{HashMap, VecDeque, HashSet};
use crate::config::loader::Loader;
#[derive(Debug, Clone, Default)]
pub struct DependencyTree {
known: HashSet<String>,
dependents: HashMap<String, HashSet<String>>,
dependencies: HashMap<String, HashSet<String>>,
}
impl DependencyTree {
pub fn add_owner(&mut self, owner: String) {
self.known.insert(owner);
}
pub fn add_dependency(&mut self, owner: String, dependency: String) {
if owner == dependency {
return;
}
self.dependencies
.entry(owner.clone())
.or_default()
.insert(dependency.clone());
self.dependents
.entry(dependency.clone())
.or_default()
.insert(owner.clone());
self.known.insert(dependency);
self.known.insert(owner);
}
/// Gets the bottom of the dependency tree
/// These are the items -without- dependencies
pub fn get_bottom(&self) -> Vec<String> {
self
.known
.iter()
.filter(|item| !self.dependencies.get(*item).map(|l| l.len() == 0).unwrap_or(true))
.map(|item| item.clone())
.collect()
}
/// Gets the top of the dependency tree
/// These are the items -without- dependents
pub fn get_top(&self) -> Vec<String> {
self
.known
.iter()
.filter(|item| self.dependents.get(*item).map(|l| l.len() == 0).unwrap_or(true))
.map(|item| item.clone())
.collect()
}
pub fn get_dependencies(&self, item: &str) -> Vec<String> {
self
.dependencies
.get(item)
.map(|set| set.iter().map(|x| x.clone()).collect::<Vec<_>>())
.unwrap_or(Vec::new())
}
pub fn get_depedents(&self, item: &str) -> Vec<String> {
self
.dependents
.get(item)
.map(|set| set.iter().map(|x| x.clone()).collect::<Vec<_>>())
.unwrap_or(Vec::new())
}
}
#[derive(Debug, Clone, Default)]
pub struct Registry {
loader: Loader,
units: HashMap<String, UnitHandle>,
}
impl Registry {
pub fn with_loader(loader: Loader) -> Registry {
Registry {
loader,
units: Default::default(),
}
}
pub async fn get_dependency_tree(&mut self, unit_name: &str) -> DependencyTree {
let mut queue = VecDeque::new();
let mut done = HashSet::new();
let mut dependencies: DependencyTree = Default::default();
queue.push_back(unit_name.to_string());
while let Some(item) = queue.pop_front() {
let unit = if let Some(unit) = self.load_unit(&item).await {
unit
} else {
done.insert(item);
continue;
};
for dep in &unit.wants {
if done.contains(dep) {
continue;
}
queue.push_back(dep.clone());
}
for dep in &unit.requires {
if done.contains(dep) {
continue;
}
queue.push_back(dep.clone());
}
for before in &unit.before {
dependencies.add_dependency(before.clone(), unit.name.clone());
}
for after in &unit.after {
dependencies.add_dependency(unit.name.clone(), after.clone());
}
}
dependencies
}
pub async fn load_unit(&mut self, unit_name: &str) -> Option<&Unit> {
let config = self
.units
.entry(unit_name.to_string())
.or_insert_with(|| UnitHandle::unloaded(unit_name));
if !config.is_loaded() {
if let Some(unit) = self.loader.load_unit(unit_name).await {
config.update(unit);
}
}
config.get_config()
}
}