use std::collections::HashMap;
use std::env;
use std::path::Path;
#[derive(Debug, Clone, PartialEq)]
pub enum EnvSource {
System,
DotEnv,
NotFound,
}
pub struct EnvTracker {
pre_dotenv_vars: HashMap<String, String>,
dotenv_loaded: bool,
}
impl EnvTracker {
pub fn new() -> Self {
let pre_dotenv_vars = env::vars().collect();
Self {
pre_dotenv_vars,
dotenv_loaded: false,
}
}
pub fn load_dotenv_override(&mut self) -> Result<(), dotenvy::Error> {
if Path::new(".env").exists() {
dotenvy::from_filename_override(".env")?;
self.dotenv_loaded = true;
crate::log_debug!("Loaded .env file with override - tracking enabled");
}
if std::env::var("OPENROUTER_APP_TITLE").is_err() {
std::env::set_var("OPENROUTER_APP_TITLE", "Octomind");
}
if std::env::var("OPENROUTER_HTTP_REFERER").is_err() {
std::env::set_var("OPENROUTER_HTTP_REFERER", "https://octomind.run");
}
Ok(())
}
pub fn get_source(&self, var_name: &str) -> EnvSource {
match env::var(var_name) {
Ok(current_value) => {
if current_value.trim().is_empty() {
return EnvSource::NotFound;
}
if !self.dotenv_loaded {
return EnvSource::System;
}
match self.pre_dotenv_vars.get(var_name) {
Some(pre_value) => {
if current_value == *pre_value {
EnvSource::System
} else {
EnvSource::DotEnv
}
}
None => {
EnvSource::DotEnv
}
}
}
Err(_) => EnvSource::NotFound,
}
}
pub fn get_source_description(&self, var_name: &str) -> &'static str {
match self.get_source(var_name) {
EnvSource::System => "environment variable",
EnvSource::DotEnv => "environment/.env file",
EnvSource::NotFound => "not set",
}
}
pub fn is_dotenv_loaded(&self) -> bool {
self.dotenv_loaded
}
}
impl Default for EnvTracker {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::env;
#[test]
fn test_env_tracker_new() {
let tracker = EnvTracker::new();
assert!(!tracker.pre_dotenv_vars.is_empty());
assert!(!tracker.dotenv_loaded);
}
#[test]
fn test_source_detection_system_only() {
env::set_var("TEST_SYSTEM_VAR", "system_value");
let tracker = EnvTracker::new();
assert_eq!(tracker.get_source("TEST_SYSTEM_VAR"), EnvSource::System);
assert_eq!(
tracker.get_source_description("TEST_SYSTEM_VAR"),
"environment variable"
);
env::remove_var("TEST_SYSTEM_VAR");
}
#[test]
fn test_source_detection_not_found() {
let tracker = EnvTracker::new();
assert_eq!(tracker.get_source("NONEXISTENT_VAR"), EnvSource::NotFound);
assert_eq!(tracker.get_source_description("NONEXISTENT_VAR"), "not set");
}
}