xbp 10.15.4

XBP is a zero-config build pack that can also interact with proxies, kafka, sockets, synthetic monitors.
Documentation
use crate::commands::service;
use std::collections::HashSet;
use std::env;
use std::path::Path;

use super::scanner;

/// Verify that all discovered and configured env vars are present locally.
pub async fn verify_envs(project_root: &Path) -> Result<(), String> {
    let mut required = scanner::get_required_env_vars(project_root)?;

    let (_, config) = service::load_xbp_config_with_root().await?;
    if let Some(env_map) = config.environment {
        for key in env_map.keys() {
            required.insert(key.clone());
        }
    }
    if let Some(services) = config.services {
        for service in services {
            if let Some(env_map) = service.environment {
                for key in env_map.keys() {
                    required.insert(key.clone());
                }
            }
        }
    }

    let mut available: HashSet<String> = env::vars().map(|(k, _)| k).collect();
    for candidate in &[".env.local", ".env"] {
        let path = project_root.join(candidate);
        if path.exists() {
            let parsed = super::parse_env_file(&path)?;
            available.extend(parsed.keys().cloned());
        }
    }

    let missing: Vec<String> = required
        .into_iter()
        .filter(|key| !available.contains(key))
        .collect();

    if missing.is_empty() {
        println!(
            "✅ All required env vars are present ({} total).",
            available.len()
        );
        return Ok(());
    }

    println!("❌ Missing {} environment variable(s):", missing.len());
    for key in &missing {
        println!("  {}", key);
    }

    Err(format!(
        "Missing {} environment variable(s).",
        missing.len()
    ))
}