|
1 | 1 | use anyhow::*; |
2 | 2 | use flate2::{write::GzEncoder, Compression}; |
3 | 3 | use serde_json::json; |
4 | | -use std::{collections::HashMap, io::Write, path::Path, result::Result::Ok, time::Duration}; |
| 4 | +use std::{collections::HashMap, io::Write, path::{Path, PathBuf}, result::Result::Ok, time::Duration}; |
5 | 5 | use tempfile::NamedTempFile; |
6 | 6 | use uuid::Uuid; |
7 | 7 |
|
@@ -380,25 +380,84 @@ async fn get_or_create_ci_manager_actor( |
380 | 380 | Ok((create_response.actor.id.to_string(), endpoint.clone())) |
381 | 381 | } |
382 | 382 |
|
| 383 | +/// Moves over build context to a temp directory, |
| 384 | +/// ignoring all .dockerignore files. |
| 385 | +fn prepare_build_context_dir( |
| 386 | + build_path: &Path, |
| 387 | + dockerfile_path: &Path |
| 388 | +) -> Result<Vec<PathBuf>> { |
| 389 | + const DOCKERIGNORE_FILENAME: &str = ".dockerignore"; |
| 390 | + |
| 391 | + let mut paths = Vec::new(); |
| 392 | + |
| 393 | + // For Kaniko on the remote build, we need to expose |
| 394 | + // our Dockerfile and our .dockerignore file if it |
| 395 | + // exists |
| 396 | + paths.push(dockerfile_path.to_path_buf()); |
| 397 | + |
| 398 | + let dockerignore_path = build_path.join(DOCKERIGNORE_FILENAME); |
| 399 | + if dockerignore_path.try_exists().unwrap_or(false) { |
| 400 | + paths.push(dockerignore_path.clone()); |
| 401 | + } |
| 402 | + |
| 403 | + let walk = ignore::WalkBuilder::new(build_path) |
| 404 | + .standard_filters(false) |
| 405 | + .add_custom_ignore_filename(DOCKERIGNORE_FILENAME) |
| 406 | + .parents(true) |
| 407 | + .build(); |
| 408 | + |
| 409 | + for entry in walk { |
| 410 | + let entry = entry?; |
| 411 | + |
| 412 | + if entry.path() == dockerfile_path || entry.path() == &dockerignore_path { |
| 413 | + // Skip the Dockerfile or .dockerignore itself, we already added it |
| 414 | + continue; |
| 415 | + } |
| 416 | + |
| 417 | + let is_file = entry.file_type() |
| 418 | + .map(|ft| ft.is_file()) |
| 419 | + .unwrap_or(false); |
| 420 | + |
| 421 | + if is_file { |
| 422 | + let file_path = entry.path(); |
| 423 | + |
| 424 | + paths.push(file_path.to_path_buf()); |
| 425 | + } |
| 426 | + } |
| 427 | + |
| 428 | + Ok(paths) |
| 429 | +} |
| 430 | + |
383 | 431 | async fn create_build_context_archive( |
384 | 432 | task: task::TaskCtx, |
385 | 433 | build_path: &Path, |
386 | | - _dockerfile: &Path, |
| 434 | + dockerfile: &Path, |
387 | 435 | ) -> Result<Vec<u8>> { |
388 | 436 | task.log(format!( |
389 | 437 | "[Remote Build] Creating gzipped tar archive from build path: {:?}", |
390 | 438 | build_path |
391 | 439 | )); |
392 | 440 |
|
| 441 | + let dockerfile_path_buf = build_path.join(dockerfile); |
| 442 | + let dockerfile = Path::new(&dockerfile_path_buf); |
| 443 | + |
| 444 | + // Get a list of all paths that weren't in .dockerignore |
| 445 | + let build_file_paths = prepare_build_context_dir(build_path, dockerfile)?; |
| 446 | + |
393 | 447 | // Create a gzipped tar archive of the build context |
394 | 448 | let mut archive_data = Vec::new(); |
395 | 449 | { |
396 | 450 | let gz_encoder = GzEncoder::new(&mut archive_data, Compression::default()); |
397 | 451 | let mut tar = tar::Builder::new(gz_encoder); |
398 | 452 |
|
399 | | - // Add the entire build directory to the archive |
400 | | - tar.append_dir_all(".", build_path) |
401 | | - .context("Failed to create build context archive")?; |
| 453 | + // Add the prepared build file paths to the archive |
| 454 | + for file_path in build_file_paths.iter() { |
| 455 | + let relative_path = file_path.strip_prefix(build_path) |
| 456 | + .context("Failed to strip build path prefix")?; |
| 457 | + |
| 458 | + tar.append_path_with_name(&file_path, relative_path) |
| 459 | + .context(format!("Failed to add file to tar: {:?}", file_path))?; |
| 460 | + } |
402 | 461 |
|
403 | 462 | tar.finish().context("Failed to finalize tar archive")?; |
404 | 463 | } |
|
0 commit comments