diff --git a/Cargo.lock b/Cargo.lock index 70ee68c..7318458 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -596,6 +596,7 @@ dependencies = [ "sys-info", "tempfile", "toml", + "which", ] [[package]] @@ -604,6 +605,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + [[package]] name = "encode_unicode" version = "0.3.6" @@ -2957,6 +2964,19 @@ version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" +[[package]] +name = "which" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bf3ea8596f3a0dd5980b46430f2058dfe2c36a27ccfbb1845d6fbfcd9ba6e14" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 6a89234..ce1f849 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ serde_json = "1.0.111" sys-info = "0.9.1" tempfile = "3.9.0" toml = "0.8.8" +which = "5.0.0" # The profile that 'cargo dist' will build with [profile.dist] diff --git a/silo/README.md b/silo/README.md new file mode 100644 index 0000000..e69de29 diff --git a/src/main.rs b/src/main.rs index 34fc213..58bd0db 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,7 +44,7 @@ fn init_logging(verbose: bool) { builder .filter_module("handlebars", log::LevelFilter::Error) .filter_module("rustls", log::LevelFilter::Error) - .filter_module("", log::LevelFilter::Error) + .filter_module("reqwest", log::LevelFilter::Error) .init(); } diff --git a/src/templating/helpers.rs b/src/templating/helpers.rs new file mode 100644 index 0000000..d8c041e --- /dev/null +++ b/src/templating/helpers.rs @@ -0,0 +1,44 @@ +use handlebars::{ + Context, Handlebars, Helper, HelperDef, HelperResult, Output, RenderContext, RenderError, + RenderErrorReason, Renderable, +}; +use which::which; + +pub struct IfInstalledHelper { + pub positive: bool, +} + +impl HelperDef for IfInstalledHelper { + fn call<'reg: 'rc, 'rc>( + &self, + h: &Helper<'rc>, + r: &'reg Handlebars<'reg>, + ctx: &'rc Context, + rc: &mut RenderContext<'reg, 'rc>, + out: &mut dyn Output, + ) -> HelperResult { + let bin = h + .param(0) + .ok_or_else(|| RenderErrorReason::ParamNotFoundForIndex("if-installed", 0))?; + let bin = if bin.is_value_missing() { + bin.relative_path() + .ok_or_else(|| RenderErrorReason::ParamNotFoundForIndex("if-installed", 0))? + .to_owned() + } else { + bin.value().to_string() + }; + log::debug!("Checking if `{bin}` is installed"); + + if which(&bin).is_ok() == self.positive { + log::debug!("`{bin}` is installed"); + h.template() + .ok_or_else(|| RenderErrorReason::BlockContentRequired)? + .render(r, ctx, rc, out) + .map_err(RenderError::from) + .into() + } else { + log::debug!("`{bin}` is not installed"); + HelperResult::Ok(()) + } + } +} diff --git a/src/templating.rs b/src/templating/mod.rs similarity index 91% rename from src/templating.rs rename to src/templating/mod.rs index b7d7ecc..0f3d83a 100644 --- a/src/templating.rs +++ b/src/templating/mod.rs @@ -5,6 +5,7 @@ use handlebars_switch::SwitchHelper; use lazy_static::lazy_static; use miette::{Context, IntoDiagnostic, Result}; use serde::Serialize; +mod helpers; pub fn render(template: &str, ctx: T) -> Result { engine() @@ -16,6 +17,14 @@ pub fn render(template: &str, ctx: T) -> Result { fn engine<'a>() -> Handlebars<'a> { let mut hb = Handlebars::new(); hb.register_helper("switch", Box::new(SwitchHelper)); + hb.register_helper( + "if-installed", + Box::new(helpers::IfInstalledHelper { positive: true }), + ); + hb.register_helper( + "if-not-installed", + Box::new(helpers::IfInstalledHelper { positive: false }), + ); hb }