feat: Include base image information in labels
This commit is contained in:
parent
3674f83fd2
commit
e3b246ef91
10 changed files with 246 additions and 193 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -451,6 +451,7 @@ dependencies = [
|
||||||
"blue-build-recipe",
|
"blue-build-recipe",
|
||||||
"blue-build-utils",
|
"blue-build-utils",
|
||||||
"bon",
|
"bon",
|
||||||
|
"chrono",
|
||||||
"colored",
|
"colored",
|
||||||
"log",
|
"log",
|
||||||
"rinja",
|
"rinja",
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ use clap::Args;
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
use log::{info, trace, warn};
|
use log::{info, trace, warn};
|
||||||
use miette::{miette, IntoDiagnostic, Report, Result};
|
use miette::{miette, IntoDiagnostic, Result};
|
||||||
use oci_distribution::Reference;
|
use oci_distribution::Reference;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use opts::{GenerateImageNameOpts, GenerateTagsOpts};
|
use opts::{GenerateImageNameOpts, GenerateTagsOpts};
|
||||||
|
|
@ -202,6 +202,8 @@ impl Driver {
|
||||||
#[builder(default)]
|
#[builder(default)]
|
||||||
platform: Platform,
|
platform: Platform,
|
||||||
) -> Result<u64> {
|
) -> Result<u64> {
|
||||||
|
trace!("Driver::get_os_version({oci_ref:#?})");
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
{
|
{
|
||||||
let _ = oci_ref; // silence lint
|
let _ = oci_ref; // silence lint
|
||||||
|
|
@ -211,8 +213,33 @@ impl Driver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("Driver::get_os_version({oci_ref:#?})");
|
info!("Retrieving OS version from {oci_ref}");
|
||||||
get_version(oci_ref, platform)
|
|
||||||
|
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()
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.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)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_build_driver() -> BuildDriverType {
|
fn get_build_driver() -> BuildDriverType {
|
||||||
|
|
@ -239,74 +266,46 @@ impl Driver {
|
||||||
#[cached(
|
#[cached(
|
||||||
result = true,
|
result = true,
|
||||||
key = "String",
|
key = "String",
|
||||||
convert = r#"{ format!("{oci_ref}-{platform}") }"#,
|
convert = r#"{ oci_ref.to_string() }"#,
|
||||||
sync_writes = true
|
sync_writes = true
|
||||||
)]
|
)]
|
||||||
fn get_version(oci_ref: &Reference, platform: Platform) -> Result<u64> {
|
fn get_version_run_image(oci_ref: &Reference) -> Result<u64> {
|
||||||
info!("Retrieving OS version from {oci_ref}. This might take a bit");
|
warn!(concat!(
|
||||||
let inspect_opts = GetMetadataOpts::builder()
|
"Pulling and running the image to retrieve the version. ",
|
||||||
.image(format!(
|
"This will take a while..."
|
||||||
"{}/{}",
|
));
|
||||||
oci_ref.resolve_registry(),
|
|
||||||
oci_ref.repository()
|
|
||||||
))
|
|
||||||
.tag(oci_ref.tag().unwrap_or("latest"))
|
|
||||||
.platform(platform)
|
|
||||||
.build();
|
|
||||||
let os_version = Driver::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()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.or_else(get_version_run_image(oci_ref))?;
|
|
||||||
trace!("os_version: {os_version}");
|
|
||||||
Ok(os_version)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_version_run_image(oci_ref: &Reference) -> impl FnOnce(Report) -> Result<u64> + '_ {
|
let progress = Logger::multi_progress().add(
|
||||||
|err: Report| -> Result<u64> {
|
ProgressBar::new_spinner()
|
||||||
warn!("Unable to get version via image inspection due to error:\n{err:?}");
|
.with_style(ProgressStyle::default_spinner())
|
||||||
warn!(concat!(
|
.with_message(format!(
|
||||||
"Pulling and running the image to retrieve the version. ",
|
"Pulling image {} to get version",
|
||||||
"This will take a while..."
|
oci_ref.to_string().bold()
|
||||||
));
|
)),
|
||||||
|
);
|
||||||
|
progress.enable_steady_tick(Duration::from_millis(100));
|
||||||
|
|
||||||
let progress = Logger::multi_progress().add(
|
let output = Driver::run_output(
|
||||||
ProgressBar::new_spinner()
|
&RunOpts::builder()
|
||||||
.with_style(ProgressStyle::default_spinner())
|
.image(oci_ref.to_string())
|
||||||
.with_message(format!(
|
.args(bon::vec![
|
||||||
"Pulling image {} to get version",
|
"/bin/bash",
|
||||||
oci_ref.to_string().bold()
|
"-c",
|
||||||
)),
|
"grep -Po '(?<=VERSION_ID=)\\d+' /usr/lib/os-release",
|
||||||
);
|
])
|
||||||
progress.enable_steady_tick(Duration::from_millis(100));
|
.pull(true)
|
||||||
|
.remove(true)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.into_diagnostic()?;
|
||||||
|
|
||||||
let output = Driver::run_output(
|
progress.finish_and_clear();
|
||||||
&RunOpts::builder()
|
Logger::multi_progress().remove(&progress);
|
||||||
.image(oci_ref.to_string())
|
|
||||||
.args(bon::vec![
|
|
||||||
"/bin/bash",
|
|
||||||
"-c",
|
|
||||||
"grep -Po '(?<=VERSION_ID=)\\d+' /usr/lib/os-release",
|
|
||||||
])
|
|
||||||
.pull(true)
|
|
||||||
.remove(true)
|
|
||||||
.build(),
|
|
||||||
)
|
|
||||||
.into_diagnostic()?;
|
|
||||||
|
|
||||||
progress.finish_and_clear();
|
String::from_utf8_lossy(&output.stdout)
|
||||||
Logger::multi_progress().remove(&progress);
|
.trim()
|
||||||
|
.parse()
|
||||||
String::from_utf8_lossy(&output.stdout)
|
.into_diagnostic()
|
||||||
.trim()
|
|
||||||
.parse()
|
|
||||||
.into_diagnostic()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_build_driver {
|
macro_rules! impl_build_driver {
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ use blue_build_utils::{
|
||||||
credentials::Credentials,
|
credentials::Credentials,
|
||||||
string_vec,
|
string_vec,
|
||||||
};
|
};
|
||||||
|
use cached::proc_macro::cached;
|
||||||
use log::{debug, info, trace, warn};
|
use log::{debug, info, trace, warn};
|
||||||
use miette::{bail, IntoDiagnostic, Result};
|
use miette::{bail, IntoDiagnostic, Result};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
@ -346,46 +347,56 @@ impl BuildDriver for DockerDriver {
|
||||||
|
|
||||||
impl InspectDriver for DockerDriver {
|
impl InspectDriver for DockerDriver {
|
||||||
fn get_metadata(opts: &GetMetadataOpts) -> Result<ImageMetadata> {
|
fn get_metadata(opts: &GetMetadataOpts) -> Result<ImageMetadata> {
|
||||||
trace!("DockerDriver::get_metadata({opts:#?})");
|
get_metadata_cache(opts)
|
||||||
|
|
||||||
let url = opts.tag.as_ref().map_or_else(
|
|
||||||
|| format!("{}", opts.image),
|
|
||||||
|tag| format!("{}:{tag}", opts.image),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut command = cmd!(
|
|
||||||
"docker",
|
|
||||||
"buildx",
|
|
||||||
|command|? {
|
|
||||||
if !env::var(DOCKER_HOST).is_ok_and(|dh| !dh.is_empty()) {
|
|
||||||
Self::setup()?;
|
|
||||||
cmd!(command, "--builder=bluebuild");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"imagetools",
|
|
||||||
"inspect",
|
|
||||||
"--format",
|
|
||||||
"{{json .}}",
|
|
||||||
&url
|
|
||||||
);
|
|
||||||
trace!("{command:?}");
|
|
||||||
|
|
||||||
let output = command.output().into_diagnostic()?;
|
|
||||||
|
|
||||||
if output.status.success() {
|
|
||||||
info!("Successfully inspected image {url}!");
|
|
||||||
} else {
|
|
||||||
bail!("Failed to inspect image {url}")
|
|
||||||
}
|
|
||||||
|
|
||||||
serde_json::from_slice::<DockerImageMetadata>(&output.stdout)
|
|
||||||
.into_diagnostic()
|
|
||||||
.inspect(|metadata| trace!("{metadata:#?}"))
|
|
||||||
.map(ImageMetadata::from)
|
|
||||||
.inspect(|metadata| trace!("{metadata:#?}"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cached(
|
||||||
|
result = true,
|
||||||
|
key = "String",
|
||||||
|
convert = r#"{ format!("{}-{:?}-{}", &*opts.image, opts.tag.as_ref(), 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 mut command = cmd!(
|
||||||
|
"docker",
|
||||||
|
"buildx",
|
||||||
|
|command|? {
|
||||||
|
if !env::var(DOCKER_HOST).is_ok_and(|dh| !dh.is_empty()) {
|
||||||
|
DockerDriver::setup()?;
|
||||||
|
cmd!(command, "--builder=bluebuild");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"imagetools",
|
||||||
|
"inspect",
|
||||||
|
"--format",
|
||||||
|
"{{json .}}",
|
||||||
|
&url
|
||||||
|
);
|
||||||
|
trace!("{command:?}");
|
||||||
|
|
||||||
|
let output = command.output().into_diagnostic()?;
|
||||||
|
|
||||||
|
if output.status.success() {
|
||||||
|
info!("Successfully inspected image {url}!");
|
||||||
|
} else {
|
||||||
|
bail!("Failed to inspect image {url}")
|
||||||
|
}
|
||||||
|
|
||||||
|
serde_json::from_slice::<DockerImageMetadata>(&output.stdout)
|
||||||
|
.into_diagnostic()
|
||||||
|
.inspect(|metadata| trace!("{metadata:#?}"))
|
||||||
|
.map(ImageMetadata::from)
|
||||||
|
.inspect(|metadata| trace!("{metadata:#?}"))
|
||||||
|
}
|
||||||
|
|
||||||
impl RunDriver for DockerDriver {
|
impl RunDriver for DockerDriver {
|
||||||
fn run(opts: &RunOpts) -> std::io::Result<ExitStatus> {
|
fn run(opts: &RunOpts) -> std::io::Result<ExitStatus> {
|
||||||
let cid_path = TempDir::new()?;
|
let cid_path = TempDir::new()?;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use bon::Builder;
|
||||||
|
|
||||||
use crate::drivers::types::Platform;
|
use crate::drivers::types::Platform;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Builder)]
|
#[derive(Debug, Clone, Builder, Hash)]
|
||||||
#[builder(derive(Clone))]
|
#[builder(derive(Clone))]
|
||||||
pub struct GetMetadataOpts<'scope> {
|
pub struct GetMetadataOpts<'scope> {
|
||||||
#[builder(into)]
|
#[builder(into)]
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use blue_build_utils::{cmd, credentials::Credentials};
|
use blue_build_utils::{cmd, credentials::Credentials};
|
||||||
|
use cached::proc_macro::cached;
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
|
|
@ -251,61 +252,71 @@ impl BuildDriver for PodmanDriver {
|
||||||
|
|
||||||
impl InspectDriver for PodmanDriver {
|
impl InspectDriver for PodmanDriver {
|
||||||
fn get_metadata(opts: &GetMetadataOpts) -> Result<ImageMetadata> {
|
fn get_metadata(opts: &GetMetadataOpts) -> Result<ImageMetadata> {
|
||||||
trace!("PodmanDriver::get_metadata({opts:#?})");
|
get_metadata_cache(opts)
|
||||||
|
|
||||||
let url = opts.tag.as_deref().map_or_else(
|
|
||||||
|| format!("{}", opts.image),
|
|
||||||
|tag| format!("{}:{tag}", opts.image),
|
|
||||||
);
|
|
||||||
|
|
||||||
let progress = Logger::multi_progress().add(
|
|
||||||
ProgressBar::new_spinner()
|
|
||||||
.with_style(ProgressStyle::default_spinner())
|
|
||||||
.with_message(format!(
|
|
||||||
"Inspecting metadata for {}, pulling image...",
|
|
||||||
url.bold()
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
progress.enable_steady_tick(Duration::from_millis(100));
|
|
||||||
|
|
||||||
let mut command = cmd!(
|
|
||||||
"podman",
|
|
||||||
"pull",
|
|
||||||
if !matches!(opts.platform, Platform::Native) => [
|
|
||||||
"--platform",
|
|
||||||
opts.platform.to_string(),
|
|
||||||
],
|
|
||||||
&url,
|
|
||||||
);
|
|
||||||
trace!("{command:?}");
|
|
||||||
|
|
||||||
let output = command.output().into_diagnostic()?;
|
|
||||||
|
|
||||||
if !output.status.success() {
|
|
||||||
bail!("Failed to pull {} for inspection!", url.bold());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut command = cmd!("podman", "image", "inspect", "--format=json", &url);
|
|
||||||
trace!("{command:?}");
|
|
||||||
|
|
||||||
let output = command.output().into_diagnostic()?;
|
|
||||||
|
|
||||||
progress.finish_and_clear();
|
|
||||||
Logger::multi_progress().remove(&progress);
|
|
||||||
|
|
||||||
if output.status.success() {
|
|
||||||
debug!("Successfully inspected image {url}!");
|
|
||||||
} else {
|
|
||||||
bail!("Failed to inspect image {url}");
|
|
||||||
}
|
|
||||||
serde_json::from_slice::<Vec<PodmanImageMetadata>>(&output.stdout)
|
|
||||||
.into_diagnostic()
|
|
||||||
.inspect(|metadata| trace!("{metadata:#?}"))
|
|
||||||
.and_then(TryFrom::try_from)
|
|
||||||
.inspect(|metadata| trace!("{metadata:#?}"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cached(
|
||||||
|
result = true,
|
||||||
|
key = "String",
|
||||||
|
convert = r#"{ format!("{}-{:?}-{}", &*opts.image, opts.tag.as_ref(), 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 progress = Logger::multi_progress().add(
|
||||||
|
ProgressBar::new_spinner()
|
||||||
|
.with_style(ProgressStyle::default_spinner())
|
||||||
|
.with_message(format!(
|
||||||
|
"Inspecting metadata for {}, pulling image...",
|
||||||
|
url.bold()
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
progress.enable_steady_tick(Duration::from_millis(100));
|
||||||
|
|
||||||
|
let mut command = cmd!(
|
||||||
|
"podman",
|
||||||
|
"pull",
|
||||||
|
if !matches!(opts.platform, Platform::Native) => [
|
||||||
|
"--platform",
|
||||||
|
opts.platform.to_string(),
|
||||||
|
],
|
||||||
|
&url,
|
||||||
|
);
|
||||||
|
trace!("{command:?}");
|
||||||
|
|
||||||
|
let output = command.output().into_diagnostic()?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
bail!("Failed to pull {} for inspection!", url.bold());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut command = cmd!("podman", "image", "inspect", "--format=json", &url);
|
||||||
|
trace!("{command:?}");
|
||||||
|
|
||||||
|
let output = command.output().into_diagnostic()?;
|
||||||
|
|
||||||
|
progress.finish_and_clear();
|
||||||
|
Logger::multi_progress().remove(&progress);
|
||||||
|
|
||||||
|
if output.status.success() {
|
||||||
|
debug!("Successfully inspected image {url}!");
|
||||||
|
} else {
|
||||||
|
bail!("Failed to inspect image {url}");
|
||||||
|
}
|
||||||
|
serde_json::from_slice::<Vec<PodmanImageMetadata>>(&output.stdout)
|
||||||
|
.into_diagnostic()
|
||||||
|
.inspect(|metadata| trace!("{metadata:#?}"))
|
||||||
|
.and_then(TryFrom::try_from)
|
||||||
|
.inspect(|metadata| trace!("{metadata:#?}"))
|
||||||
|
}
|
||||||
|
|
||||||
impl RunDriver for PodmanDriver {
|
impl RunDriver for PodmanDriver {
|
||||||
fn run(opts: &RunOpts) -> std::io::Result<ExitStatus> {
|
fn run(opts: &RunOpts) -> std::io::Result<ExitStatus> {
|
||||||
trace!("PodmanDriver::run({opts:#?})");
|
trace!("PodmanDriver::run({opts:#?})");
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use std::{process::Stdio, time::Duration};
|
use std::{process::Stdio, time::Duration};
|
||||||
|
|
||||||
use blue_build_utils::cmd;
|
use blue_build_utils::cmd;
|
||||||
|
use cached::proc_macro::cached;
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
|
|
@ -15,42 +16,52 @@ pub struct SkopeoDriver;
|
||||||
|
|
||||||
impl InspectDriver for SkopeoDriver {
|
impl InspectDriver for SkopeoDriver {
|
||||||
fn get_metadata(opts: &GetMetadataOpts) -> Result<ImageMetadata> {
|
fn get_metadata(opts: &GetMetadataOpts) -> Result<ImageMetadata> {
|
||||||
trace!("SkopeoDriver::get_metadata({opts:#?})");
|
get_metadata_cache(opts)
|
||||||
|
|
||||||
let url = opts.tag.as_ref().map_or_else(
|
|
||||||
|| format!("docker://{}", opts.image),
|
|
||||||
|tag| format!("docker://{}:{tag}", opts.image),
|
|
||||||
);
|
|
||||||
|
|
||||||
let progress = Logger::multi_progress().add(
|
|
||||||
ProgressBar::new_spinner()
|
|
||||||
.with_style(ProgressStyle::default_spinner())
|
|
||||||
.with_message(format!("Inspecting metadata for {}", url.bold())),
|
|
||||||
);
|
|
||||||
progress.enable_steady_tick(Duration::from_millis(100));
|
|
||||||
|
|
||||||
let mut command = cmd!(
|
|
||||||
"skopeo",
|
|
||||||
if !matches!(opts.platform, Platform::Native) => [
|
|
||||||
"--override-arch",
|
|
||||||
opts.platform.arch(),
|
|
||||||
],
|
|
||||||
"inspect",
|
|
||||||
&url,
|
|
||||||
stderr = Stdio::inherit(),
|
|
||||||
);
|
|
||||||
trace!("{command:?}");
|
|
||||||
|
|
||||||
let output = command.output().into_diagnostic()?;
|
|
||||||
|
|
||||||
progress.finish_and_clear();
|
|
||||||
Logger::multi_progress().remove(&progress);
|
|
||||||
|
|
||||||
if output.status.success() {
|
|
||||||
debug!("Successfully inspected image {url}!");
|
|
||||||
} else {
|
|
||||||
bail!("Failed to inspect image {url}")
|
|
||||||
}
|
|
||||||
serde_json::from_slice(&output.stdout).into_diagnostic()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cached(
|
||||||
|
result = true,
|
||||||
|
key = "String",
|
||||||
|
convert = r#"{ format!("{}-{:?}-{}", &*opts.image, opts.tag.as_ref(), 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 progress = Logger::multi_progress().add(
|
||||||
|
ProgressBar::new_spinner()
|
||||||
|
.with_style(ProgressStyle::default_spinner())
|
||||||
|
.with_message(format!("Inspecting metadata for {}", url.bold())),
|
||||||
|
);
|
||||||
|
progress.enable_steady_tick(Duration::from_millis(100));
|
||||||
|
|
||||||
|
let mut command = cmd!(
|
||||||
|
"skopeo",
|
||||||
|
if !matches!(opts.platform, Platform::Native) => [
|
||||||
|
"--override-arch",
|
||||||
|
opts.platform.arch(),
|
||||||
|
],
|
||||||
|
"inspect",
|
||||||
|
&url,
|
||||||
|
stderr = Stdio::inherit(),
|
||||||
|
);
|
||||||
|
trace!("{command:?}");
|
||||||
|
|
||||||
|
let output = command.output().into_diagnostic()?;
|
||||||
|
|
||||||
|
progress.finish_and_clear();
|
||||||
|
Logger::multi_progress().remove(&progress);
|
||||||
|
|
||||||
|
if output.status.success() {
|
||||||
|
debug!("Successfully inspected image {url}!");
|
||||||
|
} else {
|
||||||
|
bail!("Failed to inspect image {url}")
|
||||||
|
}
|
||||||
|
serde_json::from_slice(&output.stdout).into_diagnostic()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,16 @@ impl GenerateCommand {
|
||||||
.registry(registry)
|
.registry(registry)
|
||||||
.repo(Driver::get_repo_url()?)
|
.repo(Driver::get_repo_url()?)
|
||||||
.build_scripts_image(determine_scripts_tag(self.platform)?)
|
.build_scripts_image(determine_scripts_tag(self.platform)?)
|
||||||
|
.base_digest(
|
||||||
|
Driver::get_metadata(
|
||||||
|
&GetMetadataOpts::builder()
|
||||||
|
.image(&*recipe.base_image)
|
||||||
|
.tag(&*recipe.image_version)
|
||||||
|
.platform(self.platform)
|
||||||
|
.build(),
|
||||||
|
)?
|
||||||
|
.digest,
|
||||||
|
)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let output_str = template.render().into_diagnostic()?;
|
let output_str = template.render().into_diagnostic()?;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ rinja = { version = "0.3", features = ["serde_json"] }
|
||||||
blue-build-recipe = { version = "=0.8.20", path = "../recipe" }
|
blue-build-recipe = { version = "=0.8.20", path = "../recipe" }
|
||||||
blue-build-utils = { version = "=0.8.20", path = "../utils" }
|
blue-build-utils = { version = "=0.8.20", path = "../utils" }
|
||||||
|
|
||||||
|
chrono.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
colored.workspace = true
|
colored.workspace = true
|
||||||
bon.workspace = true
|
bon.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use blue_build_utils::constants::{
|
||||||
CONFIG_PATH, CONTAINERFILES_PATH, CONTAINER_FILE, COSIGN_PUB_PATH, FILES_PATH,
|
CONFIG_PATH, CONTAINERFILES_PATH, CONTAINER_FILE, COSIGN_PUB_PATH, FILES_PATH,
|
||||||
};
|
};
|
||||||
use bon::Builder;
|
use bon::Builder;
|
||||||
|
use chrono::Utc;
|
||||||
use colored::control::ShouldColorize;
|
use colored::control::ShouldColorize;
|
||||||
use log::{debug, error, trace, warn};
|
use log::{debug, error, trace, warn};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
@ -27,6 +28,7 @@ pub struct ContainerFileTemplate<'a> {
|
||||||
registry: Cow<'a, str>,
|
registry: Cow<'a, str>,
|
||||||
build_scripts_image: Cow<'a, str>,
|
build_scripts_image: Cow<'a, str>,
|
||||||
repo: Cow<'a, str>,
|
repo: Cow<'a, str>,
|
||||||
|
base_digest: Cow<'a, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Template, Builder)]
|
#[derive(Debug, Clone, Template, Builder)]
|
||||||
|
|
@ -111,6 +113,10 @@ fn config_dir_exists() -> bool {
|
||||||
exists
|
exists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn current_timestamp() -> String {
|
||||||
|
Utc::now().to_rfc3339()
|
||||||
|
}
|
||||||
|
|
||||||
fn should_color() -> bool {
|
fn should_color() -> bool {
|
||||||
ShouldColorize::from_env().should_colorize()
|
ShouldColorize::from_env().should_colorize()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
{%- include "stages.j2" %}
|
{%- include "stages.j2" %}
|
||||||
|
|
||||||
# Main image
|
# Main image
|
||||||
FROM {{ recipe.base_image }}:{{ recipe.image_version }} AS {{ recipe.name|replace('/', "-") }}
|
FROM {{ recipe.base_image }}@{{ base_digest }} AS {{ recipe.name|replace('/', "-") }}
|
||||||
|
|
||||||
ARG RECIPE={{ recipe_path.display() }}
|
ARG RECIPE={{ recipe_path.display() }}
|
||||||
ARG IMAGE_REGISTRY={{ registry }}
|
ARG IMAGE_REGISTRY={{ registry }}
|
||||||
|
|
@ -46,4 +46,7 @@ LABEL {{ blue_build_utils::constants::BUILD_ID_LABEL }}="{{ build_id }}"
|
||||||
LABEL org.opencontainers.image.title="{{ recipe.name }}"
|
LABEL org.opencontainers.image.title="{{ recipe.name }}"
|
||||||
LABEL org.opencontainers.image.description="{{ recipe.description }}"
|
LABEL org.opencontainers.image.description="{{ recipe.description }}"
|
||||||
LABEL org.opencontainers.image.source="{{ repo }}"
|
LABEL org.opencontainers.image.source="{{ repo }}"
|
||||||
|
LABEL org.opencontainers.image.base.digest="{{ base_digest }}"
|
||||||
|
LABEL org.opencontainers.image.base.name="{{ recipe.base_image }}:{{ recipe.image_version }}"
|
||||||
|
LABEL org.opencontainers.image.created="{{ self::current_timestamp() }}"
|
||||||
LABEL io.artifacthub.package.readme-url=https://raw.githubusercontent.com/blue-build/cli/main/README.md
|
LABEL io.artifacthub.package.readme-url=https://raw.githubusercontent.com/blue-build/cli/main/README.md
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue