use nargo_ir::IRModule;
use nargo_types::{NargoValue, Result, Span};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, ffi::OsStr, fs, path::Path};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum PluginLifecycle {
Init,
PreTransform,
Transform,
PostTransform,
Cleanup,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PluginConfig {
pub name: String,
pub version: String,
pub description: String,
pub priority: i32,
pub config: HashMap<String, NargoValue>,
pub enabled: bool,
}
pub trait Plugin: Send + Sync {
fn name(&self) -> String;
fn description(&self) -> String;
fn init(&mut self, config: &PluginConfig) -> Result<()>;
fn run(&mut self, ir: &mut IRModule, lifecycle: PluginLifecycle) -> Result<()>;
fn cleanup(&mut self) -> Result<()>;
}
pub struct PluginManager {
plugins: Vec<Box<dyn Plugin>>,
configs: HashMap<String, PluginConfig>,
}
impl Default for PluginManager {
fn default() -> Self {
Self::new()
}
}
impl PluginManager {
pub fn new() -> Self {
Self { plugins: Vec::new(), configs: HashMap::new() }
}
pub fn load_plugin<P: Plugin + 'static>(&mut self, plugin: P, config: PluginConfig) -> Result<()> {
let plugin_name = plugin.name();
let mut plugin_box = Box::new(plugin);
plugin_box.init(&config)?;
self.plugins.push(plugin_box);
self.configs.insert(plugin_name, config);
self.plugins.sort_by(|a, b| {
let a_name = a.name();
let b_name = b.name();
let a_priority = self.configs.get(&a_name).map(|c| c.priority).unwrap_or(0);
let b_priority = self.configs.get(&b_name).map(|c| c.priority).unwrap_or(0);
a_priority.cmp(&b_priority)
});
Ok(())
}
pub fn load_plugins_from_directory(&mut self, directory: &Path) -> Result<()> {
if !directory.exists() || !directory.is_dir() {
return Ok(()); }
for entry in fs::read_dir(directory)? {
let entry = entry?;
let path = entry.path();
if path.is_file() && path.extension() == Some(OsStr::new("rs")) {
}
}
Ok(())
}
pub fn run_plugins(&mut self, ir: &mut IRModule, lifecycle: PluginLifecycle) -> Result<()> {
for plugin in &mut self.plugins {
let plugin_name = plugin.name();
let config = self.configs.get(&plugin_name).unwrap();
if config.enabled {
plugin.run(ir, lifecycle.clone())?;
}
}
Ok(())
}
pub fn cleanup_plugins(&mut self) -> Result<()> {
for plugin in &mut self.plugins {
plugin.cleanup()?;
}
Ok(())
}
pub fn get_plugins_info(&self) -> Vec<(String, PluginConfig)> {
self.configs.iter().map(|(name, config)| (name.clone(), config.clone())).collect()
}
pub fn set_plugin_enabled(&mut self, plugin_name: &str, enabled: bool) -> Result<()> {
if let Some(config) = self.configs.get_mut(plugin_name) {
config.enabled = enabled;
Ok(())
}
else {
Err(nargo_types::Error::external_error("PluginManager".to_string(), format!("Plugin {} not found", plugin_name), Span::unknown()))
}
}
}