ntu/src/config.rs
dschlueter bd82fd7b30 fix: Cargo.lock tracken, verbose durchreichen, Config-Fehler melden, Platzhalter-Kollision beheben
- Cargo.lock aus .gitignore entfernt (Rust-Konvention: für Binaries committen)
- verbose-Parameter in clean_filename() wird jetzt korrekt von args.verbose
  durchgereicht statt hardcoded false
- Config::load() gibt bei Parse-Fehlern eine Warnung aus statt den Fehler
  still zu schlucken
- Platzhalter für C++/C# von CPLUSPLUS/CSHARP zu NTUxCPLUSPLUSx/NTUxCSHARPx
  geändert um Kollisionen mit echten Dateinamen zu vermeiden

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 04:32:59 +01:00

166 lines
6.1 KiB
Rust

use anyhow::{Context, Result};
use log::{debug, info, warn};
use serde::Deserialize;
use std::collections::HashMap;
use std::fs;
use std::path::Path;
/// Repräsentiert die Konfiguration, die sich aus einer TOML-Datei laden lässt.
#[derive(Deserialize, Default, Debug, Clone)]
#[serde(default)]
pub struct Config {
/// Individuelle Ersetzungen, z. B. "foo" => "bar"
pub replacements: HashMap<String, String>,
}
impl Config {
/// Liest eine TOML-Konfigurationsdatei ein, wenn sie existiert.
fn load_internal(path: &Path, verbose: bool) -> Result<Self> {
if path.exists() {
if verbose {
debug!("Lade Konfigurationsdatei: {}", path.display());
}
let content = fs::read_to_string(path).with_context(|| {
format!("Konnte Konfigurationsdatei nicht lesen: {}", path.display())
})?;
let loaded: Self = toml::from_str(&content).with_context(|| {
format!(
"Konnte Konfigurationsdatei nicht parsen: {}",
path.display()
)
})?;
if verbose && !loaded.replacements.is_empty() {
debug!("Eingelesene Replacements:");
for (k, v) in &loaded.replacements {
debug!(" {:?} => {:?}", k, v);
}
}
Ok(loaded)
} else {
Err(anyhow::anyhow!("Datei existiert nicht: {}", path.display()))
}
}
/// Öffentliche Methode zum Laden einer Konfiguration aus einem Pfad.
/// Gibt Standardwerte zurück wenn die Datei nicht existiert,
/// propagiert aber Parse-Fehler als Warnung.
pub fn load(path: &str, verbose: bool) -> Result<Self> {
let cfg_path = Path::new(path);
if !cfg_path.exists() {
if verbose {
info!(
"Keine Konfigurationsdatei '{}' gefunden. Verwende Standardwerte.",
path
);
}
return Ok(Self::default());
}
match Self::load_internal(cfg_path, verbose) {
Ok(config) => Ok(config),
Err(e) => {
warn!(
"Fehler beim Laden der Konfigurationsdatei '{}': {}. Verwende Standardwerte.",
path, e
);
Ok(Self::default())
}
}
}
/// Lädt Konfiguration aus spezifischer Datei (fehlschlägt bei nicht-existierender Datei)
pub fn from_file(path: &Path, verbose: bool) -> Result<Self> {
if !path.exists() {
return Err(anyhow::anyhow!(
"Konfigurationsdatei nicht gefunden: {}",
path.display()
));
}
Self::load_internal(path, verbose)
}
/// Sucht nach Konfigurationsdateien in verschiedenen Orten und kombiniert sie
pub fn from_default_locations(verbose: bool) -> Result<Self> {
// Prioritätenreihenfolge (später überschreibt früher):
// 1. Standard etc-Verzeichnis (/etc/NameToUnix/config.toml)
// 2. Benutzerverzeichnis (~/.config/NameToUnix/config.toml)
// 3. Arbeitsverzeichnis (./.NameToUnix.conf)
// Die Ladereihenfolge ist so gewählt, dass lokale Einstellungen Vorrang vor
// Benutzereinstellungen haben und diese wiederum Vorrang vor Systemeinstellungen.
// Wir beginnen mit einer leeren Konfiguration
let mut config = Self::default();
let mut config_found = false;
// Standard etc-Verzeichnis
let etc_config = Path::new("/etc/NameToUnix/config.toml");
if etc_config.exists() {
if verbose {
debug!("Lade System-Konfiguration: {}", etc_config.display());
}
if let Ok(etc_conf) = Self::load(etc_config.to_str().unwrap_or_default(), verbose) {
// Füge die Werte zur Konfiguration hinzu
config.replacements.extend(etc_conf.replacements);
config_found = true;
}
} else if verbose {
debug!(
"System-Konfiguration nicht gefunden: {}",
etc_config.display()
);
}
// Benutzerverzeichnis
if let Some(home) = dirs::home_dir() {
let user_config = home.join(".config/NameToUnix/config.toml");
if user_config.exists() {
if verbose {
debug!("Lade Benutzer-Konfiguration: {}", user_config.display());
}
if let Ok(user_conf) = Self::load(user_config.to_str().unwrap_or_default(), verbose)
{
// Überschreibe/ergänze mit Benutzerkonfiguration
config.replacements.extend(user_conf.replacements);
config_found = true;
}
} else if verbose {
debug!(
"Benutzer-Konfiguration nicht gefunden: {}",
user_config.display()
);
}
}
// Arbeitsverzeichnis (höchste Priorität)
let local_config = Path::new(".NameToUnix.conf");
if local_config.exists() {
if verbose {
debug!("Lade lokale Konfiguration: {}", local_config.display());
}
if let Ok(local_conf) = Self::load(local_config.to_str().unwrap_or_default(), verbose) {
// Überschreibe/ergänze mit lokaler Konfiguration
config.replacements.extend(local_conf.replacements);
config_found = true;
}
} else if verbose {
debug!(
"Lokale Konfiguration nicht gefunden: {}",
local_config.display()
);
}
// Gib die kombinierte Konfiguration zurück
if config_found {
if verbose && !config.replacements.is_empty() {
info!(
"Kombinierte Konfiguration enthält {} Ersetzungen",
config.replacements.len()
);
}
} else if verbose {
info!("Keine Konfigurationsdateien gefunden. Verwende nur die Standardwerte.");
}
Ok(config)
}
}