use std::{
path::{Path, PathBuf},
sync::Arc,
};
use mentra::tool::{PreparedTool, ToolAudience};
use crate::{
RunError,
runtime::Runtime,
tools::{ExecutableTool, declared::manifest::check_name},
};
#[derive(Debug)]
pub(crate) struct WorkspaceHostTools {
runtime: Arc<Runtime>,
root: PathBuf,
names: Vec<String>,
}
impl WorkspaceHostTools {
pub(crate) fn none(runtime: Arc<Runtime>, root: &Path) -> Self {
Self {
runtime,
root: root.to_path_buf(),
names: Vec::new(),
}
}
pub(crate) fn register(
runtime: Arc<Runtime>,
audience: &ToolAudience,
root: &Path,
tools: Vec<Box<dyn ExecutableTool>>,
) -> Result<Self, RunError> {
let named = tools
.into_iter()
.map(|tool| {
let prepared = PreparedTool::new(tool);
(prepared.descriptor().provider.name.clone(), prepared)
})
.collect::<Vec<_>>();
let mut held = Self::none(runtime, root);
let mut permissions = Vec::new();
for (name, _) in &named {
check_name(name).map_err(|reason| RunError::WorkspaceHostToolName {
name: name.clone(),
reason,
})?;
let permit = held
.runtime
.claim_native_tool(root, name)
.map_err(|reason| RunError::WorkspaceHostToolNameTaken {
name: name.clone(),
reason,
})?;
held.names.push(name.clone());
permissions.push(permit);
}
for ((name, prepared), permit) in named.into_iter().zip(permissions) {
held.runtime
.install_claimed_tool(audience, permit, prepared)
.map_err(|reason| RunError::WorkspaceHostToolNameTaken { name, reason })?;
}
Ok(held)
}
pub(crate) fn names(&self) -> &[String] {
&self.names
}
}
impl Drop for WorkspaceHostTools {
fn drop(&mut self) {
for name in self.names.drain(..) {
self.runtime.release_native_tool(&name, &self.root);
}
}
}