1+ #!/usr/bin/env python3
2+ """
3+ Configuration management for archpkg-helper
4+ """
5+
6+ import json
7+ import os
8+ from pathlib import Path
9+ from typing import Dict , Any , Optional
10+ from dataclasses import dataclass , asdict
11+ from archpkg .logging_config import get_logger
12+
13+ logger = get_logger (__name__ )
14+
15+ @dataclass
16+ class UserConfig :
17+ """User configuration settings"""
18+ auto_update_enabled : bool = False
19+ auto_update_mode : str = "manual" # "automatic" or "manual"
20+ update_check_interval_hours : int = 24
21+ background_download_enabled : bool = True
22+ notification_enabled : bool = True
23+
24+ class ConfigManager :
25+ """Manages user configuration with atomic file operations"""
26+
27+ def __init__ (self ):
28+ self .config_dir = Path .home () / ".archpkg"
29+ self .config_file = self .config_dir / "config.json"
30+ self ._ensure_config_dir ()
31+
32+ def _ensure_config_dir (self ) -> None :
33+ """Ensure configuration directory exists"""
34+ self .config_dir .mkdir (parents = True , exist_ok = True )
35+
36+ def _atomic_write (self , data : Dict [str , Any ]) -> None :
37+ """Atomically write configuration to file"""
38+ temp_file = self .config_file .with_suffix ('.tmp' )
39+
40+ try :
41+ # Write to temporary file first
42+ with open (temp_file , 'w' , encoding = 'utf-8' ) as f :
43+ json .dump (data , f , indent = 2 , ensure_ascii = False )
44+
45+ # Atomic move to final location
46+ temp_file .replace (self .config_file )
47+ logger .info (f"Configuration saved to { self .config_file } " )
48+
49+ except Exception as e :
50+ # Clean up temp file on error
51+ if temp_file .exists ():
52+ temp_file .unlink ()
53+ logger .error (f"Failed to save configuration: { e } " )
54+ raise
55+
56+ def load_config (self ) -> UserConfig :
57+ """Load configuration from file"""
58+ if not self .config_file .exists ():
59+ logger .info ("No configuration file found, using defaults" )
60+ return UserConfig ()
61+
62+ try :
63+ with open (self .config_file , 'r' , encoding = 'utf-8' ) as f :
64+ data = json .load (f )
65+
66+ # Create config object from loaded data
67+ config = UserConfig ()
68+ for key , value in data .items ():
69+ if hasattr (config , key ):
70+ setattr (config , key , value )
71+
72+ logger .info ("Configuration loaded successfully" )
73+ return config
74+
75+ except Exception as e :
76+ logger .warning (f"Failed to load configuration, using defaults: { e } " )
77+ return UserConfig ()
78+
79+ def save_config (self , config : UserConfig ) -> None :
80+ """Save configuration to file atomically"""
81+ data = asdict (config )
82+ self ._atomic_write (data )
83+
84+ def get_config_value (self , key : str ) -> Any :
85+ """Get a specific configuration value"""
86+ config = self .load_config ()
87+ return getattr (config , key , None )
88+
89+ def set_config_value (self , key : str , value : Any ) -> None :
90+ """Set a specific configuration value"""
91+ config = self .load_config ()
92+ if hasattr (config , key ):
93+ setattr (config , key , value )
94+ self .save_config (config )
95+ logger .info (f"Configuration updated: { key } = { value } " )
96+ else :
97+ raise ValueError (f"Unknown configuration key: { key } " )
98+
99+ def show_config (self ) -> str :
100+ """Get formatted configuration display"""
101+ config = self .load_config ()
102+ lines = [
103+ f"Configuration file: { self .config_file } " ,
104+ "" ,
105+ "Current settings:" ,
106+ f" Auto-update enabled: { config .auto_update_enabled } " ,
107+ f" Auto-update mode: { config .auto_update_mode } " ,
108+ f" Update check interval: { config .update_check_interval_hours } hours" ,
109+ f" Background download: { config .background_download_enabled } " ,
110+ f" Notifications: { config .notification_enabled } " ,
111+ ]
112+ return "\n " .join (lines )
113+
114+ # Global configuration manager instance
115+ config_manager = ConfigManager ()
116+
117+ def get_user_config () -> UserConfig :
118+ """Get current user configuration"""
119+ return config_manager .load_config ()
120+
121+ def save_user_config (config : UserConfig ) -> None :
122+ """Save user configuration"""
123+ config_manager .save_config (config )
124+
125+ def set_config_option (key : str , value : Any ) -> None :
126+ """Set a configuration option"""
127+ config_manager .set_config_value (key , value )
128+
129+ def get_config_option (key : str ) -> Any :
130+ """Get a configuration option"""
131+ return config_manager .get_config_value (key )
132+
133+ def show_current_config () -> str :
134+ """Show current configuration"""
135+ return config_manager .show_config ()
0 commit comments