use workshop_engine::{Engine, EventSender, ExecutionContext}; use crate::bake::parser::Function; use crate::bake::constant::{DEFAULT_WORKSPACE, TRIVIAL_SCRIPT_NAME}; use crate::bake::error::BakeError; use crate::cli::Cli; use crate::prebake::PrebakeConfig; use crate::prebake::security::get_drop_after; use crate::prebake::stage::PrebakeStage; use crate::prebake; use std::path::{Path, PathBuf}; mod builder; pub mod constant; mod decorator; pub mod parser; pub mod error; mod schedule; pub async fn bake( script_path: &Path, bake_base_path: &Path, prebake_path: &Path, cli: &Cli, ctx: &mut ExecutionContext, event_tx: EventSender, ) -> Result<(), BakeError> { let script_content = std::fs::read_to_string(script_path)?; let prebake_content = std::fs::read_to_string(prebake_path)?; let prebake = prebake::parse(prebake_content.as_str()).map_err(|e| { log::error!("Failed to parse prebake.yml: {}", e); log::error!("This is unexpected!"); BakeError::YamlParseError(e) })?; let workspace = get_workspace(&prebake); let functions = parser::parse_script(&script_content)?; let has_pipeline = functions.pipeline_functions.iter().any(|f| { f.decorators .iter() .any(|d| matches!(d, decorator::Decorator::Pipeline)) }); let trivial = false; let use_template = true; let engine = Engine::new(); if let Some(env) = &prebake.envvars { if let Some(prebake_env) = &env.bake { ctx.env_vars.extend(prebake_env.clone()); } } if !has_pipeline || trivial { let function = Function { name: TRIVIAL_SCRIPT_NAME.to_string(), decorators: vec![], body: script_content, }; let script = builder::build_script(&function, bake_base_path, &workspace, None, use_template)?; let result = engine.execute_script(&script, &ctx, &event_tx).await; result?; } else { let sorted_functions = schedule::sort_function(functions.pipeline_functions)?; let remaining = functions.remaining_code; for func in sorted_functions { let mut modified_func = func.clone(); modified_func.body = remaining.clone() + &func.body; let script = builder::build_script( &modified_func, bake_base_path, &workspace, None, use_template, )?; let result = engine.execute_script(&script, &ctx, &event_tx).await; result?; } } Ok(()) } fn get_workspace(prebake_config: &PrebakeConfig) -> PathBuf { prebake_config .bootstrap .as_ref() .and_then(|b| b.workspace.as_ref()) .map(|ws| { if ws.fallback { PathBuf::from(DEFAULT_WORKSPACE) } else { PathBuf::from(ws.path.clone()) } }) .unwrap_or_else(|| PathBuf::from(DEFAULT_WORKSPACE)) } fn privileged(prebake_config: &PrebakeConfig) -> bool { if let Some(bootstrap) = &prebake_config.bootstrap { if bootstrap.user == "root" { return true; } } let drop_after = get_drop_after(&prebake_config.security).unwrap_or_default(); PrebakeStage::Never == drop_after } type TaskResult = Result<(), BakeError>; type TaskFn = Box TaskResult + Send>; // TODO: Learn closure and continue // async fn run(f:F) -> TaskFn { // let engine = Engine::new(); // engine.execute_script // } // fn with_timeout(f: F, duration: i32) -> TaskFn { // }