refactor: Move modules into their own directory structure (#80)

This separates out the module template logic so that it is easier to
undertstand what each section does. This will also allow creating in
repo documentation for any special modules that don't use a bash base.
This commit is contained in:
Gerald Pinder 2024-02-24 02:16:30 -05:00 committed by GitHub
parent 0b4e1003a2
commit 4c8a8f7aa8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 239 additions and 688 deletions

7
src/akmods_info.rs Normal file
View file

@ -0,0 +1,7 @@
use typed_builder::TypedBuilder;
#[derive(Debug, Clone, TypedBuilder, PartialEq, Eq, Hash)]
pub struct AkmodsInfo {
pub images: (String, Option<String>),
pub stage_name: String,
}

View file

@ -1,5 +1,4 @@
use std::{
collections::HashSet,
env, fs,
path::{Path, PathBuf},
process,
@ -12,15 +11,12 @@ use log::{debug, error, info, trace};
use typed_builder::TypedBuilder;
use uuid::Uuid;
use crate::{
constants::*,
module_recipe::{Module, ModuleExt, Recipe},
};
use crate::{constants::*, module_recipe::Recipe};
use super::BlueBuildCommand;
#[derive(Debug, Clone, Template, TypedBuilder)]
#[template(path = "Containerfile")]
#[template(path = "Containerfile.j2", escape = "none")]
pub struct ContainerFileTemplate<'a> {
recipe: &'a Recipe<'a>,
@ -38,6 +34,24 @@ pub struct ContainerFileTemplate<'a> {
#[template(path = "export.sh", escape = "none")]
pub struct ExportsTemplate;
impl ExportsTemplate {
fn print_script(&self) -> String {
trace!("print_script({self})");
format!(
"\"{}\"",
self.render()
.unwrap_or_else(|e| {
error!("Failed to render export.sh script: {e}");
process::exit(1);
})
.replace('\n', "\\n")
.replace('\"', "\\\"")
.replace('$', "\\$")
)
}
}
#[derive(Debug, Clone, Args, TypedBuilder)]
pub struct TemplateCommand {
/// The recipe file to create a template from
@ -114,23 +128,6 @@ impl TemplateCommand {
// ========================= Helpers ====================== //
// ======================================================== //
fn print_script(script_contents: &ExportsTemplate) -> String {
trace!("print_script({script_contents})");
format!(
"\"{}\"",
script_contents
.render()
.unwrap_or_else(|e| {
error!("Failed to render export.sh script: {e}");
process::exit(1);
})
.replace('\n', "\\n")
.replace('\"', "\\\"")
.replace('$', "\\$")
)
}
fn has_cosign_file() -> bool {
trace!("has_cosign_file()");
std::env::current_dir()
@ -138,33 +135,6 @@ fn has_cosign_file() -> bool {
.unwrap_or(false)
}
#[must_use]
fn get_module_type_list(module: &Module, typ: &str, list_key: &str) -> Option<Vec<String>> {
if module.module_type.as_ref()? == typ {
Some(
module
.config
.get(list_key)?
.as_sequence()?
.iter()
.filter_map(|t| Some(t.as_str()?.to_owned()))
.collect(),
)
} else {
None
}
}
#[must_use]
fn get_containerfile_list(module: &Module) -> Option<Vec<String>> {
get_module_type_list(module, "containerfile", "containerfiles")
}
#[must_use]
fn get_containerfile_snippets(module: &Module) -> Option<Vec<String>> {
get_module_type_list(module, "containerfile", "snippets")
}
#[must_use]
fn print_containerfile(containerfile: &str) -> String {
trace!("print_containerfile({containerfile})");
@ -182,32 +152,6 @@ fn print_containerfile(containerfile: &str) -> String {
file
}
fn print_module_context(module: &Module) -> String {
serde_json::to_string(module).unwrap_or_else(|e| {
error!("Failed to parse module!!!!!: {e}");
process::exit(1);
})
}
fn get_files_list(module: &Module) -> Option<Vec<(String, String)>> {
Some(
module
.config
.get("files")?
.as_sequence()?
.iter()
.filter_map(|entry| entry.as_mapping())
.flatten()
.filter_map(|(src, dest)| {
Some((
format!("./config/files/{}", src.as_str()?),
dest.as_str()?.to_string(),
))
})
.collect(),
)
}
fn get_github_repo_owner() -> Option<String> {
Some(env::var(GITHUB_REPOSITORY_OWNER).ok()?.to_lowercase())
}
@ -228,56 +172,3 @@ fn modules_exists() -> bool {
let mod_path = Path::new("modules");
mod_path.exists() && mod_path.is_dir()
}
#[derive(Debug, Clone, TypedBuilder, PartialEq, Eq, Hash)]
struct AkmodsInfo {
images: (String, Option<String>),
stage_name: String,
}
fn get_akmods_info_list(module_ext: &ModuleExt, os_version: &str) -> Vec<AkmodsInfo> {
trace!("get_akmods_image_list({module_ext:#?}, {os_version})");
let mut seen = HashSet::new();
module_ext
.modules
.iter()
.filter(|module| module.module_type.as_ref().is_some_and(|t| t == "akmods"))
.map(|module| generate_akmods_info(module, os_version))
.filter(|image| seen.insert(image.clone()))
.collect()
}
fn generate_akmods_info(module: &Module, os_version: &str) -> AkmodsInfo {
trace!("generate_akmods_base({module:#?}, {os_version})");
let base = module
.config
.get("base")
.map(|b| b.as_str().unwrap_or_default());
let nvidia_version = module
.config
.get("nvidia-version")
.map(|v| v.as_u64().unwrap_or_default());
AkmodsInfo::builder()
.images(match (base, nvidia_version) {
(Some(b), Some(nv)) if !b.is_empty() && nv > 0 => (
format!("akmods:{b}-{os_version}"),
Some(format!("akmods-nvidia:{b}-{os_version}-{nv}")),
),
(Some(b), _) if !b.is_empty() => (format!("akmods:{b}-{os_version}"), None),
(_, Some(nv)) if nv > 0 => (
format!("akmods:main-{os_version}"),
Some(format!("akmods-nvidia:main-{os_version}")),
),
_ => (format!("akmods:main-{os_version}"), None),
})
.stage_name(format!(
"{}{}",
base.unwrap_or("main"),
nvidia_version.map_or_else(String::default, |nv| format!("-{nv}"))
))
.build()
}

View file

@ -12,6 +12,7 @@
shadow_rs::shadow!(shadow);
pub mod akmods_info;
pub mod commands;
pub mod constants;
pub mod module_recipe;

View file

@ -1,9 +1,9 @@
use std::{
borrow::Cow,
collections::HashMap,
collections::{HashMap, HashSet},
env, fs,
path::{Path, PathBuf},
process::Command,
process::{self, Command},
};
use anyhow::Result;
@ -17,6 +17,7 @@ use serde_yaml::Value;
use typed_builder::TypedBuilder;
use crate::{
akmods_info::AkmodsInfo,
constants::*,
ops::{self, check_command_exists},
};
@ -236,6 +237,19 @@ impl ModuleExt<'_> {
Ok,
)
}
pub fn get_akmods_info_list(&self, os_version: &str) -> Vec<AkmodsInfo> {
trace!("get_akmods_image_list({self:#?}, {os_version})");
let mut seen = HashSet::new();
self.modules
.iter()
.filter(|module| module.module_type.as_ref().is_some_and(|t| t == "akmods"))
.map(|module| module.generate_akmods_info(os_version))
.filter(|image| seen.insert(image.clone()))
.collect()
}
}
#[derive(Serialize, Deserialize, Debug, Clone, TypedBuilder)]
@ -257,7 +271,7 @@ pub struct Module<'a> {
pub config: IndexMap<String, Value>,
}
impl Module<'_> {
impl<'a> Module<'a> {
#[must_use]
pub fn get_modules(modules: &[Self]) -> Vec<Self> {
modules
@ -276,6 +290,90 @@ impl Module<'_> {
})
.collect()
}
#[must_use]
pub fn get_module_type_list(&'a self, typ: &str, list_key: &str) -> Option<Vec<String>> {
if self.module_type.as_ref()? == typ {
Some(
self.config
.get(list_key)?
.as_sequence()?
.iter()
.filter_map(|t| Some(t.as_str()?.to_owned()))
.collect(),
)
} else {
None
}
}
#[must_use]
pub fn get_containerfile_list(&'a self) -> Option<Vec<String>> {
self.get_module_type_list("containerfile", "containerfiles")
}
#[must_use]
pub fn get_containerfile_snippets(&'a self) -> Option<Vec<String>> {
self.get_module_type_list("containerfile", "snippets")
}
pub fn print_module_context(&'a self) -> String {
serde_json::to_string(self).unwrap_or_else(|e| {
error!("Failed to parse module!!!!!: {e}");
process::exit(1);
})
}
pub fn get_files_list(&'a self) -> Option<Vec<(String, String)>> {
Some(
self.config
.get("files")?
.as_sequence()?
.iter()
.filter_map(|entry| entry.as_mapping())
.flatten()
.filter_map(|(src, dest)| {
Some((
format!("./config/files/{}", src.as_str()?),
dest.as_str()?.to_string(),
))
})
.collect(),
)
}
pub fn generate_akmods_info(&'a self, os_version: &str) -> AkmodsInfo {
trace!("generate_akmods_base({self:#?}, {os_version})");
let base = self
.config
.get("base")
.map(|b| b.as_str().unwrap_or_default());
let nvidia_version = self
.config
.get("nvidia-version")
.map(|v| v.as_u64().unwrap_or_default());
AkmodsInfo::builder()
.images(match (base, nvidia_version) {
(Some(b), Some(nv)) if !b.is_empty() && nv > 0 => (
format!("akmods:{b}-{os_version}"),
Some(format!("akmods-nvidia:{b}-{os_version}-{nv}")),
),
(Some(b), _) if !b.is_empty() => (format!("akmods:{b}-{os_version}"), None),
(_, Some(nv)) if nv > 0 => (
format!("akmods:main-{os_version}"),
Some(format!("akmods-nvidia:main-{os_version}")),
),
_ => (format!("akmods:main-{os_version}"), None),
})
.stage_name(format!(
"{}{}",
base.unwrap_or("main"),
nvidia_version.map_or_else(String::default, |nv| format!("-{nv}"))
))
.build()
}
}
#[derive(Deserialize, Debug, Clone)]