| 842 |
842 |
|
assert!(!marker.exists(), "denied build step must NOT have executed");
|
| 843 |
843 |
|
}
|
| 844 |
844 |
|
}
|
|
845 |
+ |
|
|
846 |
+ |
/// Every recipe of every configured app must parse.
|
|
847 |
+ |
///
|
|
848 |
+ |
/// A recipe is read and compiled at release time, on the build host, after the
|
|
849 |
+ |
/// checkout has already run — so a typo in one is discovered at the worst
|
|
850 |
+ |
/// possible moment. Compiling them here costs nothing and moves that discovery
|
|
851 |
+ |
/// to `cargo test`. Skips when the live config is absent (CI, another host),
|
|
852 |
+ |
/// like [`crate::topology`]'s live-config smoke test.
|
|
853 |
+ |
#[cfg(test)]
|
|
854 |
+ |
mod live_recipe_smoke {
|
|
855 |
+ |
use crate::topology::{Kind, Topology};
|
|
856 |
+ |
use std::path::Path;
|
|
857 |
+ |
|
|
858 |
+ |
#[test]
|
|
859 |
+ |
fn live_recipes_compile_if_present() {
|
|
860 |
+ |
let Some(home) = std::env::var_os("HOME") else {
|
|
861 |
+ |
return;
|
|
862 |
+ |
};
|
|
863 |
+ |
let path = Path::new(&home).join(".config/bento/bento.toml");
|
|
864 |
+ |
if !path.exists() {
|
|
865 |
+ |
return;
|
|
866 |
+ |
}
|
|
867 |
+ |
let topo = Topology::load(&path).expect("live bento.toml must load");
|
|
868 |
+ |
// Syntax only: the host functions are bound per run against a live
|
|
869 |
+ |
// context, and Rhai resolves calls at eval time regardless.
|
|
870 |
+ |
let engine = rhai::Engine::new();
|
|
871 |
+ |
let mut checked = 0;
|
|
872 |
+ |
for (name, cfg) in &topo.app {
|
|
873 |
+ |
let dir = crate::engine::expand_tilde(&cfg.repo).join(&cfg.recipe_dir);
|
|
874 |
+ |
let files: Vec<String> = match cfg.kind {
|
|
875 |
+ |
Kind::Library => vec!["publish.rhai".into()],
|
|
876 |
+ |
Kind::App => cfg
|
|
877 |
+ |
.targets
|
|
878 |
+ |
.iter()
|
|
879 |
+ |
.map(|t| format!("{}.rhai", t.platform.as_str()))
|
|
880 |
+ |
.collect(),
|
|
881 |
+ |
};
|
|
882 |
+ |
for file in files {
|
|
883 |
+ |
let p = dir.join(&file);
|
|
884 |
+ |
// An app can ship a target whose recipe is still pending (BB's
|
|
885 |
+ |
// macOS/iOS); a missing file is that, not a parse failure.
|
|
886 |
+ |
let Ok(src) = std::fs::read_to_string(&p) else {
|
|
887 |
+ |
continue;
|
|
888 |
+ |
};
|
|
889 |
+ |
engine
|
|
890 |
+ |
.compile(&src)
|
|
891 |
+ |
.unwrap_or_else(|e| panic!("recipe {name}/{file} does not parse: {e}"));
|
|
892 |
+ |
checked += 1;
|
|
893 |
+ |
}
|
|
894 |
+ |
}
|
|
895 |
+ |
assert!(checked > 0, "live config resolved no readable recipes");
|
|
896 |
+ |
}
|
|
897 |
+ |
}
|