blue-build 0.8.2

A CLI tool built for creating Containerfile templates based on the Ublue Community Project
Documentation
use std::path::PathBuf;

use anyhow::{anyhow, Result};
use blue_build_recipe::Recipe;
use blue_build_template::{ContainerFileTemplate, Template};
use blue_build_utils::constants::*;
use clap::Args;
use log::{debug, info, trace};
use typed_builder::TypedBuilder;
use uuid::Uuid;

use super::BlueBuildCommand;

#[derive(Debug, Clone, Args, TypedBuilder)]
pub struct TemplateCommand {
    /// The recipe file to create a template from
    #[arg()]
    #[builder(default, setter(into, strip_option))]
    recipe: Option<PathBuf>,

    /// File to output to instead of STDOUT
    #[arg(short, long)]
    #[builder(default, setter(into, strip_option))]
    output: Option<PathBuf>,

    #[clap(skip)]
    #[builder(default, setter(into, strip_option))]
    build_id: Option<Uuid>,
}

impl BlueBuildCommand for TemplateCommand {
    fn try_run(&mut self) -> Result<()> {
        info!(
            "Templating for recipe at {}",
            self.recipe
                .clone()
                .unwrap_or_else(|| PathBuf::from(RECIPE_PATH))
                .display()
        );

        self.build_id.get_or_insert(Uuid::new_v4());

        self.template_file()
    }
}

impl TemplateCommand {
    fn template_file(&self) -> Result<()> {
        trace!("TemplateCommand::template_file()");

        let recipe_path = self
            .recipe
            .clone()
            .unwrap_or_else(|| PathBuf::from(RECIPE_PATH));

        debug!("Deserializing recipe");
        let recipe_de = Recipe::parse(&recipe_path)?;
        trace!("recipe_de: {recipe_de:#?}");

        let build_id = self
            .build_id
            .ok_or_else(|| anyhow!("Build ID should have been generated by now"))?;

        let template = ContainerFileTemplate::builder()
            .build_id(build_id)
            .recipe(&recipe_de)
            .recipe_path(recipe_path.as_path())
            .build();

        let output_str = template.render()?;
        if let Some(output) = self.output.as_ref() {
            debug!("Templating to file {}", output.display());
            trace!("Containerfile:\n{output_str}");

            std::fs::write(output, output_str)?;
        } else {
            debug!("Templating to stdout");
            println!("{output_str}");
        }

        info!("Finished templating Containerfile");
        Ok(())
    }
}

// ======================================================== //
// ========================= Helpers ====================== //
// ======================================================== //