From 7b17c7663306042059bef55a44fce42b6bf4170e Mon Sep 17 00:00:00 2001 From: Gerald Pinder Date: Mon, 30 Dec 2024 17:10:51 -0500 Subject: [PATCH] feat: Retrieve Nushell versions from modules --- process/drivers/docker_driver/metadata.rs | 4 +- process/drivers/podman_driver.rs | 2 +- process/drivers/types.rs | 5 +- recipe/src/module/type_ver.rs | 12 ++++ src/commands/generate.rs | 74 ++++++++++++++++++++++- utils/src/constants.rs | 1 + 6 files changed, 92 insertions(+), 6 deletions(-) diff --git a/process/drivers/docker_driver/metadata.rs b/process/drivers/docker_driver/metadata.rs index 75c9d8d0..8d589e17 100644 --- a/process/drivers/docker_driver/metadata.rs +++ b/process/drivers/docker_driver/metadata.rs @@ -54,7 +54,7 @@ impl TryFrom<(Metadata, Platform)> for ImageMetadata { fn try_from((metadata, platform): (Metadata, Platform)) -> Result { match metadata.image { MetadataImage::Single(image) => Ok(Self { - labels: image.config.labels, + labels: Some(image.config.labels), digest: metadata.manifest.digest, }), MetadataImage::Multi(mut platforms) => { @@ -70,7 +70,7 @@ impl TryFrom<(Metadata, Platform)> for ImageMetadata { bail!("Manifest does not exist for {platform}"); }; Ok(Self { - labels: image.config.labels, + labels: Some(image.config.labels), digest: manifest.digest, }) } diff --git a/process/drivers/podman_driver.rs b/process/drivers/podman_driver.rs index 2debe613..9f3da8dd 100644 --- a/process/drivers/podman_driver.rs +++ b/process/drivers/podman_driver.rs @@ -80,7 +80,7 @@ impl TryFrom> for ImageMetadata { .to_string(); Ok(Self { - labels: value.labels, + labels: Some(value.labels), digest, }) } diff --git a/process/drivers/types.rs b/process/drivers/types.rs index e1cc6aaa..151edbb1 100644 --- a/process/drivers/types.rs +++ b/process/drivers/types.rs @@ -216,10 +216,10 @@ impl std::fmt::Display for Platform { } } -#[derive(Deserialize, Debug, Clone)] +#[derive(Deserialize, Debug, Clone, Default)] #[serde(rename_all = "PascalCase")] pub struct ImageMetadata { - pub labels: HashMap, + pub labels: Option>, pub digest: String, } @@ -228,6 +228,7 @@ impl ImageMetadata { pub fn get_version(&self) -> Option { Some( self.labels + .as_ref()? .get(IMAGE_VERSION_LABEL)? .as_str() .and_then(|v| lenient_semver::parse(v).ok())? diff --git a/recipe/src/module/type_ver.rs b/recipe/src/module/type_ver.rs index 4de2d6e3..77a2278c 100644 --- a/recipe/src/module/type_ver.rs +++ b/recipe/src/module/type_ver.rs @@ -1,5 +1,7 @@ use std::borrow::Cow; +use blue_build_utils::constants::BLUE_BUILD_MODULE_IMAGE_REF; +use oci_distribution::Reference; use serde::{Deserialize, Deserializer, Serialize}; #[derive(Debug, Clone)] @@ -18,6 +20,16 @@ impl<'scope> ModuleTypeVersion<'scope> { pub fn version(&self) -> &str { &self.version } + + #[must_use] + pub fn as_reference(&self) -> Option { + format!( + "{BLUE_BUILD_MODULE_IMAGE_REF}/{}:{}", + &self.typ, &self.version + ) + .parse() + .ok() + } } impl std::fmt::Display for ModuleTypeVersion<'_> { diff --git a/src/commands/generate.rs b/src/commands/generate.rs index 6b05d8ac..244703d1 100644 --- a/src/commands/generate.rs +++ b/src/commands/generate.rs @@ -1,4 +1,6 @@ use std::{ + borrow::Cow, + collections::HashSet, env, path::{Path, PathBuf}, }; @@ -9,7 +11,10 @@ use blue_build_process_management::drivers::{ use blue_build_recipe::Recipe; use blue_build_template::{ContainerFileTemplate, Template}; use blue_build_utils::{ - constants::{BUILD_SCRIPTS_IMAGE_REF, CONFIG_PATH, RECIPE_FILE, RECIPE_PATH}, + constants::{ + BUILD_SCRIPTS_IMAGE_REF, BUILTIN_MODULES, CONFIG_PATH, NUSHELL_VERSION_LABEL, RECIPE_FILE, + RECIPE_PATH, + }, syntax_highlighting::{self, DefaultThemes}, }; use bon::Builder; @@ -159,6 +164,7 @@ impl GenerateCommand { )? .digest, ) + .nushell_versions(retrieve_nushell_versions(&recipe)) .build(); let output_str = template.render().into_diagnostic()?; @@ -209,3 +215,69 @@ fn determine_scripts_tag(platform: Platform) -> Result { }) .inspect(|image| debug!("Using build scripts image: {image}")) } + +fn retrieve_nushell_versions<'a>(recipe: &'a Recipe) -> Vec> { + use rayon::prelude::*; + fn process_module<'a>(module: &'a blue_build_recipe::Module<'a>) -> Option> { + let required_fields = module.required_fields.as_ref()?; + + if BUILTIN_MODULES.contains(&required_fields.module_type.typ()) { + return None; + } + + required_fields + .nushell_version + .as_deref() + .map(Cow::<'a>::Borrowed) + .or_else(|| { + let image = &required_fields + .source + .as_deref() + .and_then(|source| source.parse().ok()) + .or_else(|| required_fields.module_type.as_reference())?; + + Driver::get_metadata(&GetMetadataOpts::builder().image(image).build()) + .inspect_err(|e| warn!("Failed to inspect module image {image}:\n{e}")) + .ok()? + .labels + .as_ref()? + .get(NUSHELL_VERSION_LABEL)? + .as_str() + .map(ToOwned::to_owned) + .map(Cow::Owned) + }) + } + + [ + recipe.stages_ext.as_ref().map_or_else(Vec::new, |stages| { + stages + .stages + .par_iter() + .filter_map(|stage| { + Some( + stage + .required_fields + .as_ref()? + .modules_ext + .modules + .par_iter() + .filter_map(process_module) + .collect::>(), + ) + }) + .flatten() + .collect() + }), + recipe + .modules_ext + .modules + .par_iter() + .filter_map(process_module) + .collect(), + ] + .into_iter() + .flatten() + .collect::>>() + .into_iter() + .collect() +} diff --git a/utils/src/constants.rs b/utils/src/constants.rs index 2677b641..b7a27145 100644 --- a/utils/src/constants.rs +++ b/utils/src/constants.rs @@ -88,6 +88,7 @@ pub const UNKNOWN_SHELL: &str = ""; pub const UNKNOWN_VERSION: &str = ""; pub const UNKNOWN_TERMINAL: &str = ""; pub const GITHUB_CHAR_LIMIT: usize = 8100; // Magic number accepted by Github +pub const BUILTIN_MODULES: [&str; 2] = ["containerfile", "copy"]; // Messages pub const BUG_REPORT_WARNING_MESSAGE: &str =