@@ -2,6 +2,8 @@ use std::collections::HashMap;
22use std:: error:: Error ;
33use std:: path:: PathBuf ;
44
5+ use clap:: ArgMatches ;
6+
57use simple_error:: { bail, SimpleError } ;
68
79use serde_derive:: Deserialize ;
@@ -14,6 +16,8 @@ use crate::utils::*;
1416struct Config {
1517 #[ serde( default = "empty_stringmap" ) ]
1618 userlibrary : HashMap < String , String > ,
19+ #[ serde( flatten) ]
20+ extra : HashMap < String , serde_json:: Value > ,
1721}
1822
1923fn empty_stringmap ( ) -> HashMap < String , String > {
@@ -86,3 +90,137 @@ pub fn get_config(rver: &str, key: &str) -> Result<Option<String>, Box<dyn Error
8690 _ => bail ! ( "Unknown config key: {}, internal error" , key) ,
8791 }
8892}
93+
94+ #[ cfg( any( target_os = "windows" , target_os = "linux" ) ) ]
95+ pub fn sc_config ( _args : & ArgMatches , _mainargs : & ArgMatches ) -> Result < ( ) , Box < dyn Error > > {
96+ // Cannot be called
97+ Ok ( ( ) )
98+ }
99+
100+ #[ cfg( target_os = "macos" ) ]
101+ pub fn sc_config ( args : & ArgMatches , mainargs : & ArgMatches ) -> Result < ( ) , Box < dyn Error > > {
102+ match args. subcommand ( ) {
103+ Some ( ( "config-file-path" , _) ) => sc_config_config_file_path ( ) ,
104+ Some ( ( "list" , s) ) => sc_config_list ( s, mainargs) ,
105+ Some ( ( "get" , s) ) => sc_config_get ( s, mainargs) ,
106+ Some ( ( "set" , s) ) => sc_config_set ( s) ,
107+ _ => Ok ( ( ) ) ,
108+ }
109+ }
110+
111+ #[ cfg( target_os = "macos" ) ]
112+ fn sc_config_config_file_path ( ) -> Result < ( ) , Box < dyn Error > > {
113+ let path = rig_config_file ( ) ?;
114+ println ! ( "{}" , path. display( ) ) ;
115+ Ok ( ( ) )
116+ }
117+
118+ #[ cfg( target_os = "macos" ) ]
119+ fn sc_config_get ( args : & ArgMatches , mainargs : & ArgMatches ) -> Result < ( ) , Box < dyn Error > > {
120+ let key = args. get_one :: < String > ( "key" ) . unwrap ( ) ;
121+ let json = args. get_flag ( "json" ) || mainargs. get_flag ( "json" ) ;
122+
123+ let config_file = rig_config_file ( ) ?;
124+ let root: serde_json:: Value = if config_file. exists ( ) {
125+ let contents = read_file_string ( & config_file) ?;
126+ serde_json:: from_str ( & contents) ?
127+ } else {
128+ serde_json:: Value :: Object ( serde_json:: Map :: new ( ) )
129+ } ;
130+
131+ let value = & root[ key. as_str ( ) ] ;
132+ match value {
133+ serde_json:: Value :: Null => {
134+ if json {
135+ println ! ( "null" ) ;
136+ }
137+ }
138+ serde_json:: Value :: String ( s) => {
139+ if json {
140+ println ! ( "{}" , serde_json:: to_string( s) ?) ;
141+ } else {
142+ println ! ( "{}" , s) ;
143+ }
144+ }
145+ scalar @ ( serde_json:: Value :: Bool ( _) | serde_json:: Value :: Number ( _) ) => {
146+ println ! ( "{}" , scalar) ;
147+ }
148+ complex => {
149+ println ! ( "{}" , serde_json:: to_string_pretty( complex) ?) ;
150+ }
151+ }
152+ Ok ( ( ) )
153+ }
154+
155+ #[ cfg( any( target_os = "macos" , target_os = "linux" ) ) ]
156+ fn load_raw_config ( ) -> Result < serde_json:: Map < String , serde_json:: Value > , Box < dyn Error > > {
157+ let config_file = rig_config_file ( ) ?;
158+ if config_file. exists ( ) {
159+ let contents = read_file_string ( & config_file) ?;
160+ let value: serde_json:: Value = serde_json:: from_str ( & contents) ?;
161+ match value {
162+ serde_json:: Value :: Object ( map) => Ok ( map) ,
163+ _ => bail ! ( "Config file is not a JSON object" ) ,
164+ }
165+ } else {
166+ Ok ( serde_json:: Map :: new ( ) )
167+ }
168+ }
169+
170+ #[ cfg( target_os = "macos" ) ]
171+ fn save_raw_config ( map : & serde_json:: Map < String , serde_json:: Value > ) -> Result < ( ) , Box < dyn Error > > {
172+ let config_file = rig_config_file ( ) ?;
173+ let parent = config_file
174+ . parent ( )
175+ . ok_or ( SimpleError :: new ( "Invalid config file directory" ) ) ?;
176+ std:: fs:: create_dir_all ( parent) ?;
177+ std:: fs:: write ( config_file, serde_json:: to_string_pretty ( map) ?) ?;
178+ Ok ( ( ) )
179+ }
180+
181+ #[ cfg( any( target_os = "macos" , target_os = "linux" ) ) ]
182+ pub fn get_global_config_value ( key : & str ) -> Result < Option < String > , Box < dyn Error > > {
183+ let map = load_raw_config ( ) ?;
184+ match map. get ( key) {
185+ Some ( serde_json:: Value :: String ( s) ) => Ok ( Some ( s. clone ( ) ) ) ,
186+ _ => Ok ( None ) ,
187+ }
188+ }
189+
190+ #[ cfg( target_os = "macos" ) ]
191+ fn sc_config_set ( args : & ArgMatches ) -> Result < ( ) , Box < dyn Error > > {
192+ let keyvalue = args. get_one :: < String > ( "keyvalue" ) . unwrap ( ) ;
193+ let ( key, value) = keyvalue
194+ . split_once ( '=' )
195+ . ok_or_else ( || SimpleError :: new ( format ! ( "Invalid key=value format: '{}'" , keyvalue) ) ) ?;
196+ let mut map = load_raw_config ( ) ?;
197+ map. insert ( key. to_string ( ) , serde_json:: Value :: String ( value. to_string ( ) ) ) ;
198+ save_raw_config ( & map)
199+ }
200+
201+ #[ cfg( target_os = "macos" ) ]
202+ fn sc_config_list ( args : & ArgMatches , mainargs : & ArgMatches ) -> Result < ( ) , Box < dyn Error > > {
203+ let config_file = rig_config_file ( ) ?;
204+ let keys: Vec < String > = if config_file. exists ( ) {
205+ let contents = read_file_string ( & config_file) ?;
206+ let value: serde_json:: Value = serde_json:: from_str ( & contents) ?;
207+ match value. as_object ( ) {
208+ Some ( obj) => obj. keys ( ) . cloned ( ) . collect ( ) ,
209+ None => vec ! [ ] ,
210+ }
211+ } else {
212+ vec ! [ ]
213+ } ;
214+
215+ if args. get_flag ( "json" ) || mainargs. get_flag ( "json" ) {
216+ #[ derive( serde:: Serialize ) ]
217+ struct Entry { key : String }
218+ let entries: Vec < Entry > = keys. into_iter ( ) . map ( |k| Entry { key : k } ) . collect ( ) ;
219+ println ! ( "{}" , serde_json:: to_string_pretty( & entries) ?) ;
220+ } else {
221+ for key in keys {
222+ println ! ( "{}" , key) ;
223+ }
224+ }
225+ Ok ( ( ) )
226+ }
0 commit comments