feat(iso): Create generate-iso command (#192)
## Tasks - [x] Add ctrl-c handler to kill spawned children - [x] add more args to support all variables - [x] Add integration test
This commit is contained in:
parent
4634f40840
commit
e6cce3d542
25 changed files with 737 additions and 201 deletions
|
|
@ -4,7 +4,7 @@ use std::{
|
|||
};
|
||||
|
||||
use blue_build_process_management::drivers::{
|
||||
opts::{BuildTagPushOpts, CheckKeyPairOpts, CompressionType},
|
||||
opts::{BuildTagPushOpts, CheckKeyPairOpts, CompressionType, GenerateTagsOpts, SignVerifyOpts},
|
||||
BuildDriver, CiDriver, Driver, DriverArgs, SigningDriver,
|
||||
};
|
||||
use blue_build_recipe::Recipe;
|
||||
|
|
@ -14,11 +14,13 @@ use blue_build_utils::{
|
|||
GITIGNORE_PATH, LABELED_ERROR_MESSAGE, NO_LABEL_ERROR_MESSAGE, RECIPE_FILE, RECIPE_PATH,
|
||||
},
|
||||
credentials::{Credentials, CredentialsArgs},
|
||||
string,
|
||||
};
|
||||
use clap::Args;
|
||||
use colored::Colorize;
|
||||
use log::{debug, info, trace, warn};
|
||||
use miette::{bail, Context, IntoDiagnostic, Result};
|
||||
use oci_distribution::Reference;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
use crate::commands::generate::GenerateCommand;
|
||||
|
|
@ -197,7 +199,6 @@ impl BlueBuildCommand for BuildCommand {
|
|||
impl BuildCommand {
|
||||
#[cfg(feature = "multi-recipe")]
|
||||
fn start(&self, recipe_paths: &[PathBuf]) -> Result<()> {
|
||||
use blue_build_process_management::drivers::opts::SignVerifyOpts;
|
||||
use rayon::prelude::*;
|
||||
|
||||
trace!("BuildCommand::build_image()");
|
||||
|
|
@ -205,54 +206,12 @@ impl BuildCommand {
|
|||
recipe_paths
|
||||
.par_iter()
|
||||
.try_for_each(|recipe_path| -> Result<()> {
|
||||
let recipe = Recipe::parse(recipe_path)?;
|
||||
let containerfile = if recipe_paths.len() > 1 {
|
||||
blue_build_utils::generate_containerfile_path(recipe_path)?
|
||||
} else {
|
||||
PathBuf::from(CONTAINER_FILE)
|
||||
};
|
||||
let tags = Driver::generate_tags(&recipe)?;
|
||||
let image_name = self.generate_full_image_name(&recipe)?;
|
||||
|
||||
let opts = if let Some(archive_dir) = self.archive.as_ref() {
|
||||
BuildTagPushOpts::builder()
|
||||
.containerfile(&containerfile)
|
||||
.archive_path(format!(
|
||||
"{}/{}.{ARCHIVE_SUFFIX}",
|
||||
archive_dir.to_string_lossy().trim_end_matches('/'),
|
||||
recipe.name.to_lowercase().replace('/', "_"),
|
||||
))
|
||||
.squash(self.squash)
|
||||
.build()
|
||||
} else {
|
||||
BuildTagPushOpts::builder()
|
||||
.image(&image_name)
|
||||
.containerfile(&containerfile)
|
||||
.tags(&tags)
|
||||
.push(self.push)
|
||||
.retry_push(self.retry_push)
|
||||
.retry_count(self.retry_count)
|
||||
.compression(self.compression_format)
|
||||
.squash(self.squash)
|
||||
.build()
|
||||
};
|
||||
|
||||
Driver::build_tag_push(&opts)?;
|
||||
|
||||
if self.push && !self.no_sign {
|
||||
let opts = SignVerifyOpts::builder()
|
||||
.image(&image_name)
|
||||
.retry_push(self.retry_push)
|
||||
.retry_count(self.retry_count);
|
||||
let opts = if let Some(tag) = tags.first() {
|
||||
opts.tag(tag).build()
|
||||
} else {
|
||||
opts.build()
|
||||
};
|
||||
Driver::sign_and_verify(&opts)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
self.build(recipe_path, &containerfile)
|
||||
})?;
|
||||
|
||||
info!("Build complete!");
|
||||
|
|
@ -261,18 +220,27 @@ impl BuildCommand {
|
|||
|
||||
#[cfg(not(feature = "multi-recipe"))]
|
||||
fn start(&self, recipe_path: &Path) -> Result<()> {
|
||||
use blue_build_process_management::drivers::opts::SignVerifyOpts;
|
||||
|
||||
trace!("BuildCommand::start()");
|
||||
|
||||
self.build(recipe_path, Path::new(CONTAINER_FILE))?;
|
||||
|
||||
info!("Build complete!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build(&self, recipe_path: &Path, containerfile: &Path) -> Result<()> {
|
||||
let recipe = Recipe::parse(recipe_path)?;
|
||||
let containerfile = PathBuf::from(CONTAINER_FILE);
|
||||
let tags = Driver::generate_tags(&recipe)?;
|
||||
let image_name = self.generate_full_image_name(&recipe)?;
|
||||
let tags = Driver::generate_tags(
|
||||
&GenerateTagsOpts::builder()
|
||||
.oci_ref(&recipe.base_image_ref()?)
|
||||
.alt_tags(recipe.alt_tags())
|
||||
.build(),
|
||||
)?;
|
||||
let image_name = self.image_name(&recipe)?;
|
||||
|
||||
let opts = if let Some(archive_dir) = self.archive.as_ref() {
|
||||
BuildTagPushOpts::builder()
|
||||
.containerfile(&containerfile)
|
||||
.containerfile(containerfile)
|
||||
.archive_path(format!(
|
||||
"{}/{}.{ARCHIVE_SUFFIX}",
|
||||
archive_dir.to_string_lossy().trim_end_matches('/'),
|
||||
|
|
@ -283,7 +251,7 @@ impl BuildCommand {
|
|||
} else {
|
||||
BuildTagPushOpts::builder()
|
||||
.image(&image_name)
|
||||
.containerfile(&containerfile)
|
||||
.containerfile(containerfile)
|
||||
.tags(&tags)
|
||||
.push(self.push)
|
||||
.retry_push(self.retry_push)
|
||||
|
|
@ -308,14 +276,29 @@ impl BuildCommand {
|
|||
Driver::sign_and_verify(&opts)?;
|
||||
}
|
||||
|
||||
info!("Build complete!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn image_name(&self, recipe: &Recipe) -> Result<String> {
|
||||
let image_name = self.generate_full_image_name(recipe)?;
|
||||
|
||||
let image_name = if image_name.registry().is_empty() {
|
||||
string!(image_name.repository())
|
||||
} else {
|
||||
format!(
|
||||
"{}/{}",
|
||||
image_name.resolve_registry(),
|
||||
image_name.repository()
|
||||
)
|
||||
};
|
||||
|
||||
Ok(image_name)
|
||||
}
|
||||
|
||||
/// # Errors
|
||||
///
|
||||
/// Will return `Err` if the image name cannot be generated.
|
||||
fn generate_full_image_name(&self, recipe: &Recipe) -> Result<String> {
|
||||
fn generate_full_image_name(&self, recipe: &Recipe) -> Result<Reference> {
|
||||
trace!("BuildCommand::generate_full_image_name({recipe:#?})");
|
||||
info!("Generating full image name");
|
||||
|
||||
|
|
@ -324,14 +307,18 @@ impl BuildCommand {
|
|||
self.registry_namespace.as_ref().map(|s| s.to_lowercase()),
|
||||
) {
|
||||
trace!("registry={registry}, registry_path={registry_path}");
|
||||
format!(
|
||||
let image = format!(
|
||||
"{}/{}/{}",
|
||||
registry.trim().trim_matches('/'),
|
||||
registry_path.trim().trim_matches('/'),
|
||||
recipe.name.trim(),
|
||||
)
|
||||
);
|
||||
image
|
||||
.parse()
|
||||
.into_diagnostic()
|
||||
.with_context(|| format!("Unable to parse {image}"))?
|
||||
} else {
|
||||
Driver::generate_image_name(recipe)?
|
||||
Driver::generate_image_name(&recipe.name)?
|
||||
};
|
||||
|
||||
debug!("Using image name '{image_name}'");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue