nargo_transformer/
plugin.rs1use nargo_ir::IRModule;
2use nargo_types::{NargoValue, Result, Span};
3use serde::{Deserialize, Serialize};
4use std::{collections::HashMap, ffi::OsStr, fs, path::Path};
5
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
8pub enum PluginLifecycle {
9 Init,
11 PreTransform,
13 Transform,
15 PostTransform,
17 Cleanup,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct PluginConfig {
24 pub name: String,
26 pub version: String,
28 pub description: String,
30 pub priority: i32,
32 pub config: HashMap<String, NargoValue>,
34 pub enabled: bool,
36}
37
38pub trait Plugin: Send + Sync {
40 fn name(&self) -> String;
42
43 fn description(&self) -> String;
45
46 fn init(&mut self, config: &PluginConfig) -> Result<()>;
48
49 fn run(&mut self, ir: &mut IRModule, lifecycle: PluginLifecycle) -> Result<()>;
51
52 fn cleanup(&mut self) -> Result<()>;
54}
55
56pub struct PluginManager {
58 plugins: Vec<Box<dyn Plugin>>,
59 configs: HashMap<String, PluginConfig>,
60}
61
62impl Default for PluginManager {
63 fn default() -> Self {
64 Self::new()
65 }
66}
67
68impl PluginManager {
69 pub fn new() -> Self {
71 Self { plugins: Vec::new(), configs: HashMap::new() }
72 }
73
74 pub fn load_plugin<P: Plugin + 'static>(&mut self, plugin: P, config: PluginConfig) -> Result<()> {
76 let plugin_name = plugin.name();
77
78 let mut plugin_box = Box::new(plugin);
80 plugin_box.init(&config)?;
81
82 self.plugins.push(plugin_box);
84 self.configs.insert(plugin_name, config);
85
86 self.plugins.sort_by(|a, b| {
88 let a_name = a.name();
89 let b_name = b.name();
90 let a_priority = self.configs.get(&a_name).map(|c| c.priority).unwrap_or(0);
91 let b_priority = self.configs.get(&b_name).map(|c| c.priority).unwrap_or(0);
92 a_priority.cmp(&b_priority)
93 });
94
95 Ok(())
96 }
97
98 pub fn load_plugins_from_directory(&mut self, directory: &Path) -> Result<()> {
100 if !directory.exists() || !directory.is_dir() {
101 return Ok(()); }
103
104 for entry in fs::read_dir(directory)? {
105 let entry = entry?;
106 let path = entry.path();
107
108 if path.is_file() && path.extension() == Some(OsStr::new("rs")) {
110 }
114 }
115
116 Ok(())
117 }
118
119 pub fn run_plugins(&mut self, ir: &mut IRModule, lifecycle: PluginLifecycle) -> Result<()> {
121 for plugin in &mut self.plugins {
122 let plugin_name = plugin.name();
123 let config = self.configs.get(&plugin_name).unwrap();
124
125 if config.enabled {
126 plugin.run(ir, lifecycle.clone())?;
127 }
128 }
129
130 Ok(())
131 }
132
133 pub fn cleanup_plugins(&mut self) -> Result<()> {
135 for plugin in &mut self.plugins {
136 plugin.cleanup()?;
137 }
138
139 Ok(())
140 }
141
142 pub fn get_plugins_info(&self) -> Vec<(String, PluginConfig)> {
144 self.configs.iter().map(|(name, config)| (name.clone(), config.clone())).collect()
145 }
146
147 pub fn set_plugin_enabled(&mut self, plugin_name: &str, enabled: bool) -> Result<()> {
149 if let Some(config) = self.configs.get_mut(plugin_name) {
150 config.enabled = enabled;
151 Ok(())
152 }
153 else {
154 Err(nargo_types::Error::external_error("PluginManager".to_string(), format!("Plugin {} not found", plugin_name), Span::unknown()))
155 }
156 }
157}