d1ad08ef3a
Implement a priority-based merge system for pipeline configuration. Parameters carry their source (Base, Courier, Bakerd) and only higher-priority writers override. Migrate notification, prebake, bake, and finalize config to use ParamVal wrappers. Remove hardcoded constants and the InteractiveServer component. BREAKING CHANGE: Remove NotAvailable variant from MethodStatus enum
140 lines
4.9 KiB
Rust
140 lines
4.9 KiB
Rust
use workshop_baker::types::resource::ResourceRegistry;
|
|
use std::path::PathBuf;
|
|
|
|
use workshop_baker::{
|
|
bake::bake, cli::{Cli, Commands, Parser},
|
|
error::CliError,
|
|
finalize::finalize, notify::notify, prebake::prebake,
|
|
};
|
|
use workshop_baker::bare::run_bare;
|
|
use workshop_baker::notify::queue::NotificationQueue;
|
|
use workshop_engine::{EventSender, ExecutionContext};
|
|
|
|
fn or_workshop(path: &Option<PathBuf>, name: &str) -> PathBuf {
|
|
path.clone().unwrap_or_else(|| PathBuf::from(format!(".workshop/{}", name)))
|
|
}
|
|
|
|
async fn worker_main(cli: Cli) -> Result<(), CliError> {
|
|
let prebake_path = cli.prebake.clone().unwrap_or_else(|| {
|
|
log::error!("--prebake is required in worker standalone mode");
|
|
std::process::exit(1);
|
|
});
|
|
let bake_path = cli.bake.clone().unwrap_or_else(|| {
|
|
log::error!("--bake is required in worker standalone mode");
|
|
std::process::exit(1);
|
|
});
|
|
let finalize_path = cli.finalize.clone().unwrap_or_else(|| {
|
|
log::error!("--finalize is required in worker standalone mode");
|
|
std::process::exit(1);
|
|
});
|
|
|
|
log::info!("Worker standalone mode");
|
|
|
|
let mut ctx = ExecutionContext {
|
|
standalone: true,
|
|
task_id: format!("{}-{}-worker", cli.pipeline, cli.build_id),
|
|
pipeline_name: cli.pipeline.clone(),
|
|
username: cli.username.clone(),
|
|
dry_run: cli.dry_run,
|
|
privileged: false,
|
|
..Default::default()
|
|
};
|
|
|
|
let (tx, event_rx) = tokio::sync::mpsc::channel(256);
|
|
let event_tx: EventSender = Some(tx);
|
|
let _event_handle = tokio::spawn(workshop_baker::prebake::event::event_receiver(
|
|
event_rx, cli.pipeline.clone(), cli.build_id.clone(),
|
|
));
|
|
|
|
let (to_tx, to_rx) = tokio::sync::mpsc::channel(256);
|
|
let (retry_tx, retry_rx) = tokio::sync::mpsc::channel(256);
|
|
|
|
// Resource registry — populated before stages, consumed by stages
|
|
let registry = ResourceRegistry::new();
|
|
// TODO: pre-fetch plugins and templates into registry
|
|
|
|
let notify_path = finalize_path.clone();
|
|
let notify_ctx = ctx.clone();
|
|
let notify_etx = event_tx.clone();
|
|
let debug = cli.debug.clone();
|
|
let notify_registry = registry.clone();
|
|
let notify_handle = tokio::spawn(async move {
|
|
notify(¬ify_path, &mut notify_ctx.clone(), notify_etx, to_rx, retry_tx, debug.map(|d| d.contains("notify")).unwrap_or(false), ¬ify_registry).await
|
|
});
|
|
|
|
let nevent_tx = to_tx.clone();
|
|
let mut queue = NotificationQueue::new(to_tx, retry_rx);
|
|
|
|
let pipe_result: anyhow::Result<()> = async {
|
|
prebake(&prebake_path, &cli, None, &mut ctx, event_tx.clone(), Some(nevent_tx)).await?;
|
|
let bake_base_path = or_workshop(&cli.bake_base, "bake_base.sh");
|
|
let pb_path = or_workshop(&cli.prebake, "prebake.yml");
|
|
bake(&bake_path, &bake_base_path, &pb_path, &cli, &mut ctx, event_tx.clone()).await?;
|
|
finalize(&finalize_path, &cli, &mut ctx, event_tx.clone(), ®istry).await?;
|
|
Ok(())
|
|
}.await;
|
|
|
|
if let Err(e) = pipe_result {
|
|
log::error!("Pipeline stage failed: {}", e);
|
|
return Err(CliError::General(e));
|
|
}
|
|
|
|
log::info!("Pipeline complete. Draining notifications...");
|
|
if let Err(e) = queue.drain().await {
|
|
log::error!("Notification queue error: {}", e);
|
|
}
|
|
let _ = notify_handle.await;
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
env_logger::init();
|
|
let cli = Cli::parse();
|
|
if cli.dry_run {
|
|
log::warn!("Dry run enabled, no changes will be made.");
|
|
}
|
|
|
|
let pipeline = cli.pipeline.clone();
|
|
let build_id = cli.build_id.clone();
|
|
|
|
match &cli.command {
|
|
Some(Commands::Bare { command }) => {
|
|
let mut ctx = ExecutionContext {
|
|
standalone: true,
|
|
task_id: format!("{}-{}-bare", pipeline, build_id),
|
|
pipeline_name: pipeline.clone(),
|
|
username: cli.username.clone(),
|
|
dry_run: cli.dry_run,
|
|
privileged: false,
|
|
..Default::default()
|
|
};
|
|
let (tx, event_rx) = tokio::sync::mpsc::channel(256);
|
|
let event_tx: EventSender = Some(tx);
|
|
let event_handle = tokio::spawn(workshop_baker::prebake::event::event_receiver(
|
|
event_rx, pipeline.clone(), build_id.clone(),
|
|
));
|
|
|
|
let registry = ResourceRegistry::new();
|
|
let result = run_bare(&cli, command, &mut ctx, event_tx, &pipeline, &build_id, ®istry).await;
|
|
|
|
drop(ctx);
|
|
let _ = event_handle.await;
|
|
|
|
if let Err(e) = result {
|
|
log::error!("{}", e);
|
|
std::process::exit(e.exit_code());
|
|
}
|
|
}
|
|
Some(Commands::Daemon {}) => {
|
|
unimplemented!("Daemon mode not implemented");
|
|
}
|
|
None => {
|
|
if let Err(e) = worker_main(cli).await {
|
|
log::error!("{}", e);
|
|
std::process::exit(e.exit_code());
|
|
}
|
|
}
|
|
}
|
|
}
|