feat: Support versioned modules

This commit is contained in:
Gerald Pinder 2024-12-24 18:01:40 -05:00
parent 74bd05643f
commit 2d150e3c93
7 changed files with 135 additions and 19 deletions

View file

@ -11,11 +11,15 @@ use serde_yaml::Value;
use crate::{base_recipe_path, AkmodsInfo, ModuleExt};
#[derive(Serialize, Deserialize, Debug, Clone, Builder, Default)]
mod type_ver;
pub use type_ver::*;
#[derive(Serialize, Deserialize, Debug, Clone, Builder)]
pub struct ModuleRequiredFields<'a> {
#[builder(into)]
#[serde(rename = "type")]
pub module_type: Cow<'a, str>,
pub module_type: ModuleTypeVersion<'a>,
#[builder(into)]
#[serde(skip_serializing_if = "Option::is_none")]
@ -38,7 +42,7 @@ const fn is_false(b: &bool) -> bool {
impl<'a> ModuleRequiredFields<'a> {
#[must_use]
pub fn get_module_type_list(&'a self, typ: &str, list_key: &str) -> Option<Vec<String>> {
if self.module_type == typ {
if self.module_type.typ() == typ {
Some(
self.config
.get(list_key)?
@ -217,7 +221,7 @@ impl Module<'_> {
required_fields: None,
from_file: Some(file_name),
} => {
let file_name = PathBuf::from(file_name.as_ref());
let file_name = PathBuf::from(&**file_name);
if traversed_files.contains(&file_name) {
bail!(
"{} File {} has already been parsed:\n{traversed_files:?}",
@ -260,14 +264,21 @@ impl Module<'_> {
}
#[must_use]
#[allow(clippy::missing_panics_doc)]
pub fn example() -> Self {
Self::builder()
.required_fields(
ModuleRequiredFields::builder()
.module_type("module-name")
.module_type("script")
.config(IndexMap::from_iter([
("module".to_string(), Value::String("config".to_string())),
("goes".to_string(), Value::String("here".to_string())),
(
"snippets".to_string(),
Value::Sequence(bon::vec!["echo 'Hello World!'"]),
),
(
"scripts".to_string(),
Value::Sequence(bon::vec!["install-program.sh"]),
),
]))
.build(),
)

View file

@ -0,0 +1,78 @@
use std::borrow::Cow;
use serde::{Deserialize, Deserializer, Serialize};
#[derive(Debug, Clone)]
pub struct ModuleTypeVersion<'scope> {
typ: Cow<'scope, str>,
version: Cow<'scope, str>,
}
impl ModuleTypeVersion<'_> {
#[must_use]
pub fn typ(&self) -> &str {
&self.typ
}
#[must_use]
pub fn version(&self) -> &str {
&self.version
}
}
impl std::fmt::Display for ModuleTypeVersion<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}@{}", &self.typ, &self.version)
}
}
impl<'scope> From<&'scope str> for ModuleTypeVersion<'scope> {
fn from(s: &'scope str) -> Self {
if let Some((typ, version)) = s.split_once('@') {
Self {
typ: Cow::Borrowed(typ),
version: Cow::Borrowed(version),
}
} else {
Self {
typ: Cow::Borrowed(s),
version: Cow::Owned("latest".into()),
}
}
}
}
impl From<String> for ModuleTypeVersion<'_> {
fn from(s: String) -> Self {
if let Some((typ, version)) = s.split_once('@') {
Self {
typ: Cow::Owned(typ.to_owned()),
version: Cow::Owned(version.to_owned()),
}
} else {
Self {
typ: Cow::Owned(s),
version: Cow::Owned("latest".into()),
}
}
}
}
impl Serialize for ModuleTypeVersion<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl<'de> Deserialize<'de> for ModuleTypeVersion<'_> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value: String = Deserialize::deserialize(deserializer)?;
Ok(value.into())
}
}

View file

@ -72,7 +72,7 @@ impl ModuleExt<'_> {
module
.required_fields
.as_ref()
.is_some_and(|rf| rf.module_type == "akmods")
.is_some_and(|rf| rf.module_type.typ() == "akmods")
})
.filter_map(|module| {
Some(

View file

@ -108,7 +108,7 @@ impl Stage<'_> {
required_fields: None,
from_file: Some(file_name),
} => {
let file_name = PathBuf::from(file_name.as_ref());
let file_name = PathBuf::from(&**file_name);
if traversed_files.contains(&file_name) {
bail!(
"{} File {} has already been parsed:\n{traversed_files:?}",