@@ -313,27 +313,33 @@ impl Configuration {
313313 }
314314
315315 /// Loads the configuration from the `Info` struct. The whole
316- /// configuration in toml format is included in the `info.tracker_toml` string.
316+ /// configuration in toml format is included in the `info.tracker_toml`
317+ /// string.
317318 ///
318- /// Optionally will override the admin api token .
319+ /// Configuration provided via env var has priority over config file path .
319320 ///
320321 /// # Errors
321322 ///
322323 /// Will return `Err` if the environment variable does not exist or has a bad configuration.
323324 pub fn load ( info : & Info ) -> Result < Configuration , Error > {
325+ // Load configuration provided by the user, prioritizing env vars
324326 let figment = if let Some ( config_toml) = & info. config_toml {
325- // Config in env var has priority over config file path
326- Figment :: from ( Serialized :: defaults ( Configuration :: default ( ) ) )
327- . merge ( Toml :: string ( config_toml) )
328- . merge ( Env :: prefixed ( CONFIG_OVERRIDE_PREFIX ) . split ( CONFIG_OVERRIDE_SEPARATOR ) )
327+ Figment :: from ( Toml :: string ( config_toml) ) . merge ( Env :: prefixed ( CONFIG_OVERRIDE_PREFIX ) . split ( CONFIG_OVERRIDE_SEPARATOR ) )
329328 } else {
330- Figment :: from ( Serialized :: defaults ( Configuration :: default ( ) ) )
331- . merge ( Toml :: file ( & info. config_toml_path ) )
329+ Figment :: from ( Toml :: file ( & info. config_toml_path ) )
332330 . merge ( Env :: prefixed ( CONFIG_OVERRIDE_PREFIX ) . split ( CONFIG_OVERRIDE_SEPARATOR ) )
333331 } ;
334332
333+ // Make sure user has provided the mandatory options.
334+ Self :: check_mandatory_options ( & figment) ?;
335+
336+ // Fill missing options with default values.
337+ let figment = figment. join ( Serialized :: defaults ( Configuration :: default ( ) ) ) ;
338+
339+ // Build final configuration.
335340 let config: Configuration = figment. extract ( ) ?;
336341
342+ // Make sure the provided schema version matches this version.
337343 if config. metadata . schema_version != Version :: new ( VERSION_2_0_0 ) {
338344 return Err ( Error :: UnsupportedVersion {
339345 version : config. metadata . schema_version ,
@@ -343,6 +349,28 @@ impl Configuration {
343349 Ok ( config)
344350 }
345351
352+ /// Some configuration options are mandatory. The tracker will panic if
353+ /// the user doesn't provide an explicit value for them from one of the
354+ /// configuration sources: TOML or ENV VARS.
355+ ///
356+ /// # Errors
357+ ///
358+ /// Will return an error if a mandatory configuration option is only
359+ /// obtained by default value (code), meaning the user hasn't overridden it.
360+ fn check_mandatory_options ( figment : & Figment ) -> Result < ( ) , Error > {
361+ let mandatory_options = [ "metadata.schema_version" , "logging.threshold" , "core.private" , "core.listed" ] ;
362+
363+ for mandatory_option in mandatory_options {
364+ figment
365+ . find_value ( mandatory_option)
366+ . map_err ( |_err| Error :: MissingMandatoryOption {
367+ path : mandatory_option. to_owned ( ) ,
368+ } ) ?;
369+ }
370+
371+ Ok ( ( ) )
372+ }
373+
346374 /// Saves the configuration to the configuration file.
347375 ///
348376 /// # Errors
@@ -496,14 +524,25 @@ mod tests {
496524 }
497525
498526 #[ test]
499- fn configuration_should_use_the_default_values_when_an_empty_configuration_is_provided_by_the_user ( ) {
527+ fn configuration_should_use_the_default_values_when_only_the_mandatory_options_are_provided_by_the_user_via_toml_file ( ) {
500528 figment:: Jail :: expect_with ( |jail| {
501- jail. create_file ( "tracker.toml" , "" ) ?;
529+ jail. create_file (
530+ "tracker.toml" ,
531+ r#"
532+ [metadata]
533+ schema_version = "2.0.0"
534+
535+ [logging]
536+ threshold = "info"
502537
503- let empty_configuration = String :: new ( ) ;
538+ [core]
539+ listed = false
540+ private = false
541+ "# ,
542+ ) ?;
504543
505544 let info = Info {
506- config_toml : Some ( empty_configuration ) ,
545+ config_toml : None ,
507546 config_toml_path : "tracker.toml" . to_string ( ) ,
508547 } ;
509548
@@ -515,10 +554,49 @@ mod tests {
515554 } ) ;
516555 }
517556
557+ #[ test]
558+ fn configuration_should_use_the_default_values_when_only_the_mandatory_options_are_provided_by_the_user_via_toml_content ( ) {
559+ figment:: Jail :: expect_with ( |_jail| {
560+ let config_toml = r#"
561+ [metadata]
562+ schema_version = "2.0.0"
563+
564+ [logging]
565+ threshold = "info"
566+
567+ [core]
568+ listed = false
569+ private = false
570+ "#
571+ . to_string ( ) ;
572+
573+ let info = Info {
574+ config_toml : Some ( config_toml) ,
575+ config_toml_path : String :: new ( ) ,
576+ } ;
577+
578+ let configuration = Configuration :: load ( & info) . expect ( "Could not load configuration from file" ) ;
579+
580+ assert_eq ! ( configuration, Configuration :: default ( ) ) ;
581+
582+ Ok ( ( ) )
583+ } ) ;
584+ }
585+
518586 #[ test]
519587 fn default_configuration_could_be_overwritten_from_a_single_env_var_with_toml_contents ( ) {
520588 figment:: Jail :: expect_with ( |_jail| {
521589 let config_toml = r#"
590+ [metadata]
591+ schema_version = "2.0.0"
592+
593+ [logging]
594+ threshold = "info"
595+
596+ [core]
597+ listed = false
598+ private = false
599+
522600 [core.database]
523601 path = "OVERWRITTEN DEFAULT DB PATH"
524602 "#
@@ -543,6 +621,16 @@ mod tests {
543621 jail. create_file (
544622 "tracker.toml" ,
545623 r#"
624+ [metadata]
625+ schema_version = "2.0.0"
626+
627+ [logging]
628+ threshold = "info"
629+
630+ [core]
631+ listed = false
632+ private = false
633+
546634 [core.database]
547635 path = "OVERWRITTEN DEFAULT DB PATH"
548636 "# ,
0 commit comments