@@ -3,7 +3,7 @@ use std::collections::HashSet;
3
3
4
4
use anyhow:: bail;
5
5
use anyhow:: anyhow;
6
- use configparser :: ini:: Ini ;
6
+ use ini:: Ini ;
7
7
use anyhow:: Error ;
8
8
use anyhow:: Result ;
9
9
use regex:: Regex ;
@@ -140,21 +140,19 @@ config_options! {
140
140
141
141
/// Parse the configuration file
142
142
///
143
- /// Returns a vector of ConfigSections, excluding the DEFAULT section, which
143
+ /// Returns a vector of ConfigSections, excluding the [default] section, which
144
144
/// is used to fill in missing values in the other sections.
145
145
pub ( crate ) fn parse_config ( config_file : & str ) -> Result < Vec < ConfigSection > , Error >
146
146
{
147
- let mut config = Ini :: new ( ) ;
148
- config. load ( config_file) . map_err ( |e| anyhow ! ( "Error loading config file: {}" , e) ) ?;
149
- let map = config. get_map_ref ( ) ;
147
+ let mut ini = Ini :: load_from_file ( config_file) ?;
150
148
151
- // Get the DEFAULT section
152
- let mut defaults = match map . get ( "default" ) {
153
- Some ( d ) => d ,
154
- None => bail ! ( "No ' default' section in config file" ) ,
155
- } . clone ( ) ;
156
-
157
- // Fill in missing values from built-in defaults
149
+ // Collect defaults
150
+ let mut defaults = HashMap :: new ( ) ;
151
+ // ...from the [default] section
152
+ if let Some ( default_sect ) = ini . section ( Some ( " default" ) ) {
153
+ defaults . extend ( default_sect . iter ( ) . map ( | ( k , v ) | ( k . to_string ( ) , Some ( v . to_string ( ) ) ) ) ) ;
154
+ }
155
+ // .. from built-in defaults
158
156
for ( key, _, def) in CONFIG_OPTIONS . iter ( ) {
159
157
if !defaults. contains_key ( * key) {
160
158
if let Some ( def) = def {
@@ -167,18 +165,22 @@ pub(crate) fn parse_config(config_file: &str) -> Result<Vec<ConfigSection>, Erro
167
165
let mut res = Vec :: new ( ) ;
168
166
169
167
// Walk through the sections
170
- for section_name in config. sections ( ) {
171
- let mut sect_map = map. get ( section_name. as_str ( ) ) . unwrap ( ) . clone ( ) ;
168
+ for ( section_name, sect_props) in ini. iter_mut ( ) {
169
+ let section_name = match section_name {
170
+ Some ( name) => name,
171
+ None => { bail ! ( "Options outside of a section are not allowed" ) ; }
172
+ } ;
173
+
172
174
if seen_sections. contains ( & section_name) {
173
175
bail ! ( "Duplicate section [{}]" , section_name) ;
174
176
} else {
175
177
seen_sections. insert ( section_name. clone ( ) ) ;
176
178
}
177
179
178
180
// Check that no unknown keys are set
179
- let unknown_keys = sect_map. keys ( )
181
+ let unknown_keys = sect_props. iter ( )
182
+ . map ( |( key, _) | key)
180
183
. filter ( |key| !CONFIG_OPTIONS . iter ( ) . any ( |( k, _, _) | k == key) )
181
- . map ( |key| key. clone ( ) )
182
184
. collect :: < Vec < _ > > ( ) ;
183
185
if !unknown_keys. is_empty ( ) {
184
186
bail ! ( "Unknown key(s) in section [{}]: {}" , & section_name, unknown_keys. join( ", " ) ) ;
@@ -190,25 +192,26 @@ pub(crate) fn parse_config(config_file: &str) -> Result<Vec<ConfigSection>, Erro
190
192
191
193
// Apply defaults
192
194
for ( key, value) in & defaults {
193
- if sect_map. get ( key) . is_none ( ) {
194
- sect_map. insert ( key. clone ( ) , value. clone ( ) ) ;
195
+ if sect_props. get ( key) . is_none ( ) {
196
+ if let Some ( value) = value {
197
+ sect_props. insert ( key. clone ( ) , value. clone ( ) ) ;
198
+ }
195
199
}
196
200
}
197
201
198
202
// Check that all required keys are set
199
203
let missing_keys = CONFIG_OPTIONS . iter ( )
200
- . filter ( |( key, _, _) | !sect_map . contains_key ( * key) )
204
+ . filter ( |( key, _, _) | !sect_props . contains_key ( * key) )
201
205
. map ( |( key, _, _) | * key)
202
206
. filter ( |key| key != & "section" )
203
207
. collect :: < Vec < _ > > ( ) ;
204
208
if !missing_keys. is_empty ( ) {
205
209
bail ! ( "Config option(s) not set in section [{}]: {}" , section_name, missing_keys. join( ", " ) ) ;
206
210
}
207
211
208
- let get = |key : & str | sect_map . get ( key)
212
+ let get = |key : & str | sect_props . get ( key)
209
213
. unwrap_or_else ( || panic ! ( "BUG: missing key '{key}' after checking that it's not missing?!" ) )
210
- . clone ( )
211
- . expect ( "BUG? None value for an config value?" ) ;
214
+ . to_string ( ) ;
212
215
213
216
// Compile regex
214
217
let http_path = get ( "http_path" ) ;
@@ -240,7 +243,7 @@ pub(crate) fn parse_config(config_file: &str) -> Result<Vec<ConfigSection>, Erro
240
243
241
244
// Store result
242
245
res. push ( ConfigSection {
243
- section : section_name. clone ( ) ,
246
+ section : section_name. to_string ( ) ,
244
247
http_path : http_path_re,
245
248
username_http_header : get ( "username_http_header" ) ,
246
249
0 commit comments