use crate::agent::task_logger::TaskLogger;
use crate::commands::Command;
use crate::context::AppContext;
use crate::context::docker_client::DefaultDockerClient;
use crate::docker::image_manager::{BuildOptions, DockerImageManager};
use crate::repo_utils::find_repository_root;
use async_trait::async_trait;
use std::error::Error;
use std::sync::Arc;
pub struct DockerBuildCommand {
pub no_cache: bool,
pub stack: Option<String>,
pub agent: Option<String>,
pub project: Option<String>,
pub dry_run: bool,
pub proxy_only: bool,
}
#[async_trait]
impl Command for DockerBuildCommand {
async fn execute(&self, ctx: &AppContext) -> Result<(), Box<dyn Error>> {
let docker_client = Arc::new(
DefaultDockerClient::new(&ctx.tsk_config().container_engine)
.map_err(|e| -> Box<dyn Error> { e.into() })?,
);
if self.proxy_only {
println!("Building tsk/proxy image...");
use crate::docker::proxy_manager::ProxyManager;
let proxy_manager = ProxyManager::new(
docker_client,
ctx.tsk_env(),
ctx.tsk_config().container_engine.clone(),
None,
);
proxy_manager
.build_proxy(self.no_cache, &TaskLogger::no_file())
.await?;
println!("Successfully built Docker image: tsk/proxy");
return Ok(());
}
let project_root = find_repository_root(std::path::Path::new(".")).ok();
let project = match &self.project {
Some(p) => Some(p.clone()),
None => {
let repo_root = project_root
.clone()
.unwrap_or_else(|| std::path::PathBuf::from("."));
match crate::repository::detect_project_name(&repo_root).await {
Ok(detected) => Some(detected),
Err(e) => {
eprintln!("Warning: Failed to detect project name: {e}. Using default.");
Some("default".to_string())
}
}
}
};
let project_name = project.as_deref().unwrap_or("default");
let tsk_config = ctx.tsk_config();
let project_config = project_root
.as_deref()
.and_then(crate::context::tsk_config::load_project_config);
let resolved_config = tsk_config.resolve_config(
project_name,
project_config.as_ref(),
project_root.as_deref(),
);
let repo_root = project_root
.clone()
.unwrap_or_else(|| std::path::PathBuf::from("."));
let stack = crate::context::tsk_config::resolve_stack(
self.stack.clone(),
&tsk_config,
project_name,
project_config.as_ref(),
&repo_root,
)
.await;
let agent = crate::context::tsk_config::resolve_agent(self.agent.clone(), &resolved_config);
let image_manager = DockerImageManager::new(ctx, docker_client.clone(), None);
let image_tag = image_manager
.build_image(
&stack,
&agent,
project.as_deref(),
&BuildOptions {
no_cache: self.no_cache,
dry_run: self.dry_run,
build_root: project_root.as_deref(),
logger: &TaskLogger::no_file(),
},
Some(&resolved_config),
)
.await?;
if !self.dry_run {
println!("Successfully built Docker image: {}", image_tag);
println!("\nBuilding tsk/proxy image...");
use crate::docker::proxy_manager::ProxyManager;
let proxy_manager = ProxyManager::new(
docker_client,
ctx.tsk_env(),
ctx.tsk_config().container_engine.clone(),
None,
);
proxy_manager
.build_proxy(self.no_cache, &TaskLogger::no_file())
.await?;
println!("Successfully built Docker image: tsk/proxy");
println!("\nAll Docker images built successfully!");
}
Ok(())
}
}