use super::tool_record::ToolRecord;
use proto_core::Id;
use rustc_hash::{FxHashMap, FxHashSet};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use tokio::sync::RwLock;
#[derive(Debug)]
pub enum InstallStatus {
ReqFailed(Id),
WaitingOnReqs(Vec<Id>),
Waiting,
}
#[derive(Clone)]
pub struct InstallGraph {
ids: Arc<FxHashSet<Id>>,
installed: Arc<RwLock<FxHashSet<Id>>>,
not_installed: Arc<RwLock<FxHashSet<Id>>>,
requires: Arc<FxHashMap<Id, Vec<Id>>>,
waiting: Arc<AtomicBool>,
}
impl InstallGraph {
pub fn new(tools: &[ToolRecord]) -> Self {
let mut ids = FxHashSet::default();
let mut requires = FxHashMap::default();
for tool in tools {
ids.insert(tool.get_id().clone());
if !tool.metadata.requires.is_empty() {
requires.insert(
tool.get_id().clone(),
tool.metadata.requires.iter().map(Id::raw).collect(),
);
}
}
Self {
ids: Arc::new(ids),
installed: Arc::new(RwLock::new(FxHashSet::default())),
not_installed: Arc::new(RwLock::new(FxHashSet::default())),
requires: Arc::new(requires),
waiting: Arc::new(AtomicBool::new(true)),
}
}
pub async fn check_install_status(&self, id: &Id) -> Option<InstallStatus> {
if self.waiting.load(Ordering::Relaxed) {
return Some(InstallStatus::Waiting);
}
if !self.ids.contains(id) {
return None;
}
if let Some(require_ids) = self.requires.get(id) {
let installed = self.installed.read().await;
let not_installed = self.not_installed.read().await;
let mut waiting_on = vec![];
for require_id in require_ids {
if !self.ids.contains(require_id) {
continue;
}
if not_installed.contains(require_id) {
return Some(InstallStatus::ReqFailed(require_id.clone()));
}
if !installed.contains(require_id) {
waiting_on.push(require_id.clone());
}
}
if !waiting_on.is_empty() {
return Some(InstallStatus::WaitingOnReqs(waiting_on));
}
}
None
}
pub async fn mark_installed(&self, id: &Id) {
self.installed.write().await.insert(id.to_owned());
}
pub async fn mark_not_installed(&self, id: &Id) {
self.not_installed.write().await.insert(id.to_owned());
}
pub fn proceed(&mut self) {
self.waiting.store(false, Ordering::Release);
}
}