refactor: Make use of Reference to ensure typing

This commit is contained in:
Gerald Pinder 2024-12-24 18:15:37 -05:00
parent f85a761a29
commit 4a7293889d
15 changed files with 230 additions and 205 deletions

View file

@ -200,35 +200,30 @@ impl Driver {
let _ = oci_ref; // silence lint
if true {
return Ok(40);
return Ok(41);
}
}
info!("Retrieving OS version from {oci_ref}");
let inspect_opts = GetMetadataOpts::builder()
.image(format!(
"{}/{}",
oci_ref.resolve_registry(),
oci_ref.repository()
))
.tag(oci_ref.tag().unwrap_or("latest"))
.platform(platform)
.build();
let os_version = Self::get_metadata(&inspect_opts)
.and_then(|inspection| {
inspection.get_version().ok_or_else(|| {
miette!(
"Failed to parse version from metadata for {}",
oci_ref.to_string().bold()
)
})
let os_version = Self::get_metadata(
&GetMetadataOpts::builder()
.image(oci_ref)
.platform(platform)
.build(),
)
.and_then(|inspection| {
inspection.get_version().ok_or_else(|| {
miette!(
"Failed to parse version from metadata for {}",
oci_ref.to_string().bold()
)
})
.or_else(|err| {
warn!("Unable to get version via image inspection due to error:\n{err:?}");
get_version_run_image(oci_ref)
})?;
})
.or_else(|err| {
warn!("Unable to get version via image inspection due to error:\n{err:?}");
get_version_run_image(oci_ref)
})?;
trace!("os_version: {os_version}");
Ok(os_version)
}

View file

@ -1,6 +1,7 @@
use std::{io::Write, process::Stdio};
use blue_build_utils::{cmd, credentials::Credentials};
use colored::Colorize;
use log::{debug, error, info, trace};
use miette::{bail, miette, IntoDiagnostic, Result};
use semver::Version;
@ -83,13 +84,20 @@ impl BuildDriver for BuildahDriver {
fn tag(opts: &TagOpts) -> Result<()> {
trace!("BuildahDriver::tag({opts:#?})");
let mut command = cmd!("buildah", "tag", &*opts.src_image, &*opts.dest_image,);
let dest_image_str = opts.dest_image.to_string();
let mut command = cmd!(
"buildah",
"tag",
opts.src_image.to_string(),
&dest_image_str,
);
trace!("{command:?}");
if command.status().into_diagnostic()?.success() {
info!("Successfully tagged {}!", opts.dest_image);
info!("Successfully tagged {}!", dest_image_str.bold().green());
} else {
bail!("Failed to tag image {}", opts.dest_image);
bail!("Failed to tag image {}", dest_image_str.bold().red());
}
Ok(())
}
@ -97,6 +105,8 @@ impl BuildDriver for BuildahDriver {
fn push(opts: &PushOpts) -> Result<()> {
trace!("BuildahDriver::push({opts:#?})");
let image_str = opts.image.to_string();
let command = cmd!(
"buildah",
"push",
@ -104,18 +114,18 @@ impl BuildDriver for BuildahDriver {
"--compression-format={}",
opts.compression_type.unwrap_or_default()
),
&*opts.image,
&image_str,
);
trace!("{command:?}");
let status = command
.build_status(&opts.image, "Pushing Image")
.build_status(&image_str, "Pushing Image")
.into_diagnostic()?;
if status.success() {
info!("Successfully pushed {}!", opts.image);
info!("Successfully pushed {}!", image_str.bold().green());
} else {
bail!("Failed to push image {}", opts.image);
bail!("Failed to push image {}", image_str.bold().red());
}
Ok(())
}

View file

@ -5,6 +5,7 @@ use blue_build_utils::{
constants::{COSIGN_PASSWORD, COSIGN_PUB_PATH, COSIGN_YES},
credentials::Credentials,
};
use colored::Colorize;
use log::{debug, trace};
use miette::{bail, miette, Context, IntoDiagnostic, Result};
@ -121,27 +122,32 @@ impl SigningDriver for CosignDriver {
}
fn sign(opts: &SignOpts) -> Result<()> {
let image_digest: &str = opts.image.as_ref();
if opts.image.digest().is_none() {
bail!(
"Image ref {} is not a digest ref",
opts.image.to_string().bold().red(),
);
}
let mut command = cmd!(
"cosign",
"sign",
if let Some(ref key) = opts.key => format!("--key={key}"),
"--recursive",
image_digest,
opts.image.to_string(),
COSIGN_PASSWORD => "",
COSIGN_YES => "true",
);
trace!("{command:?}");
if !command.status().into_diagnostic()?.success() {
bail!("Failed to sign {image_digest}");
bail!("Failed to sign {}", opts.image.to_string().bold().red());
}
Ok(())
}
fn verify(opts: &VerifyOpts) -> Result<()> {
let image_name_tag: &str = opts.image.as_ref();
let mut command = cmd!(
"cosign",
"verify",
@ -157,12 +163,12 @@ impl SigningDriver for CosignDriver {
),
};
},
image_name_tag
opts.image.to_string(),
);
trace!("{command:?}");
if !command.status().into_diagnostic()?.success() {
bail!("Failed to verify {image_name_tag}");
bail!("Failed to verify {}", opts.image.to_string().bold().red());
}
Ok(())

View file

@ -13,6 +13,7 @@ use blue_build_utils::{
string_vec,
};
use cached::proc_macro::cached;
use colored::Colorize;
use log::{debug, info, trace, warn};
use miette::{bail, miette, IntoDiagnostic, Result};
use once_cell::sync::Lazy;
@ -154,15 +155,17 @@ impl BuildDriver for DockerDriver {
fn tag(opts: &TagOpts) -> Result<()> {
trace!("DockerDriver::tag({opts:#?})");
let dest_image_str = opts.dest_image.to_string();
trace!("docker tag {} {}", opts.src_image, opts.dest_image);
let status = cmd!("docker", "tag", &*opts.src_image, &*opts.dest_image,)
let status = cmd!("docker", "tag", opts.src_image.to_string(), &dest_image_str)
.status()
.into_diagnostic()?;
if status.success() {
info!("Successfully tagged {}!", opts.dest_image);
info!("Successfully tagged {}!", dest_image_str.bold().green());
} else {
bail!("Failed to tag image {}", opts.dest_image);
bail!("Failed to tag image {}", dest_image_str.bold().red());
}
Ok(())
}
@ -170,15 +173,17 @@ impl BuildDriver for DockerDriver {
fn push(opts: &PushOpts) -> Result<()> {
trace!("DockerDriver::push({opts:#?})");
let image_str = opts.image.to_string();
trace!("docker push {}", opts.image);
let status = cmd!("docker", "push", &*opts.image)
let status = cmd!("docker", "push", &image_str)
.status()
.into_diagnostic()?;
if status.success() {
info!("Successfully pushed {}!", opts.image);
info!("Successfully pushed {}!", image_str.bold().green());
} else {
bail!("Failed to push image {}", opts.image);
bail!("Failed to push image {}", image_str.bold().red());
}
Ok(())
}
@ -315,18 +320,25 @@ impl BuildDriver for DockerDriver {
],
);
let final_images = match (opts.image.as_deref(), opts.archive_path.as_deref()) {
let final_images = match (opts.image, opts.archive_path.as_deref()) {
(Some(image), None) => {
let images = if opts.tags.is_empty() {
cmd!(command, "-t", image);
let image = image.to_string();
cmd!(command, "-t", &image);
string_vec![image]
} else {
opts.tags.iter().for_each(|tag| {
cmd!(command, "-t", format!("{image}:{tag}"));
cmd!(
command,
"-t",
format!("{}/{}:{tag}", image.resolve_registry(), image.repository())
);
});
opts.tags
.iter()
.map(|tag| format!("{image}:{tag}"))
.map(|tag| {
format!("{}/{}:{tag}", image.resolve_registry(), image.repository())
})
.collect()
};
let first_image = images.first().unwrap();
@ -348,8 +360,12 @@ impl BuildDriver for DockerDriver {
images
}
(None, Some(archive_path)) => {
cmd!(command, "--output", format!("type=oci,dest={archive_path}"));
string_vec![archive_path]
cmd!(
command,
"--output",
format!("type=oci,dest={}", archive_path.display())
);
string_vec![archive_path.display().to_string()]
}
(Some(_), Some(_)) => bail!("Cannot use both image and archive path"),
(None, None) => bail!("Need either the image or archive path set"),
@ -385,16 +401,12 @@ impl InspectDriver for DockerDriver {
#[cached(
result = true,
key = "String",
convert = r#"{ format!("{}-{:?}-{}", &*opts.image, opts.tag.as_ref(), opts.platform)}"#,
convert = r#"{ format!("{}-{}", opts.image, opts.platform)}"#,
sync_writes = true
)]
fn get_metadata_cache(opts: &GetMetadataOpts) -> Result<ImageMetadata> {
trace!("DockerDriver::get_metadata({opts:#?})");
let url = opts.tag.as_ref().map_or_else(
|| format!("{}", opts.image),
|tag| format!("{}:{tag}", opts.image),
);
let image_str = opts.image.to_string();
let mut command = cmd!(
"docker",
@ -409,16 +421,16 @@ fn get_metadata_cache(opts: &GetMetadataOpts) -> Result<ImageMetadata> {
"inspect",
"--format",
"{{json .}}",
&url
&image_str,
);
trace!("{command:?}");
let output = command.output().into_diagnostic()?;
if output.status.success() {
info!("Successfully inspected image {url}!");
info!("Successfully inspected image {}!", image_str.bold().green());
} else {
bail!("Failed to inspect image {url}")
bail!("Failed to inspect image {}", image_str.bold().red())
}
serde_json::from_slice::<metadata::Metadata>(&output.stdout)

View file

@ -230,11 +230,11 @@ mod test {
setup_default_branch,
None,
string_vec![
format!("{}-40", &*TIMESTAMP),
format!("{}-41", &*TIMESTAMP),
"latest",
&*TIMESTAMP,
format!("{COMMIT_SHA}-40"),
"40",
format!("{COMMIT_SHA}-41"),
"41",
],
)]
#[case::default_branch_alt_tags(
@ -242,43 +242,43 @@ mod test {
Some(bon::vec![TEST_TAG_1, TEST_TAG_2]),
string_vec![
TEST_TAG_1,
format!("{TEST_TAG_1}-40"),
format!("{}-{TEST_TAG_1}-40", &*TIMESTAMP),
format!("{COMMIT_SHA}-{TEST_TAG_1}-40"),
format!("{TEST_TAG_1}-41"),
format!("{}-{TEST_TAG_1}-41", &*TIMESTAMP),
format!("{COMMIT_SHA}-{TEST_TAG_1}-41"),
TEST_TAG_2,
format!("{TEST_TAG_2}-40"),
format!("{}-{TEST_TAG_2}-40", &*TIMESTAMP),
format!("{COMMIT_SHA}-{TEST_TAG_2}-40"),
format!("{TEST_TAG_2}-41"),
format!("{}-{TEST_TAG_2}-41", &*TIMESTAMP),
format!("{COMMIT_SHA}-{TEST_TAG_2}-41"),
],
)]
#[case::pr_branch(
setup_pr_branch,
None,
string_vec!["pr-12-40", format!("{COMMIT_SHA}-40")],
string_vec!["pr-12-41", format!("{COMMIT_SHA}-41")],
)]
#[case::pr_branch_alt_tags(
setup_pr_branch,
Some(bon::vec![TEST_TAG_1, TEST_TAG_2]),
string_vec![
format!("pr-12-{TEST_TAG_1}-40"),
format!("{COMMIT_SHA}-{TEST_TAG_1}-40"),
format!("pr-12-{TEST_TAG_2}-40"),
format!("{COMMIT_SHA}-{TEST_TAG_2}-40"),
format!("pr-12-{TEST_TAG_1}-41"),
format!("{COMMIT_SHA}-{TEST_TAG_1}-41"),
format!("pr-12-{TEST_TAG_2}-41"),
format!("{COMMIT_SHA}-{TEST_TAG_2}-41"),
],
)]
#[case::branch(
setup_branch,
None,
string_vec![format!("{COMMIT_SHA}-40"), "br-test-40"],
string_vec![format!("{COMMIT_SHA}-41"), "br-test-41"],
)]
#[case::branch_alt_tags(
setup_branch,
Some(bon::vec![TEST_TAG_1, TEST_TAG_2]),
string_vec![
format!("br-{BR_REF_NAME}-{TEST_TAG_1}-40"),
format!("{COMMIT_SHA}-{TEST_TAG_1}-40"),
format!("br-{BR_REF_NAME}-{TEST_TAG_2}-40"),
format!("{COMMIT_SHA}-{TEST_TAG_2}-40"),
format!("br-{BR_REF_NAME}-{TEST_TAG_1}-41"),
format!("{COMMIT_SHA}-{TEST_TAG_1}-41"),
format!("br-{BR_REF_NAME}-{TEST_TAG_2}-41"),
format!("{COMMIT_SHA}-{TEST_TAG_2}-41"),
],
)]
fn generate_tags(

View file

@ -238,11 +238,11 @@ mod test {
setup_default_branch,
None,
string_vec![
format!("{}-40", &*TIMESTAMP),
format!("{}-41", &*TIMESTAMP),
"latest",
&*TIMESTAMP,
format!("{COMMIT_SHA}-40"),
"40",
format!("{COMMIT_SHA}-41"),
"41",
],
)]
#[case::default_branch_alt_tags(
@ -250,43 +250,43 @@ mod test {
Some(bon::vec![TEST_TAG_1, TEST_TAG_2]),
string_vec![
TEST_TAG_1,
format!("{TEST_TAG_1}-40"),
format!("{}-{TEST_TAG_1}-40", &*TIMESTAMP),
format!("{COMMIT_SHA}-{TEST_TAG_1}-40"),
format!("{TEST_TAG_1}-41"),
format!("{}-{TEST_TAG_1}-41", &*TIMESTAMP),
format!("{COMMIT_SHA}-{TEST_TAG_1}-41"),
TEST_TAG_2,
format!("{TEST_TAG_2}-40"),
format!("{}-{TEST_TAG_2}-40", &*TIMESTAMP),
format!("{COMMIT_SHA}-{TEST_TAG_2}-40"),
format!("{TEST_TAG_2}-41"),
format!("{}-{TEST_TAG_2}-41", &*TIMESTAMP),
format!("{COMMIT_SHA}-{TEST_TAG_2}-41"),
],
)]
#[case::pr_branch(
setup_mr_branch,
None,
string_vec!["mr-12-40", format!("{COMMIT_SHA}-40")],
string_vec!["mr-12-41", format!("{COMMIT_SHA}-41")],
)]
#[case::pr_branch_alt_tags(
setup_mr_branch,
Some(bon::vec![TEST_TAG_1, TEST_TAG_2]),
string_vec![
format!("mr-12-{TEST_TAG_1}-40"),
format!("{COMMIT_SHA}-{TEST_TAG_1}-40"),
format!("mr-12-{TEST_TAG_2}-40"),
format!("{COMMIT_SHA}-{TEST_TAG_2}-40"),
format!("mr-12-{TEST_TAG_1}-41"),
format!("{COMMIT_SHA}-{TEST_TAG_1}-41"),
format!("mr-12-{TEST_TAG_2}-41"),
format!("{COMMIT_SHA}-{TEST_TAG_2}-41"),
],
)]
#[case::branch(
setup_branch,
None,
string_vec![format!("{COMMIT_SHA}-40"), "br-test-40"],
string_vec![format!("{COMMIT_SHA}-41"), "br-test-41"],
)]
#[case::branch_alt_tags(
setup_branch,
Some(bon::vec![TEST_TAG_1, TEST_TAG_2]),
string_vec![
format!("br-{BR_REF_NAME}-{TEST_TAG_1}-40"),
format!("{COMMIT_SHA}-{TEST_TAG_1}-40"),
format!("br-{BR_REF_NAME}-{TEST_TAG_2}-40"),
format!("{COMMIT_SHA}-{TEST_TAG_2}-40"),
format!("br-{BR_REF_NAME}-{TEST_TAG_1}-41"),
format!("{COMMIT_SHA}-{TEST_TAG_1}-41"),
format!("br-{BR_REF_NAME}-{TEST_TAG_2}-41"),
format!("{COMMIT_SHA}-{TEST_TAG_2}-41"),
],
)]
fn generate_tags(

View file

@ -1,6 +1,7 @@
use std::{borrow::Cow, path::Path};
use bon::Builder;
use oci_distribution::Reference;
use crate::drivers::types::Platform;
@ -26,16 +27,14 @@ pub struct BuildOpts<'scope> {
}
#[derive(Debug, Clone, Builder)]
#[builder(on(Cow<'_, str>, into))]
pub struct TagOpts<'scope> {
pub src_image: Cow<'scope, str>,
pub dest_image: Cow<'scope, str>,
pub src_image: &'scope Reference,
pub dest_image: &'scope Reference,
}
#[derive(Debug, Clone, Builder)]
pub struct PushOpts<'scope> {
#[builder(into)]
pub image: Cow<'scope, str>,
pub image: &'scope Reference,
pub compression_type: Option<CompressionType>,
}
@ -55,14 +54,13 @@ pub struct BuildTagPushOpts<'scope> {
/// NOTE: This SHOULD NOT contain the tag of the image.
///
/// NOTE: You cannot have this set with `archive_path` set.
#[builder(into)]
pub image: Option<Cow<'scope, str>>,
pub image: Option<&'scope Reference>,
/// The path to the archive file.
///
/// NOTE: You cannot have this set with image set.
#[builder(into)]
pub archive_path: Option<Cow<'scope, str>>,
pub archive_path: Option<Cow<'scope, Path>>,
/// The path to the Containerfile to build.
#[builder(into)]

