use std::path::{Path, PathBuf}; use embed_nu::{Argument, CommandGroupConfig, ValueIntoExpression}; use std::fs; use crate::{distro::OSConfig, error::ScriptError, utils::CFG_PATH}; use miette::{Context, IntoDiagnostic, Result}; #[derive(Clone)] pub struct ExecBuilder { task_config: embed_nu::Value, ctx: embed_nu::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 = embed_nu::Context::builder() .with_command_groups(CommandGroupConfig::default().all_groups(true)) .into_diagnostic()? .add_parent_env_vars() .add_var("TRM_CONFIG", os_config) .into_diagnostic()? .add_script(script_contents) .into_diagnostic()? .build() .into_diagnostic()?; if !ctx.has_fn("main") { Err(ScriptError::MissingMain(script).into()) } else { Ok(Self { ctx, task_config }) } } #[tracing::instrument(level = "trace", skip_all)] pub fn exec(mut self) -> Result<()> { let pipeline = self .ctx .call_fn( "main", vec![Argument::Positional(self.task_config.into_expression())], ) .into_diagnostic()?; self.ctx.print_pipeline_stderr(pipeline).into_diagnostic()?; 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) .into_diagnostic() .context("reading script contents") } else { Err(ScriptError::ScriptNotFound(path).into()) } } }