From 7ca9434ea57310056eefef8d1b88f58d77be939d Mon Sep 17 00:00:00 2001 From: dawn Date: Tue, 8 Sep 2026 02:54:02 +0900 Subject: [PATCH] bobbin: warn on unknown environment vars Signed-off-by: dawn --- bobbin/crates/bobbin/src/config.rs | 33 ++++++++++++++++-------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/bobbin/crates/bobbin/src/config.rs b/bobbin/crates/bobbin/src/config.rs index 137eff337..6ba0fb79b 100644 --- a/bobbin/crates/bobbin/src/config.rs +++ b/bobbin/crates/bobbin/src/config.rs @@ -299,7 +299,7 @@ impl std::str::FromStr for LogFormat { } pub fn load(path: Option<&PathBuf>) -> anyhow::Result { - check_envs(std::env::vars().map(|(k, _)| k))?; + check_envs(std::env::vars().map(|(k, _)| k)); if let Some(p) = path { check_keys(p)?; } @@ -347,27 +347,28 @@ fn check_keys(path: &Path) -> anyhow::Result<()> { } } -fn check_envs(iter: I) -> anyhow::Result<()> +fn check_envs(iter: I) -> Vec where I: IntoIterator, S: AsRef, { let known: HashSet<&str> = KNOWN_ENVS.iter().copied().collect(); - let unknown: Vec = iter + let mut unknown: Vec = iter .into_iter() .filter_map(|var| { let var = var.as_ref(); (var.starts_with(ENV_PREFIX) && !known.contains(var)).then(|| var.to_owned()) }) .collect(); - if unknown.is_empty() { - Ok(()) - } else { - Err(anyhow!( - "unknown {ENV_PREFIX}* environment variables: {}\nrun `bobbin config-template` for the canonical schema", + unknown.sort(); + unknown.dedup(); + if !unknown.is_empty() { + eprintln!( + "warning: unknown {ENV_PREFIX}* environment variables: {}\nrun `bobbin config-template` for the canonical schema", unknown.join(", "), - )) + ); } + unknown } fn collect_paths(value: &toml::Value, prefix: &str) -> Vec { @@ -516,7 +517,7 @@ mod tests { let missing: Vec<&&str> = declared.difference(&known).collect(); assert!( missing.is_empty(), - "confique reads {missing:?} but check_envs will refuse to start with them set. Add them to KNOWN_ENVS" + "confique reads {missing:?} but KNOWN_ENVS does not list them. Add them to KNOWN_ENVS" ); let stale: Vec<&&str> = known.difference(&declared).collect(); assert!( @@ -526,18 +527,20 @@ mod tests { } #[test] - fn unknown_bobbin_env_rejected() { - let err = check_envs(["BOBBIN_BIDNS"]).expect_err("typo must surface"); - assert!(err.to_string().contains("BOBBIN_BIDNS"), "got {err}"); + fn unknown_bobbin_env_warns() { + let unknown = check_envs(["BOBBIN_BIDNS"]); + assert_eq!(unknown, vec!["BOBBIN_BIDNS"]); } #[test] fn known_bobbin_env_passes() { - check_envs(["BOBBIN_BIND", "BOBBIN_LOG"]).expect("known names must pass"); + let unknown = check_envs(["BOBBIN_BIND", "BOBBIN_LOG"]); + assert!(unknown.is_empty()); } #[test] fn non_bobbin_env_ignored() { - check_envs(["PATH", "HOME", "RUST_LOG"]).expect("only BOBBIN_* names are validated"); + let unknown = check_envs(["PATH", "HOME", "RUST_LOG"]); + assert!(unknown.is_empty()); } } -- 2.51.2