use std::path::{Path, PathBuf}; use embed_nu::{Argument, CommandGroupConfig, Context, ValueIntoExpression}; use std::fs; use crate::{distro::OSConfig, error::ScriptError, utils::CFG_PATH}; #[derive(Clone)] pub struct ExecBuilder { task_config: embed_nu::Value, ctx: Context, } impl ExecBuilder { pub fn create( script: PathBuf, os_config: OSConfig, task_config: embed_nu::Value, ) -> Result { let script_contents = Self::get_script_contents(&script)?; let mut ctx = Context::builder() .with_command_groups(CommandGroupConfig::default().all_groups(true))? .add_parent_env_vars() .add_var("TRM_CONFIG", os_config)? .add_script(script_contents)? .build()?; if !ctx.has_fn("main") { Err(ScriptError::MissingMain(script)) } else { Ok(Self { ctx, task_config }) } } #[tracing::instrument(level = "trace", skip_all)] pub fn exec(mut self) -> Result<(), ScriptError> { let pipeline = self.ctx.call_fn( "main", vec![Argument::Positional(self.task_config.into_expression())], )?; self.ctx.print_pipeline_stderr(pipeline)?; Ok(()) } /// Returns if the script needs to be run inside the new root pub fn requires_chroot(&self) -> bool { self.ctx .get_var("run_in_chroot") .and_then(|v| v.as_bool().ok()) .unwrap_or(false) } #[tracing::instrument(level = "trace", skip_all)] fn get_script_contents(path: &Path) -> Result { let path = CFG_PATH.join(path); if path.exists() { fs::read_to_string(path).map_err(ScriptError::from) } else { Err(ScriptError::ScriptNotFound(path)) } } }