use crate::cli::DevArgs;
use crate::context::WorkspaceContext;
use crate::docker::{DockerCompose, reclaim_stale_ports};
use crate::env_writer::EnvWriter;
use crate::services::get_active_services;
use crate::supervisor::{ShutdownSignal, Supervisor};
use anyhow::{Context, Result};
use colored::Colorize;
pub fn execute_dev(ctx: &WorkspaceContext, args: &DevArgs) -> Result<()> {
let shutdown = ShutdownSignal::install()?;
println!(
"{} Starting dev environment for project '{}' (project: {})...",
"[dev]".blue().bold(),
ctx.config.name,
ctx.compose_project.cyan()
);
reclaim_stale_ports(ctx);
let compose = DockerCompose::new(ctx)?;
if args.reset {
println!(
"{} Resetting services for project '{}' (wiping volumes)...",
"[dev]".yellow().bold(),
ctx.compose_project.cyan()
);
compose.down(true)?;
}
EnvWriter::write_workspace_env(ctx)?;
let dev_command = if args.no_command {
None
} else if !args.command.is_empty() {
Some(args.command.join(" "))
} else {
ctx.config.dev_command.clone()
};
if let Some(cmd) = &dev_command {
ctx.interpolate(cmd)?;
}
let result = start_and_supervise(ctx, &compose, &shutdown, dev_command.as_deref());
if let Err(e) = compose.stop() {
eprintln!("{} Warning: {:#}", "[dev]".yellow().bold(), e);
}
if shutdown.requested() { Ok(()) } else { result }
}
fn start_and_supervise(
ctx: &WorkspaceContext,
compose: &DockerCompose<'_>,
shutdown: &ShutdownSignal,
dev_command: Option<&str>,
) -> Result<()> {
compose.up()?;
for service in get_active_services(ctx) {
if shutdown.requested() {
return Ok(());
}
service
.post_start(ctx, compose)
.with_context(|| format!("Service '{}' failed to initialize", service.name()))?;
}
if shutdown.requested() {
return Ok(());
}
Supervisor::run_dev(ctx, compose, shutdown, dev_command)
}