@@ -2,19 +2,11 @@ use rustc_hash::FxHashMap;
22use serde:: Deserialize ;
33use serde:: Deserializer ;
44use std:: env;
5- use std:: mem;
65use std:: path:: PathBuf ;
76
87use crate :: error;
98
10- // We can't assign `a` to `b` in the loop in `Config::load`, so we'll have to use swap. It looks ugly so now we have a macro for it.
11- macro_rules! swap {
12- ( $a: expr, $b: expr) => {
13- mem:: swap( & mut $a, & mut $b)
14- } ;
15- }
16-
17- #[ derive( Clone , Deserialize ) ]
9+ #[ derive( Clone , Deserialize , Debug ) ]
1810#[ serde( rename_all = "snake_case" ) ]
1911pub enum Theme {
2012 Default ,
@@ -27,7 +19,18 @@ impl Default for Theme {
2719 }
2820}
2921
30- #[ derive( Clone , Deserialize ) ]
22+ impl std:: str:: FromStr for Theme {
23+ type Err = String ;
24+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
25+ match s. to_lowercase ( ) . as_str ( ) {
26+ "default" => Ok ( Self :: Default ) ,
27+ "blue" => Ok ( Self :: Blue ) ,
28+ _ => Err ( format ! ( "Invalid theme: {}" , s) ) ,
29+ }
30+ }
31+ }
32+
33+ #[ derive( Clone , Deserialize , Debug ) ]
3134#[ serde( rename_all = "snake_case" ) ]
3235pub enum UpdateType {
3336 None ,
@@ -42,7 +45,20 @@ impl Default for UpdateType {
4245 }
4346}
4447
45- #[ derive( Clone , Deserialize , Default ) ]
48+ impl std:: str:: FromStr for UpdateType {
49+ type Err = String ;
50+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
51+ match s. to_lowercase ( ) . as_str ( ) {
52+ "none" => Ok ( Self :: None ) ,
53+ "major" => Ok ( Self :: Major ) ,
54+ "minor" => Ok ( Self :: Minor ) ,
55+ "patch" => Ok ( Self :: Patch ) ,
56+ _ => Err ( format ! ( "Invalid update type: {}" , s) ) ,
57+ }
58+ }
59+ }
60+
61+ #[ derive( Clone , Deserialize , Default , Debug ) ]
4662#[ serde( deny_unknown_fields) ]
4763#[ serde( default ) ]
4864pub struct RegistryConfig {
@@ -51,14 +67,14 @@ pub struct RegistryConfig {
5167 pub ignore : bool ,
5268}
5369
54- #[ derive( Clone , Deserialize , Default ) ]
70+ #[ derive( Clone , Deserialize , Default , Debug ) ]
5571#[ serde( default ) ]
5672pub struct ImageConfig {
5773 pub extra : Vec < String > ,
5874 pub exclude : Vec < String > ,
5975}
6076
61- #[ derive( Clone , Deserialize ) ]
77+ #[ derive( Clone , Deserialize , Debug ) ]
6278#[ serde( default ) ]
6379pub struct Config {
6480 version : u8 ,
@@ -89,40 +105,12 @@ impl Config {
89105 }
90106
91107 /// Loads file and env config and merges them
92- pub fn load ( & mut self , path : Option < PathBuf > ) -> Self {
93- let mut config = self . load_file ( path) ;
94-
95- // Get environment variables with CUP_ prefix
96- let env_vars: FxHashMap < String , String > =
97- env:: vars ( ) . filter ( |( k, _) | k. starts_with ( "CUP_" ) ) . collect ( ) ;
98-
99- if !env_vars. is_empty ( ) {
100- if let Ok ( mut cfg) = envy:: prefixed ( "CUP_" ) . from_env :: < Config > ( ) {
101- // If we have environment variables, override config.json options
102- for ( key, _) in env_vars {
103- match key. as_str ( ) {
104- "CUP_AGENT" => config. agent = cfg. agent ,
105- #[ rustfmt:: skip]
106- "CUP_IGNORE_UPDATE_TYPE" => swap ! ( config. ignore_update_type, cfg. ignore_update_type) ,
107- #[ rustfmt:: skip]
108- "CUP_REFRESH_INTERVAL" => swap ! ( config. refresh_interval, cfg. refresh_interval) ,
109- "CUP_SOCKET" => swap ! ( config. socket, cfg. socket) ,
110- "CUP_THEME" => swap ! ( config. theme, cfg. theme) ,
111- // The syntax for these is slightly more complicated, not sure if they should be enabled or not. Let's stick to simple types for now.
112- // "CUP_IMAGES" => swap!(config.images, cfg.images),
113- // "CUP_REGISTRIES" => swap!(config.registries, cfg.registries),
114- // "CUP_SERVERS" => swap!(config.servers, cfg.servers),
115- _ => ( ) , // Maybe print a warning if other CUP_ variables are detected
116- }
117- }
118- }
119- }
120-
121- config
108+ pub fn load ( path : Option < PathBuf > ) -> Self {
109+ Config :: load_file ( path) . load_env ( )
122110 }
123111
124112 /// Reads the config from the file path provided and returns the parsed result.
125- fn load_file ( & self , path : Option < PathBuf > ) -> Self {
113+ fn load_file ( path : Option < PathBuf > ) -> Self {
126114 let raw_config = match & path {
127115 Some ( path) => std:: fs:: read_to_string ( path) ,
128116 None => return Self :: new ( ) , // Empty config
@@ -133,10 +121,10 @@ impl Config {
133121 & path. unwrap( ) . to_str( ) . unwrap( )
134122 )
135123 } ;
136- self . parse ( & raw_config. unwrap ( ) ) // We can safely unwrap here
124+ Config :: parse ( & raw_config. unwrap ( ) ) // We can safely unwrap here
137125 }
138126 /// Parses and validates the config.
139- fn parse ( & self , raw_config : & str ) -> Self {
127+ fn parse ( raw_config : & str ) -> Self {
140128 let config: Self = match serde_json:: from_str ( raw_config) {
141129 Ok ( config) => config,
142130 Err ( e) => error ! ( "Unexpected error occured while parsing config: {}" , e) ,
@@ -146,6 +134,37 @@ impl Config {
146134 }
147135 config
148136 }
137+
138+ /// Read and parse environment variables into the config object and return it.
139+ fn load_env ( mut self ) -> Self {
140+ env:: vars ( )
141+ . filter ( |( k, _) | k. starts_with ( "CUP_" ) )
142+ . for_each ( |( key, value) | match key. as_str ( ) {
143+ "CUP_AGENT" => self . agent = value. parse ( ) . unwrap ( ) ,
144+ "CUP_IGNORE_UPDATE_TYPE" => self . ignore_update_type = value. parse ( ) . unwrap ( ) ,
145+ "CUP_REFRESH_INTERVAL" => self . refresh_interval = Some ( value) ,
146+ "CUP_SOCKET" => self . socket = Some ( value) ,
147+ "CUP_THEME" => self . theme = value. parse ( ) . unwrap ( ) ,
148+ "CUP_IMAGES_EXCLUDE" => {
149+ self . images . exclude = value
150+ . split ( ' ' )
151+ . map ( |s| s. trim ( ) . to_string ( ) )
152+ . filter ( |s| !s. is_empty ( ) )
153+ . collect ( )
154+ }
155+ "CUP_IMAGES_EXTRA" => {
156+ self . images . extra = value
157+ . split ( ' ' )
158+ . map ( |s| s. trim ( ) . to_string ( ) )
159+ . filter ( |s| !s. is_empty ( ) )
160+ . collect ( )
161+ }
162+ // "CUP_REGISTRIES" => ...
163+ // "CUP_SERVERS" => ...
164+ _ => println ! ( "Warning: Skip unknown CUP_ variable '{}'." , key) ,
165+ } ) ;
166+ self
167+ }
149168}
150169
151170impl Default for Config {
0 commit comments