use crate::exec::ScanPolicy;
use crate::paths::concat_paths;
use std::io::BufRead;
pub struct Config {
pub home: String,
pub tracked_file: String,
pub tracked_enc_file: String,
pub bootstrap_dir: String,
pub ssh_key_path: String,
pub age_pass: String,
pub repo_path: String,
pub repo_url: String,
pub pre_sync_hook: String,
pub post_sync_hook: String,
pub secret_scan: String,
}
fn clean_yaml_val(val: &str, home: &str) -> String {
let mut cleaned = val.trim().to_string();
if cleaned.starts_with('"') && cleaned.ends_with('"') {
cleaned = cleaned[1..cleaned.len() - 1].to_string();
} else if cleaned.starts_with('\'') && cleaned.ends_with('\'') {
cleaned = cleaned[1..cleaned.len() - 1].to_string();
}
if cleaned.starts_with('~') {
cleaned = cleaned.replacen('~', home, 1);
}
cleaned
}
impl Config {
pub fn load() -> Self {
let home = std::env::var("HOME").unwrap_or_default();
let mut tracked_file = concat_paths(&home, ".config/fp-dotfiles-manager/tracked");
let mut tracked_enc_file =
concat_paths(&home, ".config/fp-dotfiles-manager/tracked_encrypted");
let mut bootstrap_dir = concat_paths(&home, ".config/fp-dotfiles-manager/bootstrap.d");
let mut ssh_key_path = concat_paths(&home, ".config/fp-dotfiles-manager/ssh_gitlab");
let mut age_pass = String::new();
let mut repo_path = "fptbb/dotfiles".to_string();
let mut repo_url = "git@gitlab.com:fptbb/dotfiles.git".to_string();
let mut pre_sync_hook =
concat_paths(&home, ".config/fp-dotfiles-manager/hooks/pre-sync.sh");
let mut post_sync_hook =
concat_paths(&home, ".config/fp-dotfiles-manager/hooks/post-sync.sh");
let mut secret_scan = "enforce".to_string();
let config_file_path = concat_paths(&home, ".config/fp-dotfiles-manager/config.yml");
if let Ok(file) = std::fs::File::open(&config_file_path) {
let reader = std::io::BufReader::new(file);
for line in reader.lines().flatten() {
let trimmed = line.trim();
if trimmed.is_empty() || trimmed.starts_with('#') {
continue;
}
if let Some(idx) = trimmed.find(':') {
let key = trimmed[..idx].trim();
let val = &trimmed[idx + 1..];
match key {
"tracked_file" => tracked_file = clean_yaml_val(val, &home),
"tracked_enc_file" => tracked_enc_file = clean_yaml_val(val, &home),
"bootstrap_dir" => bootstrap_dir = clean_yaml_val(val, &home),
"ssh_key_path" => ssh_key_path = clean_yaml_val(val, &home),
"age_pass" => age_pass = clean_yaml_val(val, &home),
"repo_path" => {
repo_path = clean_yaml_val(val, &home);
repo_url = "git@gitlab.com:".to_owned() + &repo_path + ".git";
}
"repo_url" => repo_url = clean_yaml_val(val, &home),
"pre_sync_hook" => pre_sync_hook = clean_yaml_val(val, &home),
"post_sync_hook" => post_sync_hook = clean_yaml_val(val, &home),
"secret_scan" => {
secret_scan = if ScanPolicy::parse(val).is_some() {
clean_yaml_val(val, &home)
} else {
eprintln!(
"Warning: ignoring invalid secret_scan value {:?} (expected off, warn, or enforce)",
val.trim()
);
secret_scan
};
}
_ => {}
}
}
}
}
if let Ok(val) = std::env::var("DOTFILES_TRACKED") {
tracked_file = clean_yaml_val(&val, &home);
}
if let Ok(val) = std::env::var("DOTFILES_TRACKED_ENC") {
tracked_enc_file = clean_yaml_val(&val, &home);
}
if let Ok(val) = std::env::var("DOTFILES_BOOTSTRAP_DIR") {
bootstrap_dir = clean_yaml_val(&val, &home);
}
if let Ok(val) = std::env::var("DOTFILES_SSH_KEY") {
ssh_key_path = clean_yaml_val(&val, &home);
}
if let Ok(val) = std::env::var("DOTFILES_AGE_PASS") {
age_pass = val;
}
if let Ok(val) = std::env::var("DOTFILES_REPO_PATH") {
repo_path = val;
repo_url = "git@gitlab.com:".to_owned() + &repo_path + ".git";
}
if let Ok(val) = std::env::var("DOTFILES_REPO_URL") {
repo_url = clean_yaml_val(&val, &home);
}
if let Ok(val) = std::env::var("DOTFILES_PRE_SYNC") {
pre_sync_hook = clean_yaml_val(&val, &home);
}
if let Ok(val) = std::env::var("DOTFILES_POST_SYNC") {
post_sync_hook = clean_yaml_val(&val, &home);
}
if let Ok(val) = std::env::var("DOTFILES_SECRET_SCAN") {
secret_scan = if ScanPolicy::parse(&val).is_some() {
val
} else {
eprintln!(
"Warning: ignoring invalid DOTFILES_SECRET_SCAN value {:?} (expected off, warn, or enforce)",
val
);
secret_scan
};
}
Self {
home,
tracked_file,
tracked_enc_file,
bootstrap_dir,
ssh_key_path,
age_pass,
repo_path,
repo_url,
pre_sync_hook,
post_sync_hook,
secret_scan,
}
}
pub fn scan_policy(&self) -> ScanPolicy {
ScanPolicy::parse(&self.secret_scan).unwrap_or(ScanPolicy::Enforce)
}
}