feat: snippets (#51)

## Goals

This PR adds snippets which is being discussed in #41 .

It will generate snippet lines for *ONLY* our containerfile module

- [x] allow for modules to specify snippets
- [x] append snippets to module run inside Containerfile
- [ ] write supporting test

## Preview
Recipe.yml

```yml
# image will be published to ghcr.io/<user>/<name>
name: orora

description: A starting point for further customization of uBlue images. Make your own! https://ublue.it/making-your-own/

base-image: ghcr.io/ublue-os/silverblue-main
image-version: latest # latest is also supported if you want new updates ASAP

modules:
  - type: signing
    snippets:
      - COPY --from=ghcr.io/blue-build/cli:latest-installer /out/BLUEBUILD /usr/bin/BLUEBUILD
```

Generated Container File snippet

```docker
RUN chmod +x /tmp/modules/signing/signing.sh && source /tmp/exports.sh && /tmp/modules/signing/signing.sh '{"type":"signing","snippets":["COPY --from=ghcr.io/blue-build/cli:latest-installer /out/BLUEBUILD /usr/bin/BLUEBUILD"]}'
COPY --from=ghcr.io/blue-build/cli:latest-installer /out/BLUEBUILD /usr/bin/BLUEBUILD
```

---------

Co-authored-by: Gerald Pinder <gmpinder@gmail.com>
This commit is contained in:
Hikari 2024-02-07 12:03:26 -06:00 committed by GitHub
parent 2492bb0eee
commit 0d8fd93917
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 29 additions and 9 deletions

View file

@ -121,12 +121,12 @@ fn has_cosign_file() -> bool {
}
#[must_use]
fn get_containerfile_list(module: &Module) -> Option<Vec<String>> {
if module.module_type.as_ref()? == "containerfile" {
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("containerfiles")?
.get(list_key)?
.as_sequence()?
.iter()
.filter_map(|t| Some(t.as_str()?.to_owned()))
@ -137,6 +137,16 @@ fn get_containerfile_list(module: &Module) -> Option<Vec<String>> {
}
}
#[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 {
debug!("print_containerfile({containerfile})");
@ -156,7 +166,7 @@ fn print_containerfile(containerfile: &str) -> String {
fn print_module_context(module: &Module) -> String {
serde_json::to_string(module).unwrap_or_else(|e| {
error!("Failed to parse module: {e}");
error!("Failed to parse module!!!!!: {e}");
process::exit(1);
})
}

View file

@ -209,6 +209,11 @@ pub struct ModuleExt {
}
impl ModuleExt {
/// # Parse a module file returning a [`ModuleExt`]
///
/// # Errors
/// Can return an `anyhow` Error if the file cannot be read or deserialized
/// into a [`ModuleExt`]
pub fn parse_module_from_file(file_name: &str) -> Result<ModuleExt> {
let file_path = PathBuf::from("config").join(file_name);
let file_path = if file_path.is_absolute() {
@ -246,6 +251,7 @@ pub struct Module {
}
impl Module {
#[must_use]
pub fn get_modules(modules: &[Self]) -> Vec<Self> {
modules
.iter()

View file

@ -34,8 +34,8 @@ pub fn serde_yaml_err(contents: &str) -> impl Fn(serde_yaml::Error) -> SerdeErro
contents.to_string(),
(
err.into(),
location.map_or(0, |l| l.line()).into(),
location.map_or(0, |l| l.column()).into(),
location.map_or(0, serde_yaml::Location::line).into(),
location.map_or(0, serde_yaml::Location::column).into(),
),
)
}