use std::env;
use std::fs;
use std::path::PathBuf;
pub struct Config;
impl Config {
pub const PKG_VERSION: &'static str = env!("CARGO_PKG_VERSION");
pub fn data_dir() -> PathBuf {
if let Ok(test_dir) = env::var("GEIST_SUPERVISOR_DATA_DIR_TEST") {
return PathBuf::from(test_dir);
}
let home = env::var("HOME").unwrap_or_else(|_| "/tmp".to_string());
let dir = PathBuf::from(home).join(".local/share/geist-supervisor");
if let Err(e) = fs::create_dir_all(&dir) {
tracing::warn!("Failed to create data directory {}: {}", dir.display(), e);
}
dir
}
pub fn install_path() -> PathBuf {
if let Ok(test_dir) = env::var("GEIST_INSTALL_PATH_TEST") {
return PathBuf::from(test_dir);
}
let home = env::var("HOME").unwrap_or_else(|_| "/tmp".to_string());
PathBuf::from(home).join(".local/share/geist-supervisor")
}
pub fn normalize_version(version: &str) -> String {
version.trim_start_matches('v').to_string()
}
pub fn format_version(version: &str) -> String {
if version.starts_with('v') {
version.to_string()
} else {
format!("v{}", version)
}
}
pub fn get_current_version() -> String {
if let Ok(version) = env::var("GEIST_CURRENT_VERSION") {
return version;
}
Self::read_version_from_paths(&Self::install_path(), &Self::data_dir())
}
fn read_version_from_paths(
install_path: &std::path::Path,
data_dir: &std::path::Path,
) -> String {
let metadata_path = install_path.join("ota_metadata.json");
if let Ok(content) = fs::read_to_string(metadata_path) {
if let Ok(json) = serde_json::from_str::<serde_json::Value>(&content) {
if let Some(version) = json["version"].as_str() {
return Self::format_version(version);
}
}
}
let legacy_file = data_dir.join("current_version");
if let Ok(version) = fs::read_to_string(legacy_file) {
let v = version.trim();
if !v.is_empty() {
return v.to_string();
}
}
format!("v{}", Self::PKG_VERSION)
}
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::tempdir;
#[test]
fn test_normalize_version() {
assert_eq!(Config::normalize_version("v1.2.3"), "1.2.3");
assert_eq!(Config::normalize_version("1.2.3"), "1.2.3");
assert_eq!(Config::normalize_version("v0.1.0-alpha"), "0.1.0-alpha");
assert_eq!(Config::normalize_version(""), "");
}
#[test]
fn test_format_version() {
assert_eq!(Config::format_version("1.2.3"), "v1.2.3");
assert_eq!(Config::format_version("v1.2.3"), "v1.2.3");
assert_eq!(Config::format_version("0.1.0-alpha"), "v0.1.0-alpha");
assert_eq!(Config::format_version("v0.1.0-alpha"), "v0.1.0-alpha");
assert_eq!(Config::format_version(""), "v");
}
#[test]
fn test_get_version_from_metadata() {
let temp_dir = tempdir().unwrap();
let install_dir = temp_dir.path().join("install");
let data_dir = temp_dir.path().join("data");
std::fs::create_dir_all(&install_dir).unwrap();
std::fs::create_dir_all(&data_dir).unwrap();
let metadata = r#"{"version": "1.2.3"}"#;
std::fs::write(install_dir.join("ota_metadata.json"), metadata).unwrap();
let version = Config::read_version_from_paths(&install_dir, &data_dir);
assert_eq!(version, "v1.2.3");
}
#[test]
fn test_get_version_env_override() {
std::env::set_var("GEIST_CURRENT_VERSION", "v9.9.9");
let version = Config::get_current_version();
assert_eq!(version, "v9.9.9");
std::env::remove_var("GEIST_CURRENT_VERSION");
}
#[test]
fn test_get_version_fallback_pkg_version() {
let temp_dir = tempdir().unwrap();
let install_dir = temp_dir.path().join("install");
let data_dir = temp_dir.path().join("data");
std::fs::create_dir_all(&install_dir).unwrap();
std::fs::create_dir_all(&data_dir).unwrap();
let version = Config::read_version_from_paths(&install_dir, &data_dir);
assert_eq!(version, format!("v{}", Config::PKG_VERSION));
}
#[test]
fn test_get_version_legacy_file() {
let temp_dir = tempdir().unwrap();
let install_dir = temp_dir.path().join("install");
let data_dir = temp_dir.path().join("data");
std::fs::create_dir_all(&install_dir).unwrap();
std::fs::create_dir_all(&data_dir).unwrap();
std::fs::write(data_dir.join("current_version"), "v2.0.0").unwrap();
let version = Config::read_version_from_paths(&install_dir, &data_dir);
assert_eq!(version, "v2.0.0");
}
}