View file

@ -1,6 +1,5 @@
use std::borrow::Cow;
use bon::Builder;
use oci_distribution::Reference;
use crate::drivers::types::Platform;
@ -8,10 +7,7 @@ use crate::drivers::types::Platform;
#[builder(derive(Clone))]
pub struct GetMetadataOpts<'scope> {
#[builder(into)]
pub image: Cow<'scope, str>,
#[builder(into)]
pub tag: Option<Cow<'scope, str>>,
pub image: &'scope Reference,
#[builder(default)]
pub platform: Platform,

View file

@ -6,6 +6,7 @@ use std::{
use bon::Builder;
use miette::{IntoDiagnostic, Result};
use oci_distribution::Reference;
use zeroize::{Zeroize, Zeroizing};
use crate::drivers::types::Platform;
@ -69,7 +70,7 @@ pub struct CheckKeyPairOpts<'scope> {
#[derive(Debug, Clone, Builder)]
pub struct SignOpts<'scope> {
#[builder(into)]
pub image: Cow<'scope, str>,
pub image: &'scope Reference,
#[builder(into)]
pub key: Option<Cow<'scope, str>>,
@ -90,17 +91,14 @@ pub enum VerifyType<'scope> {
#[derive(Debug, Clone, Builder)]
pub struct VerifyOpts<'scope> {
#[builder(into)]
pub image: Cow<'scope, str>,
pub image: &'scope Reference,
pub verify_type: VerifyType<'scope>,
}
#[derive(Debug, Clone, Builder)]
pub struct SignVerifyOpts<'scope> {
#[builder(into)]
pub image: Cow<'scope, str>,
#[builder(into)]
pub tag: Option<Cow<'scope, str>>,
pub image: &'scope Reference,
#[builder(into)]
pub dir: Option<Cow<'scope, Path>>,

