devrc 0.6.0

devrc is an easy to use task runner tool on steroids for developers
Documentation
pub mod plugins;
pub mod shebang;
pub mod system;

use crate::{
    config::Config,
    errors::{DevrcError, DevrcResult},
    scope::Scope,
};
use std::{
    convert::{TryFrom, TryInto},
    env,
    fmt::{self, Display},
};

use serde::Deserialize;
use std::{cell::RefCell, rc::Rc};

use self::{plugins::PluginInterpreter, system::SystemShell};

use devrc_plugins::{config::ExecutionConfig, execution::ExecutionPluginManager};

#[derive(Debug, Clone, Deserialize)]
#[serde(untagged)]
pub enum InterpreterKind {
    PluginInterpreter(PluginInterpreter),
    Internal(SystemShell),
}

impl InterpreterKind {
    pub fn execute(
        &self,
        code: &str,
        scope: &Scope,
        config: &Config,
        registry: Rc<RefCell<ExecutionPluginManager>>,
    ) -> DevrcResult<i32> {
        match self {
            InterpreterKind::Internal(internal_shell) => {
                internal_shell.execute(code, scope, config)
            }
            InterpreterKind::PluginInterpreter(interpreter) => {
                let mut manager = (*registry)
                    .try_borrow_mut()
                    .map_err(|_| DevrcError::RuntimeError)?;
                let plugin = manager.get_plugin(&interpreter.runtime)?;
                let options = interpreter
                    .try_into()
                    .map_err(|_| DevrcError::RuntimeError)?;
                Ok(plugin.execute(options, code, &scope.environment)?)
            }
        }
    }
}

impl Default for InterpreterKind {
    fn default() -> Self {
        InterpreterKind::Internal(SystemShell::default())
    }
}

impl Display for InterpreterKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            InterpreterKind::Internal(interpreter) => {
                write!(f, "{}", interpreter)
            }
            InterpreterKind::PluginInterpreter(interpreter) => {
                write!(f, "{}", interpreter)
            }
        }
    }
}

impl TryFrom<&PluginInterpreter> for ExecutionConfig {
    type Error = DevrcError;

    fn try_from(value: &PluginInterpreter) -> Result<Self, Self::Error> {
        Ok(Self {
            runtime: value.runtime.clone(),
            current_dir: env::current_dir().ok(),
            args: value.args.clone().unwrap_or_default(),
            options: value
                .options
                .clone()
                .into_iter()
                .map(|(key, value)| (key, value.into()))
                .collect(),
        })
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_name() {}
}