Build a Docker image for the given configuration # Arguments `stack` - The stack layer (e.g., "rust", "python", "default") `agent` - The agent layer (e.g., "claude") `project` - Optional project layer (defaults to "default") `options` - Build options (cache, dry run, build root, log path) `resolved_config` - Optional resolved config for inline layer overrides # Returns The Docker image tag (e.g.
(
&self,
stack: &str,
agent: &str,
project: Option<&str>,
options: &BuildOptions<'_>,
resolved_config: Option<&ResolvedConfig>,
)
| 359 | /// # Returns |
| 360 | /// The Docker image tag (e.g., "tsk/rust/claude/web-api") |
| 361 | pub async fn build_image( |
| 362 | &self, |
| 363 | stack: &str, |
| 364 | agent: &str, |
| 365 | project: Option<&str>, |
| 366 | options: &BuildOptions<'_>, |
| 367 | resolved_config: Option<&ResolvedConfig>, |
| 368 | ) -> Result<String> { |
| 369 | let project = project.unwrap_or("default"); |
| 370 | |
| 371 | // Extract inline overrides from config |
| 372 | let overrides = Self::extract_inline_overrides(resolved_config, stack, agent); |
| 373 | |
| 374 | // Create configuration |
| 375 | let config = Self::create_config(stack, agent, project); |
| 376 | |
| 377 | // Compose the Dockerfile |
| 378 | let composed = self |
| 379 | .composer |
| 380 | .compose(&config, overrides.as_ref(), resolved_config) |
| 381 | .with_context(|| format!("Failed to compose Dockerfile for {}", config.image_tag()))?; |
| 382 | |
| 383 | // Validate the composed Dockerfile |
| 384 | self.composer |
| 385 | .validate_dockerfile(&composed.dockerfile_content) |
| 386 | .with_context(|| "Dockerfile validation failed")?; |
| 387 | |
| 388 | if options.dry_run { |
| 389 | self.print_dry_run_output(&composed, stack, agent, project); |
| 390 | } else { |
| 391 | // Normal mode: build the image |
| 392 | // Get git configuration from the repository (or global config as fallback) |
| 393 | let git_user_name = get_git_config_from_repo(options.build_root, "user.name")?; |
| 394 | let git_user_email = get_git_config_from_repo(options.build_root, "user.email")?; |
| 395 | |
| 396 | // Get agent version if available |
| 397 | let agent_version = if let Ok(agent_instance) = |
| 398 | crate::agent::AgentProvider::get_agent(agent, self.ctx.tsk_env()) |
| 399 | { |
| 400 | Some(agent_instance.version()) |
| 401 | } else { |
| 402 | None |
| 403 | }; |
| 404 | |
| 405 | // Build the image |
| 406 | self.build_docker_image( |
| 407 | &composed, |
| 408 | &git_user_name, |
| 409 | &git_user_email, |
| 410 | agent_version.as_deref(), |
| 411 | options, |
| 412 | ) |
| 413 | .await?; |
| 414 | } |
| 415 | |
| 416 | Ok(format!("tsk/{stack}/{agent}/{project}")) |
| 417 | } |
| 418 |