devalang_wasm/engine/plugin/
loader.rs1#[cfg(feature = "cli")]
2use std::path::PathBuf;
3
4#[derive(Debug, Clone)]
5pub struct PluginInfo {
6 pub author: String,
7 pub name: String,
8 pub version: Option<String>,
9 pub description: Option<String>,
10 pub exports: Vec<PluginExport>,
11}
12
13#[derive(Debug, Clone)]
14pub struct PluginExport {
15 pub name: String,
16 pub kind: String,
17}
18
19#[cfg(feature = "cli")]
20pub fn load_plugin(author: &str, name: &str) -> Result<(PluginInfo, Vec<u8>), String> {
21 use serde::Deserialize;
22
23 #[derive(Debug, Deserialize)]
24 struct LocalPluginToml {
25 plugin: LocalPluginInfo,
26 #[serde(rename = "exports", default)]
27 exports: Vec<LocalExportEntry>,
28 }
29
30 #[derive(Debug, Deserialize)]
31 struct LocalPluginInfo {
32 name: String,
33 #[serde(default)]
34 version: Option<String>,
35 #[serde(default)]
36 description: Option<String>,
37 #[serde(default)]
38 publisher: Option<String>,
39 }
40
41 #[derive(Debug, Deserialize)]
42 struct LocalExportEntry {
43 name: String,
44 kind: String,
45 }
46
47 let deva_dir = find_deva_dir()?;
49
50 let plugin_dir = deva_dir.join("plugins").join(author).join(name);
52 let toml_path = plugin_dir.join("plugin.toml");
53 let wasm_path = plugin_dir.join(format!("{}.wasm", name));
54
55 if !toml_path.exists() {
56 return Err(format!("❌ Plugin file not found: {}", toml_path.display()));
57 }
58
59 if !wasm_path.exists() {
60 return Err(format!("❌ Plugin wasm not found: {}", wasm_path.display()));
61 }
62
63 let toml_content = std::fs::read_to_string(&toml_path)
65 .map_err(|e| format!("Failed to read '{}': {}", toml_path.display(), e))?;
66 let plugin_toml: LocalPluginToml = toml::from_str(&toml_content)
67 .map_err(|e| format!("Failed to parse '{}': {}", toml_path.display(), e))?;
68
69 let wasm_bytes = std::fs::read(&wasm_path)
71 .map_err(|e| format!("Failed to read '{}': {}", wasm_path.display(), e))?;
72
73 let info = PluginInfo {
75 author: plugin_toml
76 .plugin
77 .publisher
78 .unwrap_or_else(|| author.to_string()),
79 name: plugin_toml.plugin.name.clone(),
80 version: plugin_toml.plugin.version.clone(),
81 description: plugin_toml.plugin.description.clone(),
82 exports: plugin_toml
83 .exports
84 .iter()
85 .map(|e| PluginExport {
86 name: e.name.clone(),
87 kind: e.kind.clone(),
88 })
89 .collect(),
90 };
91
92 Ok((info, wasm_bytes))
93}
94
95#[cfg(feature = "cli")]
96fn find_deva_dir() -> Result<PathBuf, String> {
97 use std::env;
98
99 let current_dir =
100 env::current_dir().map_err(|e| format!("Failed to get current directory: {}", e))?;
101
102 let mut dir = current_dir.as_path();
104 loop {
105 let deva_path = dir.join(".deva");
106 if deva_path.exists() && deva_path.is_dir() {
107 return Ok(deva_path);
108 }
109
110 match dir.parent() {
112 Some(parent) => dir = parent,
113 None => {
114 return Err(
115 "Could not find .deva directory in current directory or parents".to_string(),
116 );
117 }
118 }
119 }
120}