diff --git a/process/drivers.rs b/process/drivers.rs index 596fb6b..80dcd11 100644 --- a/process/drivers.rs +++ b/process/drivers.rs @@ -5,6 +5,7 @@ //! labels for an image. use std::{ + borrow::Borrow, collections::{hash_map::Entry, HashMap}, fmt::Debug, process::{ExitStatus, Output}, @@ -17,7 +18,7 @@ use log::{debug, info, trace}; use miette::{miette, Result}; use oci_distribution::Reference; use once_cell::sync::Lazy; -use opts::GenerateTagsOpts; +use opts::{GenerateImageNameOpts, GenerateTagsOpts}; #[cfg(feature = "sigstore")] use sigstore_driver::SigstoreDriver; use typed_builder::TypedBuilder; @@ -402,10 +403,10 @@ impl CiDriver for Driver { impl_ci_driver!(get_registry()) } - fn generate_image_name(name: S) -> Result + fn generate_image_name<'a, O>(opts: O) -> Result where - S: AsRef, + O: Borrow>, { - impl_ci_driver!(generate_image_name(name)) + impl_ci_driver!(generate_image_name(opts)) } } diff --git a/process/drivers/local_driver.rs b/process/drivers/local_driver.rs index 2f53cf1..5cda4ce 100644 --- a/process/drivers/local_driver.rs +++ b/process/drivers/local_driver.rs @@ -1,7 +1,6 @@ use blue_build_utils::string_vec; use log::trace; -use miette::{bail, Context, IntoDiagnostic}; -use oci_distribution::Reference; +use miette::bail; use super::{opts::GenerateTagsOpts, CiDriver, Driver}; @@ -37,19 +36,6 @@ impl CiDriver for LocalDriver { )) } - fn generate_image_name(name: S) -> miette::Result - where - S: AsRef, - { - fn inner(name: &str) -> miette::Result { - trace!("LocalDriver::generate_image_name({name})"); - name.parse() - .into_diagnostic() - .with_context(|| format!("Unable to parse {name}")) - } - inner(&name.as_ref().trim().to_lowercase()) - } - fn get_repo_url() -> miette::Result { trace!("LocalDriver::get_repo_url()"); Ok(String::new()) @@ -57,6 +43,6 @@ impl CiDriver for LocalDriver { fn get_registry() -> miette::Result { trace!("LocalDriver::get_registry()"); - Ok(String::new()) + Ok(String::from("localhost")) } } diff --git a/process/drivers/opts/ci.rs b/process/drivers/opts/ci.rs index 29138ad..a2e8407 100644 --- a/process/drivers/opts/ci.rs +++ b/process/drivers/opts/ci.rs @@ -10,3 +10,15 @@ pub struct GenerateTagsOpts<'scope> { #[builder(default, setter(into))] pub alt_tags: Option>>, } + +#[derive(Debug, Clone, TypedBuilder)] +pub struct GenerateImageNameOpts<'scope> { + #[builder(default, setter(into))] + pub name: Cow<'scope, str>, + + #[builder(default, setter(into))] + pub registry: Option>, + + #[builder(default, setter(into))] + pub registry_namespace: Option>, +} diff --git a/process/drivers/traits.rs b/process/drivers/traits.rs index 22f8487..c1c229c 100644 --- a/process/drivers/traits.rs +++ b/process/drivers/traits.rs @@ -1,4 +1,5 @@ use std::{ + borrow::Borrow, path::PathBuf, process::{ExitStatus, Output}, }; @@ -14,9 +15,9 @@ use crate::drivers::{functions::get_private_key, types::CiDriverType, Driver}; use super::{ image_metadata::ImageMetadata, opts::{ - BuildOpts, BuildTagPushOpts, CheckKeyPairOpts, GenerateKeyPairOpts, GenerateTagsOpts, - GetMetadataOpts, PushOpts, RunOpts, SignOpts, SignVerifyOpts, TagOpts, VerifyOpts, - VerifyType, + BuildOpts, BuildTagPushOpts, CheckKeyPairOpts, GenerateImageNameOpts, GenerateKeyPairOpts, + GenerateTagsOpts, GetMetadataOpts, PushOpts, RunOpts, SignOpts, SignVerifyOpts, TagOpts, + VerifyOpts, VerifyType, }, }; @@ -308,27 +309,34 @@ pub trait CiDriver { /// /// # Errors /// Will error if the environment variables aren't set. - fn generate_tags(oci_ref: &GenerateTagsOpts) -> Result>; + fn generate_tags(opts: &GenerateTagsOpts) -> Result>; /// Generates the image name based on CI. /// /// # Errors /// Will error if the environment variables aren't set. - fn generate_image_name(name: S) -> Result + fn generate_image_name<'a, O>(opts: O) -> Result where - S: AsRef, + O: Borrow>, { - fn inner(name: &str, registry: &str) -> Result { - let image = format!("{registry}/{name}"); + fn inner(opts: &GenerateImageNameOpts, driver_registry: &str) -> Result { + let image = match (&opts.registry, &opts.registry_namespace) { + (Some(registry), Some(registry_namespace)) => { + format!("{registry}/{registry_namespace}/{}", &opts.name) + } + (Some(registry), None) => { + format!("{registry}/{}", &opts.name) + } + _ => { + format!("{}/{}", driver_registry, &opts.name) + } + }; image .parse() .into_diagnostic() .with_context(|| format!("Unable to parse image {image}")) } - inner( - &name.as_ref().trim().to_lowercase(), - &Self::get_registry()?.to_lowercase(), - ) + inner(opts.borrow(), &Self::get_registry()?) } /// Get the URL for the repository. diff --git a/recipe/src/recipe.rs b/recipe/src/recipe.rs index 02a6707..cbbc247 100644 --- a/recipe/src/recipe.rs +++ b/recipe/src/recipe.rs @@ -126,10 +126,11 @@ impl<'a> Recipe<'a> { /// # Errors /// Will error if it fails to parse the `base_image`. pub fn base_image_ref(&self) -> Result { - self.base_image + let base_image = format!("{}:{}", self.base_image, self.image_version); + base_image .parse() .into_diagnostic() - .with_context(|| format!("Unable to parse base image {}", self.base_image)) + .with_context(|| format!("Unable to parse base image {base_image}")) } #[must_use] diff --git a/src/commands/build.rs b/src/commands/build.rs index e884a50..947f629 100644 --- a/src/commands/build.rs +++ b/src/commands/build.rs @@ -4,7 +4,10 @@ use std::{ }; use blue_build_process_management::drivers::{ - opts::{BuildTagPushOpts, CheckKeyPairOpts, CompressionType, GenerateTagsOpts, SignVerifyOpts}, + opts::{ + BuildTagPushOpts, CheckKeyPairOpts, CompressionType, GenerateImageNameOpts, + GenerateTagsOpts, SignVerifyOpts, + }, BuildDriver, CiDriver, Driver, DriverArgs, SigningDriver, }; use blue_build_recipe::Recipe; @@ -13,14 +16,14 @@ use blue_build_utils::{ ARCHIVE_SUFFIX, BB_REGISTRY_NAMESPACE, BUILD_ID_LABEL, CONFIG_PATH, CONTAINER_FILE, GITIGNORE_PATH, LABELED_ERROR_MESSAGE, NO_LABEL_ERROR_MESSAGE, RECIPE_FILE, RECIPE_PATH, }, + cowstr, credentials::{Credentials, CredentialsArgs}, string, }; use clap::Args; use colored::Colorize; -use log::{debug, info, trace, warn}; +use log::{info, trace, warn}; use miette::{bail, Context, IntoDiagnostic, Result}; -use oci_distribution::Reference; use typed_builder::TypedBuilder; use crate::commands::generate::GenerateCommand; @@ -280,52 +283,25 @@ impl BuildCommand { } fn image_name(&self, recipe: &Recipe) -> Result { - let image_name = self.generate_full_image_name(recipe)?; + let image_name = Driver::generate_image_name( + GenerateImageNameOpts::builder() + .name(recipe.name.trim()) + .registry(self.credentials.registry.as_ref().map(|r| cowstr!(r))) + .registry_namespace(self.registry_namespace.as_ref().map(|r| cowstr!(r))) + .build(), + )?; let image_name = if image_name.registry().is_empty() { string!(image_name.repository()) + } else if image_name.registry() == "" { + image_name.repository().to_string() } else { - format!( - "{}/{}", - image_name.resolve_registry(), - image_name.repository() - ) + format!("{}/{}", image_name.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 { - trace!("BuildCommand::generate_full_image_name({recipe:#?})"); - info!("Generating full image name"); - - let image_name = if let (Some(registry), Some(registry_path)) = ( - self.credentials.registry.as_ref().map(|r| r.to_lowercase()), - self.registry_namespace.as_ref().map(|s| s.to_lowercase()), - ) { - trace!("registry={registry}, registry_path={registry_path}"); - 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.name)? - }; - - debug!("Using image name '{image_name}'"); - - Ok(image_name) - } - fn update_gitignore(&self) -> Result<()> { // Check if the Containerfile exists // - If doesn't => *Build* diff --git a/src/commands/generate.rs b/src/commands/generate.rs index c3581f1..ef7a1a0 100644 --- a/src/commands/generate.rs +++ b/src/commands/generate.rs @@ -91,6 +91,13 @@ impl GenerateCommand { legacy_path.join(RECIPE_FILE) } }); + let registry = if let (Some(registry), Some(registry_namespace)) = + (&self.registry, &self.registry_namespace) + { + format!("{registry}/{registry_namespace}") + } else { + Driver::get_registry()? + }; debug!("Deserializing recipe"); let recipe = Recipe::parse(&recipe_path)?; @@ -113,7 +120,7 @@ impl GenerateCommand { .build_id(Driver::get_build_id()) .recipe(&recipe) .recipe_path(recipe_path.as_path()) - .registry(Driver::get_registry()?) + .registry(registry) .repo(Driver::get_repo_url()?) .exports_tag({ #[allow(clippy::const_is_empty)]