Skip to content

Commit 11b846c

Browse files
committed
feat: Support versioned modules
1 parent 8325de0 commit 11b846c

File tree

6 files changed

+108
-18
lines changed

6 files changed

+108
-18
lines changed

recipe/src/module.rs

+18-7
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,15 @@ use serde_yaml::Value;
1111

1212
use crate::{base_recipe_path, AkmodsInfo, ModuleExt};
1313

14-
#[derive(Serialize, Deserialize, Debug, Clone, Builder, Default)]
14+
mod type_ver;
15+
16+
pub use type_ver::*;
17+
18+
#[derive(Serialize, Deserialize, Debug, Clone, Builder)]
1519
pub struct ModuleRequiredFields<'a> {
1620
#[builder(into)]
1721
#[serde(rename = "type")]
18-
pub module_type: Cow<'a, str>,
22+
pub module_type: ModuleTypeVersion<'a>,
1923

2024
#[builder(into)]
2125
#[serde(skip_serializing_if = "Option::is_none")]
@@ -38,7 +42,7 @@ const fn is_false(b: &bool) -> bool {
3842
impl<'a> ModuleRequiredFields<'a> {
3943
#[must_use]
4044
pub fn get_module_type_list(&'a self, typ: &str, list_key: &str) -> Option<Vec<String>> {
41-
if self.module_type == typ {
45+
if self.module_type.typ() == typ {
4246
Some(
4347
self.config
4448
.get(list_key)?
@@ -217,7 +221,7 @@ impl Module<'_> {
217221
required_fields: None,
218222
from_file: Some(file_name),
219223
} => {
220-
let file_name = PathBuf::from(file_name.as_ref());
224+
let file_name = PathBuf::from(&**file_name);
221225
if traversed_files.contains(&file_name) {
222226
bail!(
223227
"{} File {} has already been parsed:\n{traversed_files:?}",
@@ -260,14 +264,21 @@ impl Module<'_> {
260264
}
261265

262266
#[must_use]
267+
#[allow(clippy::missing_panics_doc)]
263268
pub fn example() -> Self {
264269
Self::builder()
265270
.required_fields(
266271
ModuleRequiredFields::builder()
267-
.module_type("module-name")
272+
.module_type("script")
268273
.config(IndexMap::from_iter([
269-
("module".to_string(), Value::String("config".to_string())),
270-
("goes".to_string(), Value::String("here".to_string())),
274+
(
275+
"snippets".to_string(),
276+
Value::Sequence(bon::vec!["echo 'Hello World!'"]),
277+
),
278+
(
279+
"scripts".to_string(),
280+
Value::Sequence(bon::vec!["install-program.sh"]),
281+
),
271282
]))
272283
.build(),
273284
)

recipe/src/module/type_ver.rs

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use std::borrow::Cow;
2+
3+
use serde::{Deserialize, Deserializer, Serialize};
4+
5+
#[derive(Debug, Clone)]
6+
pub struct ModuleTypeVersion<'scope> {
7+
typ: Cow<'scope, str>,
8+
version: Cow<'scope, str>,
9+
}
10+
11+
impl<'scope> ModuleTypeVersion<'scope> {
12+
#[must_use]
13+
pub fn typ(&self) -> &str {
14+
&self.typ
15+
}
16+
17+
#[must_use]
18+
pub fn version(&self) -> &str {
19+
&self.version
20+
}
21+
}
22+
23+
impl std::fmt::Display for ModuleTypeVersion<'_> {
24+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25+
write!(f, "{}@{}", &self.typ, &self.version)
26+
}
27+
}
28+
29+
impl<'scope> From<&'scope str> for ModuleTypeVersion<'scope> {
30+
fn from(s: &'scope str) -> Self {
31+
if let Some((typ, version)) = s.split_once('@') {
32+
Self {
33+
typ: Cow::Borrowed(typ),
34+
version: Cow::Borrowed(version),
35+
}
36+
} else {
37+
Self {
38+
typ: Cow::Borrowed(s),
39+
version: Cow::Owned("latest".into()),
40+
}
41+
}
42+
}
43+
}
44+
45+
impl From<String> for ModuleTypeVersion<'_> {
46+
fn from(s: String) -> Self {
47+
if let Some((typ, version)) = s.split_once('@') {
48+
Self {
49+
typ: Cow::Owned(typ.to_owned()),
50+
version: Cow::Owned(version.to_owned()),
51+
}
52+
} else {
53+
Self {
54+
typ: Cow::Owned(s),
55+
version: Cow::Owned("latest".into()),
56+
}
57+
}
58+
}
59+
}
60+
61+
impl Serialize for ModuleTypeVersion<'_> {
62+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
63+
where
64+
S: serde::Serializer,
65+
{
66+
serializer.serialize_str(&self.to_string())
67+
}
68+
}
69+
70+
impl<'de> Deserialize<'de> for ModuleTypeVersion<'_> {
71+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
72+
where
73+
D: Deserializer<'de>,
74+
{
75+
let value: String = Deserialize::deserialize(deserializer)?;
76+
Ok(value.into())
77+
}
78+
}

recipe/src/module_ext.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ impl ModuleExt<'_> {
7272
module
7373
.required_fields
7474
.as_ref()
75-
.is_some_and(|rf| rf.module_type == "akmods")
75+
.is_some_and(|rf| rf.module_type.typ() == "akmods")
7676
})
7777
.filter_map(|module| {
7878
Some(

recipe/src/stage.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ impl Stage<'_> {
108108
required_fields: None,
109109
from_file: Some(file_name),
110110
} => {
111-
let file_name = PathBuf::from(file_name.as_ref());
111+
let file_name = PathBuf::from(&**file_name);
112112
if traversed_files.contains(&file_name) {
113113
bail!(
114114
"{} File {} has already been parsed:\n{traversed_files:?}",

template/templates/modules/modules.j2

+9-9
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
ARG CACHEBUST="{{ build_id }}"
77
{%- endif %}
88

9-
{%- if module.module_type == "containerfile" %}
9+
{%- if module.module_type.typ() == "containerfile" %}
1010
{%- include "modules/containerfile/containerfile.j2" %}
11-
{%- else if module.module_type == "copy" %}
11+
{%- else if module.module_type.typ() == "copy" %}
1212
{%- include "modules/copy/copy.j2" %}
1313
{%- else %}
1414
RUN \
@@ -22,15 +22,15 @@ RUN \
2222
{%- else if module.is_local_source() %}
2323
--mount=type=bind,from=stage-modules,src=/modules,dst=/tmp/modules,rw \
2424
{%- else %}
25-
--mount=type=bind,from=ghcr.io/blue-build/modules/{{ module.module_type }}:latest,src=/modules,dst=/tmp/modules,rw \
25+
--mount=type=bind,from={{ blue_build_utils::constants::BLUE_BUILD_MODULE_IMAGE_REF }}/{{ module.module_type.typ() }}:{{ module.module_type.version() }},src=/modules,dst=/tmp/modules,rw \
2626
{%- endif %}
27-
{%- if module.module_type == "akmods" %}
27+
{%- if module.module_type.typ() == "akmods" %}
2828
--mount=type=bind,from=stage-akmods-{{ module.generate_akmods_info(os_version).stage_name }},src=/rpms,dst=/tmp/rpms,rw \
2929
{%- endif %}
3030
--mount=type=bind,from={{ build_scripts_image }},src=/scripts/,dst=/tmp/scripts/ \
3131
--mount=type=cache,dst=/var/cache/rpm-ostree,id=rpm-ostree-cache-{{ recipe.name }}-{{ recipe.image_version }},sharing=locked \
3232
--mount=type=cache,dst=/var/cache/libdnf5,id=dnf-cache-{{ recipe.name }}-{{ recipe.image_version }},sharing=locked \
33-
/tmp/scripts/run_module.sh '{{ module.module_type }}' '{{ module|json|safe }}'
33+
/tmp/scripts/run_module.sh '{{ module.module_type.typ() }}' '{{ module|json|safe }}'
3434
{%- endif %}
3535
{%- endif %}
3636
{%- endfor %}
@@ -45,9 +45,9 @@ RUN \
4545
ARG CACHEBUST="{{ build_id }}"
4646
{%- endif %}
4747

48-
{%- if module.module_type == "containerfile" %}
48+
{%- if module.module_type.typ() == "containerfile" %}
4949
{%- include "modules/containerfile/containerfile.j2" %}
50-
{%- else if module.module_type == "copy" %}
50+
{%- else if module.module_type.typ() == "copy" %}
5151
{%- include "modules/copy/copy.j2" %}
5252
{%- else %}
5353
RUN \
@@ -61,10 +61,10 @@ RUN \
6161
{%- else if module.is_local_source() %}
6262
--mount=type=bind,from=stage-modules,src=/modules,dst=/tmp/modules,rw \
6363
{%- else %}
64-
--mount=type=bind,from=ghcr.io/blue-build/modules/{{ module.module_type }}:latest,src=/modules,dst=/tmp/modules,rw \
64+
--mount=type=bind,from={{ blue_build_utils::constants::BLUE_BUILD_MODULE_IMAGE_REF }}/{{ module.module_type.typ() }}:{{ module.module_type.version() }},src=/modules,dst=/tmp/modules,rw \
6565
{%- endif %}
6666
--mount=type=bind,from={{ build_scripts_image }},src=/scripts/,dst=/tmp/scripts/ \
67-
/tmp/scripts/run_module.sh '{{ module.module_type }}' '{{ module|json|safe }}'
67+
/tmp/scripts/run_module.sh '{{ module.module_type.typ() }}' '{{ module|json|safe }}'
6868
{%- endif %}
6969
{%- endif %}
7070
{%- endfor %}

utils/src/constants.rs

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ pub const XDG_RUNTIME_DIR: &str = "XDG_RUNTIME_DIR";
7575
// Misc
7676
pub const BUILD_SCRIPTS_IMAGE_REF: &str = "ghcr.io/blue-build/cli/build-scripts";
7777
pub const BLUE_BULID_IMAGE_REF: &str = "ghcr.io/blue-build/cli";
78+
pub const BLUE_BUILD_MODULE_IMAGE_REF: &str = "ghcr.io/blue-build/modules";
7879
pub const COSIGN_IMAGE: &str = "ghcr.io/sigstore/cosign/cosign:v2.4.1";
7980
pub const NUSHELL_IMAGE: &str = "ghcr.io/blue-build/nushell-image:latest";
8081
pub const OCI_ARCHIVE: &str = "oci-archive";

0 commit comments

Comments
 (0)