diff --git a/.gitignore b/.gitignore index 1c239e4..8839e91 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target .sccache/ +.vscode/ \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 3677b41..9e5218a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,23 +8,23 @@ license = "Apache-2.0" categories = ["command-line-utilities"] [dependencies] -anyhow = "1.0.75" +anyhow = "1" askama = { version = "0.12.1", features = ["serde-json"] } cfg-if = "1.0.0" -chrono = "0.4.31" -clap = { version = "4.4.4", features = ["derive"] } +chrono = "0.4" +clap = { version = "4", features = ["derive"] } clap-verbosity-flag = "2.1.1" derive_builder = "0.12.0" env_logger = "0.10.1" futures-util = { version = "0.3.30", optional = true } indexmap = { version = "2.1.0", features = ["serde"] } -log = "0.4.20" +log = "0.4" podman-api = { version = "0.10.0", optional = true } -serde = { version = "1.0.188", features = ["derive"] } -serde_json = "1.0.107" +serde = { version = "1", features = ["derive"] } +serde_json = "1" serde_yaml = "0.9.25" sigstore = { version = "0.8.0", optional = true } -tokio = { version = "1.35.1", features = ["full"], optional = true } +tokio = { version = "1", features = ["full"], optional = true } typed-builder = "0.18.0" users = "0.11.0" diff --git a/src/bin/bb.rs b/src/bin/bb.rs index 3ab3ba8..2f8b170 100644 --- a/src/bin/bb.rs +++ b/src/bin/bb.rs @@ -1,11 +1,17 @@ -use blue_build::{self, build, local, template}; +#![warn(clippy::pedantic, clippy::nursery)] + use clap::{Parser, Subcommand}; use clap_verbosity_flag::{InfoLevel, Verbosity}; use env_logger::WriteStyle; use log::trace; +use blue_build::{ + self, + commands::{build, local, template, BlueBuildCommand}, +}; + #[cfg(feature = "init")] -use blue_build::init; +use blue_build::commands::init; #[derive(Parser, Debug)] #[command(name = "BlueBuild", author, version, about, long_about = None)] @@ -68,15 +74,15 @@ fn main() { trace!("{args:#?}"); match args.command { + #[cfg(feature = "init")] + CommandArgs::Init(mut command) => command.run(), + + #[cfg(feature = "init")] + CommandArgs::New(mut command) => command.run(), + + CommandArgs::Template(mut command) => command.run(), CommandArgs::Build(mut command) => command.run(), - CommandArgs::Template(command) => command.run(), - CommandArgs::Upgrade(command) => command.run(), - CommandArgs::Rebase(command) => command.run(), - - #[cfg(feature = "init")] - CommandArgs::Init(command) => command.run(), - - #[cfg(feature = "init")] - CommandArgs::New(command) => command.run(), + CommandArgs::Rebase(mut command) => command.run(), + CommandArgs::Upgrade(mut command) => command.run(), } } diff --git a/src/commands.rs b/src/commands.rs new file mode 100644 index 0000000..43aaa49 --- /dev/null +++ b/src/commands.rs @@ -0,0 +1,20 @@ +#[cfg(feature = "init")] +pub mod init; + +pub mod build; +pub mod local; +pub mod template; + +use log::error; + +pub trait BlueBuildCommand { + fn try_run(&mut self) -> anyhow::Result<()>; + + /// Runs the command and exits if there is an error. + fn run(&mut self) { + if let Err(e) = self.try_run() { + error!("{e}"); + std::process::exit(1); + } + } +} diff --git a/src/build.rs b/src/commands/build.rs similarity index 82% rename from src/build.rs rename to src/commands/build.rs index 9b2ee11..ca3a743 100644 --- a/src/build.rs +++ b/src/commands/build.rs @@ -29,10 +29,12 @@ use futures_util::StreamExt; use tokio::runtime::Runtime; use crate::{ + commands::template::TemplateCommand, ops::{self, ARCHIVE_SUFFIX}, - template::{Recipe, TemplateCommand}, }; +use super::{template::Recipe, BlueBuildCommand}; + #[derive(Debug, Clone, Args, TypedBuilder)] pub struct BuildCommand { /// The recipe file to build an image @@ -127,9 +129,9 @@ pub struct BuildCommand { private_key: Option, } -impl BuildCommand { +impl BlueBuildCommand for BuildCommand { /// Runs the command and returns a result. - pub fn try_run(&mut self) -> Result<()> { + fn try_run(&mut self) -> Result<()> { trace!("BuildCommand::try_run()"); if self.push && self.archive.is_some() { @@ -168,18 +170,9 @@ impl BuildCommand { #[cfg(not(feature = "podman-api"))] self.build_image() } +} - /// Runs the command and exits if there is an error. - pub fn run(&mut self) { - trace!("BuildCommand::run()"); - - if let Err(e) = self.try_run() { - error!("Failed to build image: {e}"); - process::exit(1); - } - info!("Finished building!"); - } - +impl BuildCommand { #[cfg(feature = "podman-api")] async fn build_image_podman_api(&self, client: Podman) -> Result<()> { use podman_api::opts::ImageTagOpts; @@ -327,7 +320,7 @@ impl BuildCommand { } } - self.sign_images(&image_name, tags.first().map(|x| x.as_str()))?; + sign_images(&image_name, tags.first().map(String::as_str))?; } Ok(()) } @@ -434,6 +427,9 @@ impl BuildCommand { Ok(()) } + /// # Errors + /// + /// Will return `Err` if the image name cannot be generated. pub fn generate_full_image_name(&self, recipe: &Recipe) -> Result { trace!("BuildCommand::generate_full_image_name({recipe:#?})"); info!("Generating full image name"); @@ -483,7 +479,7 @@ impl BuildCommand { if self.push { bail!("Need '--registry' and '--registry-path' in order to push image"); } - recipe.name.to_owned() + recipe.name.clone() } } }; @@ -493,6 +489,9 @@ impl BuildCommand { Ok(image_name) } + /// # Errors + /// + /// Will return `Err` if the build fails. fn run_build(&self, image_name: &str, tags: &[String]) -> Result<()> { trace!("BuildCommand::run_build({image_name}, {tags:#?})"); @@ -579,7 +578,7 @@ impl BuildCommand { if self.push { debug!("Pushing all images"); - for tag in tags.iter() { + for tag in tags { debug!("Pushing image {image_name}:{tag}"); let tag_image = format!("{image_name}:{tag}"); @@ -605,138 +604,143 @@ impl BuildCommand { .status()?; if status.success() { - info!("Successfully pushed {image_name}:{tag}!") + info!("Successfully pushed {image_name}:{tag}!"); } else { bail!("Failed to push image {image_name}:{tag}"); } } - self.sign_images(image_name, tags.first().map(|x| x.as_str()))?; - } - - Ok(()) - } - - fn sign_images(&self, image_name: &str, tag: Option<&str>) -> Result<()> { - trace!("BuildCommand::sign_images({image_name}, {tag:?})"); - - env::set_var("COSIGN_PASSWORD", ""); - env::set_var("COSIGN_YES", "true"); - - let image_digest = get_image_digest(image_name, tag)?; - let image_name_tag = tag - .map(|t| format!("{image_name}:{t}")) - .unwrap_or(image_name.to_owned()); - - match ( - env::var("CI_DEFAULT_BRANCH"), - env::var("CI_COMMIT_REF_NAME"), - env::var("CI_PROJECT_URL"), - env::var("CI_SERVER_PROTOCOL"), - env::var("CI_SERVER_HOST"), - env::var("SIGSTORE_ID_TOKEN"), - env::var("GITHUB_EVENT_NAME"), - env::var("GITHUB_REF_NAME"), - env::var("COSIGN_PRIVATE_KEY"), - ) { - ( - Ok(ci_default_branch), - Ok(ci_commit_ref), - Ok(ci_project_url), - Ok(ci_server_protocol), - Ok(ci_server_host), - Ok(_), - _, - _, - _, - ) if ci_default_branch == ci_commit_ref => { - trace!("CI_PROJECT_URL={ci_project_url}, CI_DEFAULT_BRANCH={ci_default_branch}, CI_COMMIT_REF_NAME={ci_commit_ref}, CI_SERVER_PROTOCOL={ci_server_protocol}, CI_SERVER_HOST={ci_server_host}"); - - debug!("On default branch"); - - info!("Signing image: {image_digest}"); - - trace!("cosign sign {image_digest}"); - - if Command::new("cosign") - .arg("sign") - .arg(&image_digest) - .status()? - .success() - { - info!("Successfully signed image!"); - } else { - bail!("Failed to sign image: {image_digest}"); - } - - let cert_ident = - format!("{ci_project_url}//.gitlab-ci.yml@refs/heads/{ci_default_branch}"); - - let cert_oidc = format!("{ci_server_protocol}://{ci_server_host}"); - - trace!("cosign verify --certificate-identity {cert_ident} --certificate-oidc-issuer {cert_oidc} {image_name_tag}"); - - if !Command::new("cosign") - .arg("verify") - .arg("--certificate-identity") - .arg(&cert_ident) - .arg("--certificate-oidc-issuer") - .arg(&cert_oidc) - .arg(&image_name_tag) - .status()? - .success() - { - bail!("Failed to verify image!"); - } - } - (_, _, _, _, _, _, Ok(github_event_name), Ok(github_ref_name), Ok(_)) - if github_event_name != "pull_request" && github_ref_name == "live" => - { - trace!("GITHUB_EVENT_NAME={github_event_name}, GITHUB_REF_NAME={github_ref_name}"); - - debug!("On live branch"); - - info!("Signing image: {image_digest}"); - - trace!("cosign sign --key=env://COSIGN_PRIVATE_KEY {image_digest}"); - - if Command::new("cosign") - .arg("sign") - .arg("--key=env://COSIGN_PRIVATE_KEY") - .arg(&image_digest) - .status()? - .success() - { - info!("Successfully signed image!"); - } else { - bail!("Failed to sign image: {image_digest}"); - } - - trace!("cosign verify --key ./cosign.pub {image_name_tag}"); - - if !Command::new("cosign") - .arg("verify") - .arg("--key=./cosign.pub") - .arg(&image_name_tag) - .status()? - .success() - { - bail!("Failed to verify image!"); - } - } - _ => debug!("Not running in CI with cosign variables, not signing"), + sign_images(image_name, tags.first().map(String::as_str))?; } Ok(()) } } +// ======================================================== // +// ========================= Helpers ====================== // +// ======================================================== // + +fn sign_images(image_name: &str, tag: Option<&str>) -> Result<()> { + trace!("BuildCommand::sign_images({image_name}, {tag:?})"); + + env::set_var("COSIGN_PASSWORD", ""); + env::set_var("COSIGN_YES", "true"); + + let image_digest = get_image_digest(image_name, tag)?; + let image_name_tag = tag + .map(|t| format!("{image_name}:{t}")) + .unwrap_or(image_name.to_owned()); + + match ( + env::var("CI_DEFAULT_BRANCH"), + env::var("CI_COMMIT_REF_NAME"), + env::var("CI_PROJECT_URL"), + env::var("CI_SERVER_PROTOCOL"), + env::var("CI_SERVER_HOST"), + env::var("SIGSTORE_ID_TOKEN"), + env::var("GITHUB_EVENT_NAME"), + env::var("GITHUB_REF_NAME"), + env::var("COSIGN_PRIVATE_KEY"), + ) { + ( + Ok(ci_default_branch), + Ok(ci_commit_ref), + Ok(ci_project_url), + Ok(ci_server_protocol), + Ok(ci_server_host), + Ok(_), + _, + _, + _, + ) if ci_default_branch == ci_commit_ref => { + trace!("CI_PROJECT_URL={ci_project_url}, CI_DEFAULT_BRANCH={ci_default_branch}, CI_COMMIT_REF_NAME={ci_commit_ref}, CI_SERVER_PROTOCOL={ci_server_protocol}, CI_SERVER_HOST={ci_server_host}"); + + debug!("On default branch"); + + info!("Signing image: {image_digest}"); + + trace!("cosign sign {image_digest}"); + + if Command::new("cosign") + .arg("sign") + .arg(&image_digest) + .status()? + .success() + { + info!("Successfully signed image!"); + } else { + bail!("Failed to sign image: {image_digest}"); + } + + let cert_ident = + format!("{ci_project_url}//.gitlab-ci.yml@refs/heads/{ci_default_branch}"); + + let cert_oidc = format!("{ci_server_protocol}://{ci_server_host}"); + + trace!("cosign verify --certificate-identity {cert_ident} --certificate-oidc-issuer {cert_oidc} {image_name_tag}"); + + if !Command::new("cosign") + .arg("verify") + .arg("--certificate-identity") + .arg(&cert_ident) + .arg("--certificate-oidc-issuer") + .arg(&cert_oidc) + .arg(&image_name_tag) + .status()? + .success() + { + bail!("Failed to verify image!"); + } + } + (_, _, _, _, _, _, Ok(github_event_name), Ok(github_ref_name), Ok(_)) + if github_event_name != "pull_request" && github_ref_name == "live" => + { + trace!("GITHUB_EVENT_NAME={github_event_name}, GITHUB_REF_NAME={github_ref_name}"); + + debug!("On live branch"); + + info!("Signing image: {image_digest}"); + + trace!("cosign sign --key=env://COSIGN_PRIVATE_KEY {image_digest}"); + + if Command::new("cosign") + .arg("sign") + .arg("--key=env://COSIGN_PRIVATE_KEY") + .arg(&image_digest) + .status()? + .success() + { + info!("Successfully signed image!"); + } else { + bail!("Failed to sign image: {image_digest}"); + } + + trace!("cosign verify --key ./cosign.pub {image_name_tag}"); + + if !Command::new("cosign") + .arg("verify") + .arg("--key=./cosign.pub") + .arg(&image_name_tag) + .status()? + .success() + { + bail!("Failed to verify image!"); + } + } + _ => debug!("Not running in CI with cosign variables, not signing"), + } + + Ok(()) +} + fn get_image_digest(image_name: &str, tag: Option<&str>) -> Result { trace!("get_image_digest({image_name}, {tag:?})"); - let image_url = match tag { - Some(tag) => format!("docker://{image_name}:{tag}"), - None => format!("docker://{image_name}"), + let image_url = if let Some(tag) = tag { + format!("docker://{image_name}:{tag}") + } else { + format!("docker://{image_name}") }; trace!("skopeo inspect --format='{{.Digest}}' {image_url}"); diff --git a/src/build/build_strategy.rs b/src/commands/build/build_strategy.rs similarity index 100% rename from src/build/build_strategy.rs rename to src/commands/build/build_strategy.rs diff --git a/src/init.rs b/src/commands/init.rs similarity index 70% rename from src/init.rs rename to src/commands/init.rs index c9fe2fb..5952020 100644 --- a/src/init.rs +++ b/src/commands/init.rs @@ -8,9 +8,11 @@ use clap::Args; use log::error; use typed_builder::TypedBuilder; -const GITLAB_CI_FILE: &'static str = include_str!("../templates/init/gitlab-ci.yml.tera"); -const RECIPE_FILE: &'static str = include_str!("../templates/init/recipe.yml.tera"); -const LICENSE_FILE: &'static str = include_str!("../LICENSE"); +use super::BlueBuildCommand; + +const GITLAB_CI_FILE: &'static str = include_str!("../../templates/init/gitlab-ci.yml.tera"); +const RECIPE_FILE: &'static str = include_str!("../../templates/init/recipe.yml.tera"); +const LICENSE_FILE: &'static str = include_str!("../../LICENSE"); #[derive(Debug, Clone, Default, Args, TypedBuilder)] pub struct NewInitCommon { @@ -30,8 +32,8 @@ pub struct InitCommand { common: NewInitCommon, } -impl InitCommand { - pub fn try_run(&self) -> Result<()> { +impl BlueBuildCommand for InitCommand { + fn try_run(&mut self) -> Result<()> { let base_dir = match self.dir.as_ref() { Some(dir) => dir, None => std::path::Path::new("./"), @@ -40,14 +42,9 @@ impl InitCommand { self.initialize_directory(base_dir); Ok(()) } +} - pub fn run(&self) { - if let Err(e) = self.try_run() { - error!("Failed to init ublue project: {e}"); - process::exit(1); - } - } - +impl InitCommand { fn initialize_directory(&self, base_dir: &Path) { let recipe_path = base_dir.join("recipe.yml"); @@ -74,19 +71,12 @@ pub struct NewCommand { common: NewInitCommon, } -impl NewCommand { - pub fn try_run(&self) -> Result<()> { +impl BlueBuildCommand for NewCommand { + fn try_run(&mut self) -> Result<()> { InitCommand::builder() .dir(self.dir.clone()) .common(self.common.clone()) .build() .try_run() } - - pub fn run(&self) { - if let Err(e) = self.try_run() { - error!("Failed to create new project: {e}"); - process::exit(1); - } - } } diff --git a/src/local.rs b/src/commands/local.rs similarity index 88% rename from src/local.rs rename to src/commands/local.rs index 4762e2e..7083cc0 100644 --- a/src/local.rs +++ b/src/commands/local.rs @@ -11,11 +11,12 @@ use typed_builder::TypedBuilder; use users::{Users, UsersCache}; use crate::{ - build::BuildCommand, + commands::{build::BuildCommand, template::Recipe}, ops::{self, ARCHIVE_SUFFIX, LOCAL_BUILD}, - template::Recipe, }; +use super::BlueBuildCommand; + #[derive(Default, Clone, Debug, TypedBuilder, Args)] pub struct LocalCommonArgs { /// The recipe file to build an image. @@ -35,8 +36,8 @@ pub struct UpgradeCommand { common: LocalCommonArgs, } -impl UpgradeCommand { - pub fn try_run(&self) -> Result<()> { +impl BlueBuildCommand for UpgradeCommand { + fn try_run(&mut self) -> Result<()> { trace!("UpgradeCommand::try_run()"); check_can_run()?; @@ -78,15 +79,6 @@ impl UpgradeCommand { } Ok(()) } - - pub fn run(&self) { - trace!("UpgradeCommand::run()"); - - if let Err(e) = self.try_run() { - error!("Failed to upgrade image: {e}"); - process::exit(1); - } - } } #[derive(Default, Clone, Debug, TypedBuilder, Args)] @@ -95,8 +87,8 @@ pub struct RebaseCommand { common: LocalCommonArgs, } -impl RebaseCommand { - pub fn try_run(&self) -> Result<()> { +impl BlueBuildCommand for RebaseCommand { + fn try_run(&mut self) -> Result<()> { trace!("RebaseCommand::try_run()"); check_can_run()?; @@ -142,24 +134,18 @@ impl RebaseCommand { } Ok(()) } - - pub fn run(&self) { - trace!("RebaseCommand::run()"); - - if let Err(e) = self.try_run() { - error!("Failed to rebase onto new image: {e}"); - process::exit(1); - } - } } +// ======================================================== // +// ========================= Helpers ====================== // +// ======================================================== // + fn check_can_run() -> Result<()> { trace!("check_can_run()"); ops::check_command_exists("rpm-ostree")?; let cache = UsersCache::new(); - if cache.get_current_uid() != 0 { bail!("You need to be root to rebase a local image! Try using 'sudo'."); } @@ -180,13 +166,7 @@ fn clean_local_build_dir(image_name: &str, rebase: bool) -> Result<()> { ); } - if !local_build_path.exists() { - debug!( - "Creating build output dir at {}", - local_build_path.display() - ); - fs::create_dir_all(local_build_path)?; - } else { + if local_build_path.exists() { debug!("Cleaning out build dir {LOCAL_BUILD}"); let entries = fs::read_dir(LOCAL_BUILD)?; @@ -205,6 +185,12 @@ fn clean_local_build_dir(image_name: &str, rebase: bool) -> Result<()> { fs::remove_file(path)?; } } + } else { + debug!( + "Creating build output dir at {}", + local_build_path.display() + ); + fs::create_dir_all(local_build_path)?; } Ok(()) diff --git a/src/template.rs b/src/commands/template.rs similarity index 87% rename from src/template.rs rename to src/commands/template.rs index 804b524..345d9e5 100644 --- a/src/template.rs +++ b/src/commands/template.rs @@ -15,6 +15,8 @@ use serde::{Deserialize, Serialize}; use serde_yaml::Value; use typed_builder::TypedBuilder; +use super::BlueBuildCommand; + #[derive(Debug, Clone, Template, TypedBuilder)] #[template(path = "Containerfile")] pub struct ContainerFileTemplate<'a> { @@ -58,6 +60,7 @@ pub struct Recipe { } impl Recipe { + #[must_use] pub fn generate_tags(&self) -> Vec { trace!("Recipe::generate_tags()"); debug!("Generating image tags for {}", &self.name); @@ -83,14 +86,14 @@ impl Recipe { } } - if default_branch != commit_branch { - debug!("Running on branch {commit_branch}"); - tags.push(format!("{commit_branch}-{image_version}")); - } else { + if default_branch == commit_branch { debug!("Running on the default branch"); tags.push(image_version.to_string()); tags.push(format!("{image_version}-{timestamp}")); - tags.push(timestamp.to_string()); + tags.push(timestamp); + } else { + debug!("Running on branch {commit_branch}"); + tags.push(format!("{commit_branch}-{image_version}")); } tags.push(format!("{commit_sha}-{image_version}")); @@ -108,7 +111,7 @@ impl Recipe { trace!("GITHUB_EVENT_NAME={github_event_name},PR_EVENT_NUMBER={github_event_number},GITHUB_SHA={github_sha},GITHUB_REF_NAME={github_ref_name}"); warn!("Detected running in Github, pulling information from GITHUB variables"); - let mut short_sha = github_sha.clone(); + let mut short_sha = github_sha; short_sha.truncate(7); if github_event_name == "pull_request" { @@ -167,20 +170,15 @@ pub struct TemplateCommand { output: Option, } -impl TemplateCommand { - pub fn try_run(&self) -> Result<()> { +impl BlueBuildCommand for TemplateCommand { + fn try_run(&mut self) -> Result<()> { info!("Templating for recipe at {}", self.recipe.display()); self.template_file() } +} - pub fn run(&self) { - if let Err(e) = self.try_run() { - error!("Failed to template file: {e}"); - process::exit(1); - } - } - +impl TemplateCommand { fn template_file(&self) -> Result<()> { trace!("TemplateCommand::template_file()"); @@ -194,18 +192,14 @@ impl TemplateCommand { .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}"); - match self.output.as_ref() { - Some(output) => { - debug!("Templating to file {}", output.display()); - trace!("Containerfile:\n{output_str}"); - - std::fs::write(output, output_str)?; - } - None => { - debug!("Templating to stdout"); - println!("{output_str}"); - } + std::fs::write(output, output_str)?; + } else { + debug!("Templating to stdout"); + println!("{output_str}"); } info!("Finished templating Containerfile"); @@ -213,6 +207,10 @@ impl TemplateCommand { } } +// ======================================================== // +// ========================= Helpers ====================== // +// ======================================================== // + fn print_script(script_contents: &ExportsTemplate) -> String { trace!("print_script({script_contents})"); @@ -284,17 +282,18 @@ fn get_module_from_file(file_name: &str) -> String { process::exit(1); }; - if let Ok(module_ext) = serde_yaml::from_str::(file.as_str()) { - module_ext.render().unwrap_or_else(template_err_fn) - } else { - let module = serde_yaml::from_str::(file.as_str()).unwrap_or_else(serde_err_fn); + serde_yaml::from_str::(file.as_str()).map_or_else( + |_| { + let module = serde_yaml::from_str::(file.as_str()).unwrap_or_else(serde_err_fn); - ModuleExt::builder() - .modules(vec![module]) - .build() - .render() - .unwrap_or_else(template_err_fn) - } + ModuleExt::builder() + .modules(vec![module]) + .build() + .render() + .unwrap_or_else(template_err_fn) + }, + |module_ext| module_ext.render().unwrap_or_else(template_err_fn), + ) } fn print_module_context(module: &Module) -> String { diff --git a/src/lib.rs b/src/lib.rs index 356c4e7..740a0ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,16 +1,12 @@ //! The root library for blue-build. - +#![warn(clippy::correctness, clippy::suspicious, clippy::perf, clippy::style)] #![doc( html_logo_url = "https://gitlab.com/wunker-bunker/blue-build/-/raw/main/logos/BlueBuild-logo.png" )] #![doc = include_str!("../README.md")] #![forbid(unsafe_code)] #![allow(unused_imports)] +#![allow(clippy::module_name_repetitions)] -#[cfg(feature = "init")] -pub mod init; - -pub mod build; -pub mod local; +pub mod commands; mod ops; -pub mod template; diff --git a/src/ops.rs b/src/ops.rs index e5828da..e0716ef 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -1,12 +1,6 @@ -use std::{ - env, - path::{Path, PathBuf}, - process::Command, -}; - -use anyhow::{anyhow, bail, Result}; -use clap::ValueEnum; +use anyhow::{anyhow, Result}; use log::{debug, trace}; +use std::process::Command; pub const LOCAL_BUILD: &str = "/etc/blue-build"; pub const ARCHIVE_SUFFIX: &str = ".tar.gz"; @@ -16,18 +10,17 @@ pub fn check_command_exists(command: &str) -> Result<()> { debug!("Checking if {command} exists"); trace!("which {command}"); - match Command::new("which") + if Command::new("which") .arg(command) .output()? .status .success() { - true => { - debug!("Command {command} does exist"); - Ok(()) - } - false => Err(anyhow!( + debug!("Command {command} does exist"); + Ok(()) + } else { + Err(anyhow!( "Command {command} doesn't exist and is required to build the image" - )), + )) } }