macro_rules! cli_features {
($($name:literal),+ $(,)?) => {
#[cfg(test)]
pub const ALL: &[&str] = &[$($name),+];
pub const ENABLED: &[&str] = &[
$(
#[cfg(feature = $name)]
$name,
)+
];
};
}
cli_features! {
"cef",
"daachorse-index",
"daemon",
"daemon-nats",
"daemon-otlp",
"daemon-tls",
"evtx",
"hunt-postgres",
"logfmt",
"mcp",
"stix-enrich",
"taxii-sync",
}
pub fn print_enabled() {
for name in ENABLED {
println!("{name}");
}
}
pub fn help_footer() -> &'static str {
static FOOTER: std::sync::OnceLock<&'static str> = std::sync::OnceLock::new();
FOOTER.get_or_init(|| leak(format!("Compiled-in features: {}", format_enabled())))
}
pub fn long_version() -> &'static str {
static VERSION: std::sync::OnceLock<&'static str> = std::sync::OnceLock::new();
VERSION.get_or_init(|| {
leak(format!(
"{}\nfeatures: {}",
env!("CARGO_PKG_VERSION"),
format_enabled(),
))
})
}
fn leak(s: String) -> &'static str {
Box::leak(s.into_boxed_str())
}
fn format_enabled() -> String {
ENABLED.join(", ")
}
pub fn requested(args: impl IntoIterator<Item = impl AsRef<str>>) -> bool {
let mut has_features = false;
for arg in args {
let arg = arg.as_ref();
if arg == "--features" {
has_features = true;
continue;
}
if arg == "--" || !arg.starts_with('-') {
return false;
}
}
has_features
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn catalogues_are_sorted() {
let mut all = ALL.to_vec();
all.sort_unstable();
assert_eq!(ALL, all.as_slice());
let mut enabled = ENABLED.to_vec();
enabled.sort_unstable();
assert_eq!(ENABLED, enabled.as_slice());
}
#[test]
fn enabled_is_a_subset_of_all() {
for name in ENABLED {
assert!(ALL.contains(name), "unknown feature {name}");
}
}
#[test]
fn daemon_tracks_the_cfg() {
assert_eq!(ENABLED.contains(&"daemon"), cfg!(feature = "daemon"));
}
#[test]
fn format_enabled_joins_enabled_names() {
assert_eq!(format_enabled(), ENABLED.join(", "));
}
#[test]
fn long_version_starts_with_the_crate_version() {
let version = long_version();
assert!(version.starts_with(env!("CARGO_PKG_VERSION")), "{version}");
assert!(version.contains("features:"));
}
#[test]
fn requested_is_true_only_without_a_subcommand() {
assert!(requested(["--features"]));
assert!(requested(["--quiet", "--features"]));
assert!(!requested(["--features", "engine"]));
assert!(!requested(["engine", "eval", "--features"]));
assert!(!requested(["--help"]));
assert!(!requested(Vec::<&str>::new()));
}
}