diff --git a/crates/bazed-stew/src/executable.rs b/crates/bazed-stew/src/executable.rs index 0a3f4c2..6fdded8 100644 --- a/crates/bazed-stew/src/executable.rs +++ b/crates/bazed-stew/src/executable.rs @@ -2,55 +2,71 @@ use std::path::{Path, PathBuf}; use semver::{Version, VersionReq}; +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error(transparent)] + VersionParse(#[from] semver::Error), + #[error("Malformed plugin filename, must be \"@\"")] + MalformedName(String), + #[error("Given path is not a file")] + NotAFile(PathBuf), +} + #[derive(Debug, Clone)] -pub struct PluginExecutable(PathBuf); +pub struct PluginExecutable { + pub name: String, + pub version: Version, + pub path: PathBuf, +} impl std::fmt::Display for PluginExecutable { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "{}@{} ({})", - self.name(), - self.version(), - self.0.display() + self.name, + self.version, + self.path.display() ) } } impl PluginExecutable { - pub fn new(path: PathBuf) -> Option { - if !path.is_file() { - return None; - } - let file_name = path.file_name()?.to_string_lossy(); - let version = file_name.split('@').nth(1)?.to_string(); - Version::parse(&version).is_ok().then_some(Self(path)) - } - - pub fn path(&self) -> &PathBuf { - &self.0 - } - - pub fn name(&self) -> String { - let file_name = self.0.file_name().unwrap().to_string_lossy(); - file_name.split('@').next().unwrap().to_string() + pub fn new(path: PathBuf) -> Result { + let file_name = &path + .file_name() + .ok_or_else(|| Error::NotAFile(path.clone()))? + .to_str() + .expect("Non-unicode filename encountered") + .to_string(); + let (name, version) = file_name + .split_once('@') + .ok_or_else(|| Error::MalformedName(file_name.clone()))?; + Ok(Self { + name: name.to_string(), + version: Version::parse(&version)?, + path, + }) } - pub fn version(&self) -> Version { - let file_name = self.0.file_name().unwrap().to_string_lossy(); - let version = file_name.split('@').nth(1).unwrap().to_string(); - Version::parse(&version).unwrap() + pub fn filename(&self) -> &str { + self.path + .file_name() + .unwrap() + .to_str() + .expect("Non-unicode filename encountered") } pub(crate) fn version_matches(&self, version_requirement: &VersionReq) -> bool { - version_requirement.matches(&self.version()) + version_requirement.matches(&self.version) } + } pub fn search_plugins_in(path: &Path) -> impl Iterator { path.read_dir() .unwrap() - .filter_map(|entry| PluginExecutable::new(entry.unwrap().path())) + .filter_map(|entry| PluginExecutable::new(entry.unwrap().path()).ok()) } pub fn search_plugin( @@ -61,5 +77,5 @@ pub fn search_plugin( paths .iter() .flat_map(|path| search_plugins_in(path)) - .find(|plugin| plugin.name() == name && plugin.version_matches(version_req)) + .find(|plugin| plugin.name == name && plugin.version_matches(version_req)) } diff --git a/crates/bazed-stew/src/lib.rs b/crates/bazed-stew/src/lib.rs index e08294b..1d223fd 100644 --- a/crates/bazed-stew/src/lib.rs +++ b/crates/bazed-stew/src/lib.rs @@ -56,7 +56,7 @@ impl Stew { let (to_stew_write, to_stew_read) = interprocess::unnamed_pipe::pipe().unwrap(); let (to_plugin_write, to_plugin_read) = interprocess::unnamed_pipe::pipe().unwrap(); let plugin_id = PluginId(Uuid::new_v4()); - Command::new(plugin.path()) + Command::new(&plugin.path) .arg(to_stew_write.as_raw_fd().to_string()) .arg(to_plugin_read.as_raw_fd().to_string()) .arg(plugin_id.0.to_string()) @@ -218,7 +218,7 @@ impl Stew { invocation_id, InvocationResponseData::PluginLoaded { plugin_id, - version: found.version(), + version: found.version, }, ) .await;