View file

@ -167,15 +167,17 @@ impl BuildDriver for PodmanDriver {
fn tag(opts: &TagOpts) -> Result<()> {
trace!("PodmanDriver::tag({opts:#?})");
let mut command = cmd!("podman", "tag", &*opts.src_image, &*opts.dest_image,);
let dest_image_str = opts.dest_image.to_string();
let mut command = cmd!("podman", "tag", opts.src_image.to_string(), &dest_image_str);
trace!("{command:?}");
let status = command.status().into_diagnostic()?;
if status.success() {
info!("Successfully tagged {}!", opts.dest_image);
info!("Successfully tagged {}!", dest_image_str.bold().green());
} else {
bail!("Failed to tag image {}", opts.dest_image);
bail!("Failed to tag image {}", dest_image_str.bold().red());
}
Ok(())
}
@ -183,6 +185,8 @@ impl BuildDriver for PodmanDriver {
fn push(opts: &PushOpts) -> Result<()> {
trace!("PodmanDriver::push({opts:#?})");
let image_str = opts.image.to_string();
let command = cmd!(
"podman",
"push",
@ -190,18 +194,18 @@ impl BuildDriver for PodmanDriver {
"--compression-format={}",
opts.compression_type.unwrap_or_default()
),
&*opts.image,
&image_str,
);
trace!("{command:?}");
let status = command
.build_status(&opts.image, "Pushing Image")
.build_status(&image_str, "Pushing Image")
.into_diagnostic()?;
if status.success() {
info!("Successfully pushed {}!", opts.image);
info!("Successfully pushed {}!", image_str.bold().green());
} else {
bail!("Failed to push image {}", opts.image)
bail!("Failed to push image {}", image_str.bold().red());
}
Ok(())
}
@ -283,23 +287,20 @@ impl InspectDriver for PodmanDriver {
#[cached(
result = true,
key = "String",
convert = r#"{ format!("{}-{:?}-{}", &*opts.image, opts.tag.as_ref(), opts.platform)}"#,
convert = r#"{ format!("{}-{}", opts.image, opts.platform)}"#,
sync_writes = true
)]
fn get_metadata_cache(opts: &GetMetadataOpts) -> Result<ImageMetadata> {
trace!("PodmanDriver::get_metadata({opts:#?})");
let url = opts.tag.as_deref().map_or_else(
|| format!("{}", opts.image),
|tag| format!("{}:{tag}", opts.image),
);
let image_str = opts.image.to_string();
let progress = Logger::multi_progress().add(
ProgressBar::new_spinner()
.with_style(ProgressStyle::default_spinner())
.with_message(format!(
"Inspecting metadata for {}, pulling image...",
url.bold()
image_str.bold()
)),
);
progress.enable_steady_tick(Duration::from_millis(100));
@ -311,17 +312,17 @@ fn get_metadata_cache(opts: &GetMetadataOpts) -> Result<ImageMetadata> {
"--platform",
opts.platform.to_string(),
],
&url,
&image_str,
);
trace!("{command:?}");
let output = command.output().into_diagnostic()?;
if !output.status.success() {
bail!("Failed to pull {} for inspection!", url.bold());
bail!("Failed to pull {} for inspection!", image_str.bold().red());
}
let mut command = cmd!("podman", "image", "inspect", "--format=json", &url);
let mut command = cmd!("podman", "image", "inspect", "--format=json", &image_str);
trace!("{command:?}");
let output = command.output().into_diagnostic()?;
@ -330,9 +331,9 @@ fn get_metadata_cache(opts: &GetMetadataOpts) -> Result<ImageMetadata> {
Logger::multi_progress().remove(&progress);
if output.status.success() {
debug!("Successfully inspected image {url}!");
debug!("Successfully inspected image {}!", image_str.bold().green());
} else {
bail!("Failed to inspect image {url}");
bail!("Failed to inspect image {}", image_str.bold().red());
}
serde_json::from_slice::<Vec<PodmanImageMetadata>>(&output.stdout)
.into_diagnostic()

View file

@ -15,6 +15,7 @@ use blue_build_utils::{
credentials::Credentials,
retry,
};
use colored::Colorize;
use log::{debug, trace};
use miette::{bail, miette, Context, IntoDiagnostic};
use sigstore::{
@ -107,12 +108,16 @@ impl SigningDriver for SigstoreDriver {
fn sign(opts: &SignOpts) -> miette::Result<()> {
trace!("SigstoreDriver::sign({opts:?})");
if opts.image.digest().is_none() {
bail!(
"Image ref {} is not a digest ref",
opts.image.to_string().bold().red(),
);
}
let path = opts.dir.as_ref().map_or_else(|| Path::new("."), |dir| dir);
let mut client = ClientBuilder::default().build().into_diagnostic()?;
let image_digest: &str = opts.image.as_ref();
let image_digest: OciReference = image_digest.parse().into_diagnostic()?;
trace!("{image_digest:?}");
let image_digest: OciReference = opts.image.to_string().parse().into_diagnostic()?;
let signing_scheme = SigningScheme::default();
let key: Zeroizing<Vec<u8>> = get_private_key(path)?.contents()?;
@ -174,8 +179,7 @@ impl SigningDriver for SigstoreDriver {
fn verify(opts: &VerifyOpts) -> miette::Result<()> {
let mut client = ClientBuilder::default().build().into_diagnostic()?;
let image_digest: &str = opts.image.as_ref();
let image_digest: OciReference = image_digest.parse().into_diagnostic()?;
let image_digest: OciReference = opts.image.to_string().parse().into_diagnostic()?;
trace!("{image_digest:?}");
let signing_scheme = SigningScheme::default();

View file

@ -23,21 +23,18 @@ impl InspectDriver for SkopeoDriver {
#[cached(
result = true,
key = "String",
convert = r#"{ format!("{}-{:?}-{}", &*opts.image, opts.tag.as_ref(), opts.platform)}"#,
convert = r#"{ format!("{}-{}", opts.image, opts.platform)}"#,
sync_writes = true
)]
fn get_metadata_cache(opts: &GetMetadataOpts) -> Result<ImageMetadata> {
trace!("SkopeoDriver::get_metadata({opts:#?})");
let url = opts.tag.as_ref().map_or_else(
|| format!("docker://{}", opts.image),
|tag| format!("docker://{}:{tag}", opts.image),
);
let image_str = opts.image.to_string();
let progress = Logger::multi_progress().add(
ProgressBar::new_spinner()
.with_style(ProgressStyle::default_spinner())
.with_message(format!("Inspecting metadata for {}", url.bold())),
.with_message(format!("Inspecting metadata for {}", image_str.bold())),
);
progress.enable_steady_tick(Duration::from_millis(100));
@ -48,7 +45,7 @@ fn get_metadata_cache(opts: &GetMetadataOpts) -> Result<ImageMetadata> {
opts.platform.arch(),
],
"inspect",
&url,
format!("docker://{image_str}"),
stderr = Stdio::inherit(),
);
trace!("{command:?}");
@ -59,9 +56,9 @@ fn get_metadata_cache(opts: &GetMetadataOpts) -> Result<ImageMetadata> {
Logger::multi_progress().remove(&progress);
if output.status.success() {
debug!("Successfully inspected image {url}!");
debug!("Successfully inspected image {}!", image_str.bold().green());
} else {
bail!("Failed to inspect image {url}")
bail!("Failed to inspect image {}", image_str.bold().red());
}
serde_json::from_slice(&output.stdout).into_diagnostic()
}

View file

@ -6,7 +6,7 @@ use std::{
use blue_build_utils::{constants::COSIGN_PUB_PATH, retry, string_vec};
use log::{debug, info, trace};
use miette::{bail, miette, Context, IntoDiagnostic, Result};
use miette::{bail, Context, IntoDiagnostic, Result};
use oci_distribution::Reference;
use semver::{Version, VersionReq};
@ -127,12 +127,9 @@ pub trait BuildDriver: PrivateDriver {
let full_image = match (opts.archive_path.as_ref(), opts.image.as_ref()) {
(Some(archive_path), None) => {
format!("oci-archive:{archive_path}")
format!("oci-archive:{}", archive_path.display())
}
(None, Some(image)) => opts
.tags
.first()
.map_or_else(|| image.to_string(), |tag| format!("{image}:{tag}")),
(None, Some(image)) => image.to_string(),
(Some(_), Some(_)) => bail!("Cannot use both image and archive path"),
(None, None) => bail!("Need either the image or archive path set"),
};
@ -148,25 +145,25 @@ pub trait BuildDriver: PrivateDriver {
Self::build(&build_opts)?;
let image_list: Vec<String> = if !opts.tags.is_empty() && opts.archive_path.is_none() {
let image = opts
.image
.as_ref()
.ok_or_else(|| miette!("Image is required in order to tag"))?;
let image = opts.image.unwrap();
debug!("Tagging all images");
let mut image_list = Vec::with_capacity(opts.tags.len());
for tag in &opts.tags {
debug!("Tagging {} with {tag}", &full_image);
let tagged_image = format!("{image}:{tag}");
let tagged_image: Reference =
format!("{}/{}:{tag}", image.resolve_registry(), image.repository())
.parse()
.into_diagnostic()?;
let tag_opts = TagOpts::builder()
.src_image(&full_image)
.src_image(image)
.dest_image(&tagged_image)
.build();
Self::tag(&tag_opts)?;
image_list.push(tagged_image);
image_list.push(tagged_image.to_string());
if opts.push {
let retry_count = if opts.retry_push { opts.retry_count } else { 0 };
@ -174,12 +171,10 @@ pub trait BuildDriver: PrivateDriver {
debug!("Pushing all images");
// Push images with retries (1s delay between retries)
blue_build_utils::retry(retry_count, 5, || {
let tag_image = format!("{image}:{tag}");
debug!("Pushing image {tag_image}");
debug!("Pushing image {tagged_image}");
let push_opts = PushOpts::builder()
.image(&tag_image)
.image(&tagged_image)
.compression_type(opts.compression)
.build();
@ -516,23 +511,20 @@ pub trait SigningDriver: PrivateDriver {
.as_ref()
.map_or_else(|| PathBuf::from("."), |d| d.to_path_buf());
let image_name: &str = opts.image.as_ref();
let inspect_opts = GetMetadataOpts::builder()
.image(image_name)
.platform(opts.platform);
let inspect_opts = if let Some(ref tag) = opts.tag {
inspect_opts.tag(&**tag).build()
} else {
inspect_opts.build()
};
let image_digest = Driver::get_metadata(&inspect_opts)?.digest;
let image_name_tag = opts
.tag
.as_ref()
.map_or_else(|| image_name.to_owned(), |t| format!("{image_name}:{t}"));
let image_digest = format!("{image_name}@{image_digest}");
let image_digest = Driver::get_metadata(
&GetMetadataOpts::builder()
.image(opts.image)
.platform(opts.platform)
.build(),
)?
.digest;
let image_digest: Reference = format!(
"{}/{}@{image_digest}",
opts.image.resolve_registry(),
opts.image.repository(),
)
.parse()
.into_diagnostic()?;
let (sign_opts, verify_opts) = match (Driver::get_ci_driver(), get_private_key(&path)) {
// Cosign public/private key pair
@ -543,7 +535,7 @@ pub trait SigningDriver: PrivateDriver {
.key(priv_key.to_string())
.build(),
VerifyOpts::builder()
.image(&image_name_tag)
.image(opts.image)
.verify_type(VerifyType::File(path.join(COSIGN_PUB_PATH).into()))
.build(),
),
@ -551,7 +543,7 @@ pub trait SigningDriver: PrivateDriver {
(CiDriverType::Github | CiDriverType::Gitlab, _) => (
SignOpts::builder().dir(&path).image(&image_digest).build(),
VerifyOpts::builder()
.image(&image_name_tag)
.image(opts.image)
.verify_type(VerifyType::Keyless {
issuer: Driver::oidc_provider()?.into(),
identity: Driver::keyless_cert_identity()?.into(),

View file

@ -26,6 +26,7 @@ use bon::Builder;
use clap::Args;
use log::{info, trace, warn};
use miette::{bail, IntoDiagnostic, Result};
use oci_distribution::Reference;
use tempfile::TempDir;
use crate::commands::generate::GenerateCommand;
@ -299,12 +300,15 @@ impl BuildCommand {
.build(),
)?;
let image_name = self.image_name(&recipe)?;
let image: Reference = format!("{image_name}:{}", tags.first().map_or("latest", |tag| tag))
.parse()
.into_diagnostic()?;
let build_fn = || -> Result<Vec<String>> {
Driver::build_tag_push(&self.archive.as_ref().map_or_else(
|| {
BuildTagPushOpts::builder()
.image(&image_name)
.image(&image)
.containerfile(containerfile)
.platform(self.platform)
.tags(tags.collect_cow_vec())
@ -319,11 +323,11 @@ impl BuildCommand {
BuildTagPushOpts::builder()
.containerfile(containerfile)
.platform(self.platform)
.archive_path(format!(
.archive_path(PathBuf::from(format!(
"{}/{}.{ARCHIVE_SUFFIX}",
archive_dir.to_string_lossy().trim_end_matches('/'),
recipe.name.to_lowercase().replace('/', "_"),
))
)))
.squash(self.squash)
.build()
},
@ -337,6 +341,10 @@ impl BuildCommand {
InspectDriver, RechunkDriver,
};
let base_image: Reference = format!("{}:{}", &recipe.base_image, &recipe.image_version)
.parse()
.into_diagnostic()?;
Driver::rechunk(
&RechunkOpts::builder()
.image(&image_name)
@ -357,8 +365,7 @@ impl BuildCommand {
.base_digest(
Driver::get_metadata(
&GetMetadataOpts::builder()
.image(&*recipe.base_image)
.tag(&*recipe.image_version)
.image(&base_image)
.platform(self.platform)
.build(),
)?
@ -382,10 +389,9 @@ impl BuildCommand {
if self.push && !self.no_sign {
Driver::sign_and_verify(
&SignVerifyOpts::builder()
.image(&image_name)
.image(&image)
.retry_push(self.retry_push)
.retry_count(self.retry_count)
.maybe_tag(tags.first())
.platform(self.platform)
.build(),
)?;

View file

@ -17,6 +17,7 @@ use cached::proc_macro::cached;
use clap::{crate_version, Args};
use log::{debug, info, trace, warn};
use miette::{IntoDiagnostic, Result};
use oci_distribution::Reference;
#[cfg(feature = "validate")]
use crate::commands::validate::ValidateCommand;
@ -132,6 +133,10 @@ impl GenerateCommand {
info!("Templating for recipe at {}", recipe_path.display());
let base_image: Reference = format!("{}:{}", &recipe.base_image, &recipe.image_version)
.parse()
.into_diagnostic()?;
let template = ContainerFileTemplate::builder()
.os_version(
Driver::get_os_version()
@ -144,12 +149,11 @@ impl GenerateCommand {
.recipe_path(recipe_path.as_path())
.registry(registry)
.repo(Driver::get_repo_url()?)
.build_scripts_image(determine_scripts_tag(self.platform)?)
.build_scripts_image(determine_scripts_tag(self.platform)?.to_string())
.base_digest(
Driver::get_metadata(
&GetMetadataOpts::builder()
.image(&*recipe.base_image)
.tag(&*recipe.image_version)
.image(&base_image)
.platform(self.platform)
.build(),
)?
@ -178,24 +182,30 @@ impl GenerateCommand {
convert = r#"{ platform }"#,
sync_writes = true
)]
fn determine_scripts_tag(platform: Platform) -> Result<String> {
let version = format!("v{}", crate_version!());
let opts = GetMetadataOpts::builder()
.image(BUILD_SCRIPTS_IMAGE_REF)
.platform(platform);
fn determine_scripts_tag(platform: Platform) -> Result<Reference> {
let image: Reference = format!("{BUILD_SCRIPTS_IMAGE_REF}:{}", shadow::COMMIT_HASH)
.parse()
.into_diagnostic()?;
let opts = GetMetadataOpts::builder().platform(platform);
Driver::get_metadata(&opts.clone().tag(shadow::COMMIT_HASH).build())
Driver::get_metadata(&opts.clone().image(&image).build())
.inspect_err(|e| trace!("{e:?}"))
.map(|_| format!("{BUILD_SCRIPTS_IMAGE_REF}:{}", shadow::COMMIT_HASH))
.map(|_| image)
.or_else(|_| {
Driver::get_metadata(&opts.clone().tag(shadow::BRANCH).build())
let image: Reference = format!("{BUILD_SCRIPTS_IMAGE_REF}:{}", shadow::BRANCH)
.parse()
.into_diagnostic()?;
Driver::get_metadata(&opts.clone().image(&image).build())
.inspect_err(|e| trace!("{e:?}"))
.map(|_| format!("{BUILD_SCRIPTS_IMAGE_REF}:{}", shadow::BRANCH))
.map(|_| image)
})
.or_else(|_| {
Driver::get_metadata(&opts.tag(&version).build())
let image: Reference = format!("{BUILD_SCRIPTS_IMAGE_REF}:v{}", crate_version!())
.parse()
.into_diagnostic()?;
Driver::get_metadata(&opts.image(&image).build())
.inspect_err(|e| trace!("{e:?}"))
.map(|_| format!("{BUILD_SCRIPTS_IMAGE_REF}:{version}"))
.map(|_| image)
})
.inspect(|image| debug!("Using build scripts image: {image}"))
}