@@ -13,7 +13,7 @@ use chess_tui::ui::tui::Tui;
1313use clap:: Parser ;
1414use log:: LevelFilter ;
1515use std:: fs:: { self , File } ;
16- use std:: io:: Write ;
16+ use std:: io:: { self , Write } ;
1717use std:: panic;
1818use std:: path:: Path ;
1919
@@ -312,13 +312,31 @@ fn main() -> AppResult<()> {
312312 Ok ( ( ) )
313313}
314314
315- fn config_create ( args : & Args , folder_path : & Path , config_path : & Path ) -> AppResult < ( ) > {
316- std:: fs:: create_dir_all ( folder_path) ?;
315+ /// Checks if an IO error indicates a read-only filesystem or permission issue.
316+ /// This handles both EROFS (error code 30) and permission denied errors.
317+ fn is_readonly_error ( e : & io:: Error ) -> bool {
318+ // EROFS = 30 on Unix systems (Read-only file system)
319+ e. raw_os_error ( ) == Some ( 30 ) || e. kind ( ) == io:: ErrorKind :: PermissionDenied
320+ }
317321
318- if !config_path. exists ( ) {
319- //write to console
320- File :: create ( config_path) ?;
322+ /// Handles config file write errors gracefully, printing appropriate warnings.
323+ /// This allows the application to work with read-only config files (e.g., from NixOS/home-manager).
324+ fn handle_config_write_error ( e : io:: Error , config_path : & Path ) {
325+ if is_readonly_error ( & e) {
326+ eprintln ! (
327+ "Warning: Config file at {:?} is read-only. The application will continue with the existing read-only config." ,
328+ config_path
329+ ) ;
330+ } else {
331+ eprintln ! (
332+ "Warning: Could not write to config file at {:?}: {}. The application will continue with the existing config." ,
333+ config_path, e
334+ ) ;
321335 }
336+ }
337+
338+ fn config_create ( args : & Args , folder_path : & Path , config_path : & Path ) -> AppResult < ( ) > {
339+ std:: fs:: create_dir_all ( folder_path) ?;
322340
323341 // Attempt to read the configuration file and parse it as a TOML Value.
324342 // If we encounter any issues (like the file not being readable or not being valid TOML), we start with a new, empty TOML table instead.
@@ -374,14 +392,25 @@ fn config_create(args: &Args, folder_path: &Path, config_path: &Path) -> AppResu
374392 config. sound_enabled = Some ( false ) ;
375393 }
376394
395+ // Try to write the config file, but don't fail if it's read-only
396+ // This allows the application to work with read-only config files (e.g., from NixOS/home-manager)
377397 let toml_string = toml:: to_string ( & config) . map_err ( |e| {
378- std :: io:: Error :: new (
379- std :: io:: ErrorKind :: InvalidData ,
398+ io:: Error :: new (
399+ io:: ErrorKind :: InvalidData ,
380400 format ! ( "Failed to serialize config to TOML: {e}" ) ,
381401 )
382402 } ) ?;
383- let mut file = File :: create ( config_path) ?;
384- file. write_all ( toml_string. as_bytes ( ) ) ?;
403+
404+ match File :: create ( config_path) {
405+ Ok ( mut file) => {
406+ if let Err ( e) = file. write_all ( toml_string. as_bytes ( ) ) {
407+ handle_config_write_error ( e, config_path) ;
408+ }
409+ }
410+ Err ( e) => {
411+ handle_config_write_error ( e, config_path) ;
412+ }
413+ }
385414
386415 Ok ( ( ) )
387416}
0 commit comments