22
33use anyhow:: { Context , Result } ;
44use serde:: { Deserialize , Serialize } ;
5- use std:: io:: Write ;
5+ use std:: io:: { Read , Write } ;
66use std:: path:: { Path , PathBuf } ;
7- use std:: {
8- borrow:: Cow ,
9- fs:: { self , File } ,
10- } ;
7+ use std:: { borrow:: Cow , fs} ;
118use tmc_langs_framework:: file_util;
129use toml:: { value:: Table , Value } ;
1310
@@ -66,39 +63,59 @@ impl TmcConfig {
6663
6764 pub fn save ( self , client_name : & str ) -> Result < ( ) > {
6865 let path = Self :: get_location ( client_name) ?;
69- file_util:: lock!( & path) ;
66+ if let Some ( parent) = path. parent ( ) {
67+ file_util:: create_dir_all ( parent) ?;
68+ }
69+ let mut lock = file_util:: create_file_lock ( & path) ?;
70+ let mut guard = lock. lock ( ) ?;
7071
7172 let toml = toml:: to_string_pretty ( & self ) . context ( "Failed to serialize HashMap" ) ?;
72- fs:: write ( & path, toml. as_bytes ( ) )
73+ guard
74+ . write_all ( toml. as_bytes ( ) )
7375 . with_context ( || format ! ( "Failed to write TOML to {}" , path. display( ) ) ) ?;
7476 Ok ( ( ) )
7577 }
7678
7779 pub fn reset ( client_name : & str ) -> Result < ( ) > {
7880 let path = Self :: get_location ( client_name) ?;
79- file_util:: lock!( & path) ;
80-
81- Self :: init_at ( client_name, & path) ?;
81+ Self :: init_at ( client_name, & path) ?; // init locks the file
8282 Ok ( ( ) )
8383 }
8484
8585 pub fn load ( client_name : & str ) -> Result < TmcConfig > {
8686 let path = Self :: get_location ( client_name) ?;
87- file_util:: lock!( & path) ;
88-
89- let config = match fs:: read ( & path) {
90- Ok ( bytes) => match toml:: from_slice ( & bytes) {
91- Ok ( config) => Ok ( config) ,
92- Err ( _) => {
93- log:: error!(
94- "Failed to deserialize config at {}, resetting" ,
95- path. display( )
96- ) ;
97- Self :: init_at ( client_name, & path)
87+
88+ // try to open config file
89+ let config = match file_util:: open_file_lock ( & path) {
90+ Ok ( mut lock) => {
91+ // found config file, lock and read
92+ let mut guard = lock. lock ( ) ?;
93+ let mut buf = vec ! [ ] ;
94+ let _bytes = guard. read_to_end ( & mut buf) ?;
95+ match toml:: from_slice ( & buf) {
96+ // successfully read file, try to deserialize
97+ Ok ( config) => config, // successfully read and deserialized the config
98+ Err ( _) => {
99+ log:: error!(
100+ "Failed to deserialize config at {}, resetting" ,
101+ path. display( )
102+ ) ;
103+ Self :: init_at ( client_name, & path) ?
104+ }
98105 }
99- } ,
100- Err ( _) => Self :: init_at ( client_name, & path) ,
101- } ?;
106+ }
107+ Err ( e) => {
108+ // failed to open config file, create new one
109+ log:: info!(
110+ "could not open config file at {} due to {}, initializing a new config file" ,
111+ path. display( ) ,
112+ e
113+ ) ;
114+ // todo: check the cause to make sure this makes sense, might be necessary to propagate some error kinds
115+ Self :: init_at ( client_name, & path) ?
116+ }
117+ } ;
118+
102119 if !config. projects_dir . exists ( ) {
103120 fs:: create_dir_all ( & config. projects_dir ) . with_context ( || {
104121 format ! (
@@ -112,10 +129,13 @@ impl TmcConfig {
112129
113130 // initializes the default configuration file at the given path
114131 fn init_at ( client_name : & str , path : & Path ) -> Result < TmcConfig > {
115- file_util:: lock!( path) ;
132+ if let Some ( parent) = path. parent ( ) {
133+ file_util:: create_dir_all ( parent) ?;
134+ }
116135
117- let mut file = File :: create ( & path)
136+ let mut lock = file_util :: create_file_lock ( path)
118137 . with_context ( || format ! ( "Failed to create new config file at {}" , path. display( ) ) ) ?;
138+ let mut guard = lock. lock ( ) ?;
119139
120140 let default_project_dir = dirs:: data_local_dir ( )
121141 . context ( "Failed to find local data directory" ) ?
@@ -134,7 +154,8 @@ impl TmcConfig {
134154 } ;
135155
136156 let toml = toml:: to_string_pretty ( & config) . context ( "Failed to serialize config" ) ?;
137- file. write_all ( toml. as_bytes ( ) )
157+ guard
158+ . write_all ( toml. as_bytes ( ) )
138159 . with_context ( || format ! ( "Failed to write default config to {}" , path. display( ) ) ) ?;
139160 Ok ( config)
140161 }
0 commit comments