From bd6fabd0de73217a69fbf89a8441de45b027c314 Mon Sep 17 00:00:00 2001 From: Gerald Pinder Date: Sun, 1 Oct 2023 15:25:53 -0400 Subject: [PATCH] Get cli in basic working order --- src/bin/ublue.rs | 55 ++------------------- src/lib.rs | 79 ++++++++++++++++--------------- src/recipe.rs | 60 +++++++++++++++++++++++ templates/starting_point.template | 39 ++++++++++++--- 4 files changed, 135 insertions(+), 98 deletions(-) create mode 100644 src/recipe.rs diff --git a/src/bin/ublue.rs b/src/bin/ublue.rs index 1d82db2..38195f6 100644 --- a/src/bin/ublue.rs +++ b/src/bin/ublue.rs @@ -1,36 +1,6 @@ -use std::{fs, path::PathBuf}; - use anyhow::Result; -use clap::{Parser, Subcommand}; -use tera::{Context, Tera}; -use ublue_rs::{Recipe, DEFAULT_CONTAINERFILE}; - -#[derive(Parser, Debug)] -#[command(name = "Ublue Builder", author, version, about, long_about = None)] -struct UblueArgs { - #[command(subcommand)] - command: CommandArgs, -} - -#[derive(Debug, Subcommand)] -enum CommandArgs { - /// Generate a Containerfile from a recipe - Template { - /// The recipe file to create a template from - #[arg()] - recipe: String, - - /// Optional Containerfile to use as a template - #[arg(short, long)] - containerfile: Option, - }, - - /// Build an image from a Containerfile - Build { - #[arg()] - containerfile: String, - }, -} +use clap::Parser; +use ublue_rs::{setup_tera, CommandArgs, UblueArgs}; fn main() -> Result<()> { let args = UblueArgs::parse(); @@ -40,26 +10,7 @@ fn main() -> Result<()> { recipe, containerfile: _, } => { - let mut recipe_de: Recipe = - serde_yaml::from_str(fs::read_to_string(PathBuf::from(&recipe))?.as_str())?; - - recipe_de.rpm.repos = recipe_de - .rpm - .repos - .iter() - .map(|s| { - s.replace( - "%FEDORA_VERSION%", - recipe_de.fedora_version.to_string().as_str(), - ) - }) - .collect(); - - let mut context = Context::from_serialize(recipe_de)?; - context.insert("recipe", &recipe); - - let mut tera = Tera::default(); - tera.add_raw_template("Containerfile", DEFAULT_CONTAINERFILE)?; + let (tera, context) = setup_tera(recipe)?; let output = tera.render("Containerfile", &context)?; println!("{output}"); } diff --git a/src/lib.rs b/src/lib.rs index 712c6d3..2e5d301 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,51 +1,52 @@ -use serde::{Deserialize, Serialize}; +use std::{fs, path::PathBuf}; + +use anyhow::Result; +use clap::{Parser, Subcommand}; +use recipe::Recipe; +use tera::{Context, Tera}; pub const DEFAULT_CONTAINERFILE: &'static str = include_str!("../templates/starting_point.template"); -#[derive(Serialize, Deserialize, Debug)] -pub struct Recipe { - pub name: String, +pub mod recipe; - #[serde(alias = "base-image")] - pub base_image: String, - - #[serde(alias = "fedora-version")] - pub fedora_version: u16, - - pub scripts: Scripts, - - pub rpm: Rpm, - - #[serde(alias = "usr-dir-overlays")] - pub usr_dir_overlays: Option>, - - pub containerfiles: Option, - - pub firstboot: FirstBoot, +#[derive(Parser, Debug)] +#[command(name = "Ublue Builder", author, version, about, long_about = None)] +pub struct UblueArgs { + #[command(subcommand)] + pub command: CommandArgs, } -#[derive(Debug, Serialize, Deserialize)] -pub struct Scripts { - pub pre: Vec, - pub post: Vec, +#[derive(Debug, Subcommand)] +pub enum CommandArgs { + /// Generate a Containerfile from a recipe + Template { + /// The recipe file to create a template from + #[arg()] + recipe: String, + + /// Optional Containerfile to use as a template + #[arg(short, long)] + containerfile: Option, + }, + + /// Build an image from a Containerfile + Build { + #[arg()] + containerfile: String, + }, } -#[derive(Debug, Serialize, Deserialize)] -pub struct Rpm { - pub repos: Vec, - pub install: Vec, - pub remove: Vec, -} +pub fn setup_tera(recipe: String) -> Result<(Tera, Context)> { + let recipe_de = + serde_yaml::from_str::(fs::read_to_string(PathBuf::from(&recipe))?.as_str())? + .process_repos(); -#[derive(Debug, Serialize, Deserialize)] -pub struct FirstBoot { - pub yafti: bool, - pub flatpaks: Vec, -} + let mut context = Context::from_serialize(recipe_de)?; + context.insert("recipe", &recipe); -#[derive(Debug, Serialize, Deserialize)] -pub struct Containerfiles { - pub pre: Vec, - pub post: Vec, + let mut tera = Tera::default(); + tera.add_raw_template("Containerfile", DEFAULT_CONTAINERFILE)?; + + Ok((tera, context)) } diff --git a/src/recipe.rs b/src/recipe.rs new file mode 100644 index 0000000..456ebcc --- /dev/null +++ b/src/recipe.rs @@ -0,0 +1,60 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug)] +pub struct Recipe { + pub name: String, + + #[serde(alias = "base-image")] + pub base_image: String, + + #[serde(alias = "fedora-version")] + pub fedora_version: u16, + + pub scripts: Scripts, + + pub rpm: Rpm, + + #[serde(alias = "usr-dir-overlays")] + pub usr_dir_overlays: Option>, + + pub containerfiles: Option, + + pub firstboot: FirstBoot, +} + +impl Recipe { + pub fn process_repos(mut self) -> Self { + self.rpm.repos = self + .rpm + .repos + .iter() + .map(|s| s.replace("%FEDORA_VERSION%", self.fedora_version.to_string().as_str())) + .collect(); + self + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Scripts { + pub pre: Vec, + pub post: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Rpm { + pub repos: Vec, + pub install: Vec, + pub remove: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct FirstBoot { + pub yafti: bool, + pub flatpaks: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Containerfiles { + pub pre: Vec, + pub post: Vec, +} diff --git a/templates/starting_point.template b/templates/starting_point.template index 3628446..5fd90b0 100644 --- a/templates/starting_point.template +++ b/templates/starting_point.template @@ -23,33 +23,58 @@ COPY --from=docker.io/mikefarah/yq /usr/bin/yq /usr/bin/yq COPY --from=gcr.io/projectsigstore/cosign /ko-app/cosign /usr/bin/cosign COPY scripts /tmp/scripts +RUN find /tmp/scripts -type f -exec chmod +x {} \; +{# TODO: Create helper function {% if continerfiles %} {% for containerfile in containerfiles.pre %} {{ print_containerfile(containerfile = containerfile) }} {% endfor %} -{% endif %} +{% endif %} #} {% for script in scripts.pre %} -RUN chmod +x /tmp/scripts/{{ script }} && /tmp/scripts/{{ script }} pre +RUN /bin/bash -c '/tmp/scripts/{{ script }} pre' {% endfor %} {% for repo in rpm.repos %} RUN wget "{{ repo }}" -P "/etc/yum.repos.d/" {% endfor %} -RUN rpm-ostree uninstall {% for app in rpm.remove %}{{ app }} {% endfor %} +RUN rpm-ostree override remove {% for app in rpm.remove %}{{ app }} {% endfor %} + +ARG FIRSTBOOT_DATA="/usr/share/ublue-os/firstboot" +ARG FIRSTBOOT_LINK="/usr/etc/profile.d/ublue-firstboot.sh" +{% if firstboot.yafti -%} +RUN echo "-- firstboot: Installing and enabling \"yafti\" --"; \ + pip install --prefix=/usr yafti; \ + mkdir -p "$(dirname "${FIRSTBOOT_LINK}")"; \ + ln -s "${FIRSTBOOT_DATA}/launcher/login-profile.sh" "${FIRSTBOOT_LINK}" +ARG YAFTI_FILE="${FIRSTBOOT_DATA}/yafti.yml" +RUN echo "-- yafti: Adding Flatpaks defined in recipe.yml --"; \ + yq -i '.screens.applications.values.groups.Custom.description = "Flatpaks suggested by the image maintainer."' "${YAFTI_FILE}"; \ + yq -i '.screens.applications.values.groups.Custom.default = true' "${YAFTI_FILE}"; \ +{%- for pkg in firstboot.flatpaks %} + echo "Adding to yafti: {{ pkg }}"; \ + yq -i ".screens.applications.values.groups.Custom.packages += [{\"{{ pkg }}\": \"{{ pkg }}\"}]" "${YAFTI_FILE}"; \ +{%- endfor %} + echo "Done setting up Yafti" +{% else %} +RUN echo "-- firstboot: Removing all \"firstboot\" components --"; \ + rm -f "${FIRSTBOOT_LINK}"; \ + rm -rf "${FIRSTBOOT_DATA}" +{% endif %} RUN rpm-ostree install {% for app in rpm.install %}{{ app }} {% endfor %} -{% for script in scripts.post %} -RUN chmod +x /tmp/scripts/{{ script }} && /tmp/scripts/{{ script }} post -{% endfor %} +{% for script in scripts.post -%} +RUN /bin/bash -c '/tmp/scripts/{{ script }} post' +{% endfor -%} +{# TODO: Create helper function {% if continerfiles %} {% for containerfile in containerfiles.post %} {{ print_containerfile(containerfile = containerfile) }} {% endfor %} -{% endif %} +{% endif %} #} RUN rm -rf /tmp/* /var/* && ostree container commit