strixonomy_plugin/
discovery.rs1use crate::manifest::{parse_manifest, DiscoveredPlugin};
2use std::fs;
3use std::path::{Path, PathBuf};
4use thiserror::Error;
5
6pub const PLUGIN_DIR: &str = ".strixonomy/plugins";
8
9#[allow(dead_code)] pub const LEGACY_PLUGIN_DIR: &str = ".ontocore/plugins";
12
13#[derive(Debug, Error)]
14pub enum PluginDiscoveryError {
15 #[error("IO error reading {path}: {source}")]
16 Io { path: PathBuf, source: std::io::Error },
17 #[error("invalid manifest {path}: {message}")]
18 InvalidManifest { path: PathBuf, message: String },
19}
20
21pub fn discover_plugins(workspace: &Path) -> Result<Vec<DiscoveredPlugin>, PluginDiscoveryError> {
23 let mut discovered = Vec::new();
24 let mut seen_ids = std::collections::HashSet::new();
25 for plugins_dir in strixonomy_core::plugin_search_dirs(workspace) {
26 if !plugins_dir.is_dir() {
27 continue;
28 }
29 for entry in fs::read_dir(&plugins_dir)
30 .map_err(|source| PluginDiscoveryError::Io { path: plugins_dir.clone(), source })?
31 {
32 let entry = entry
33 .map_err(|source| PluginDiscoveryError::Io { path: plugins_dir.clone(), source })?;
34 let path = entry.path();
35 if path.extension().and_then(|e| e.to_str()) != Some("toml") {
36 continue;
37 }
38 let text = fs::read_to_string(&path)
39 .map_err(|source| PluginDiscoveryError::Io { path: path.clone(), source })?;
40 let manifest = parse_manifest(&text).map_err(|e| {
41 PluginDiscoveryError::InvalidManifest { path: path.clone(), message: e.to_string() }
42 })?;
43 if !seen_ids.insert(manifest.id.clone()) {
44 continue;
46 }
47 discovered.push(DiscoveredPlugin { manifest, manifest_path: path });
48 }
49 }
50 Ok(discovered)
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
58 fn discovers_legacy_plugins_dir() {
59 let dir = tempfile::tempdir().unwrap();
60 let plugins = dir.path().join(LEGACY_PLUGIN_DIR);
61 fs::create_dir_all(&plugins).unwrap();
62 fs::write(
63 plugins.join("demo.toml"),
64 r#"
65[plugin]
66id = "demo"
67name = "Demo"
68version = "0.1.0"
69kind = "validator"
70entry = "./demo"
71"#,
72 )
73 .unwrap();
74 let found = discover_plugins(dir.path()).unwrap();
75 assert_eq!(found.len(), 1);
76 assert_eq!(found[0].manifest.id.as_deref(), Some("demo"));
77 }
78}