Skip to main content

cloud_image_download/
settings.rs

1/* Configuration management */
2use crate::cli::Cli;
3use crate::website::WebSite;
4use config::Config;
5use log::error;
6use serde::Deserialize;
7use std::process::exit;
8
9/// Stores settings read from a configuration file.
10#[derive(Debug, Deserialize)]
11pub struct Settings {
12    pub db_path: Option<String>,
13    pub sites: Vec<WebSite>,
14}
15
16impl Settings {
17    /// Deserializes (if possible) the whole configuration file that
18    /// may have been specified in the command line
19    #[must_use]
20    pub fn from_config(cli: &Cli) -> Self {
21        let config_filename = match shellexpand::full(&cli.config) {
22            Ok(conf) => conf,
23            Err(e) => {
24                error!("Error expanding {}: {e}", cli.config);
25                exit(1);
26            }
27        };
28
29        let config = match Config::builder()
30            .add_source(config::File::with_name(&config_filename).required(false))
31            .add_source(config::Environment::with_prefix("CID_"))
32            .build()
33        {
34            Ok(conf) => conf,
35            Err(e) => {
36                error!("Error: {e}");
37                exit(1);
38            }
39        };
40
41        let mut settings = match config.try_deserialize::<Settings>() {
42            Ok(settings) => settings,
43            Err(e) => {
44                error!("Error deserializing: {e}");
45                exit(1);
46            }
47        };
48
49        // To give the command line option the latest word:
50        // overwrite db_path setting if one was provided with
51        // the cli
52        if let Some(db_path) = &cli.db_path {
53            settings.db_path = Some(db_path.clone());
54        }
55
56        settings
57    }
58}
59
60// Tests that the test configuration has been correctly parsed
61#[test]
62fn test_settings_from_config() {
63    use clap_verbosity_flag::Verbosity;
64
65    let cli = Cli {
66        db_path: None,
67        config: "test_data/cloud-image-download.toml".to_string(),
68        verbose: Verbosity::new(0, 0),
69        concurrent_downloads: 2,
70        verify_skipped: false,
71    };
72
73    let settings = Settings::from_config(&cli);
74
75    assert_eq!(settings.sites.len(), 4);
76    assert_eq!(settings.db_path, Some("~/.cache/".to_string()));
77}
78
79// Tests cli precedence
80#[test]
81fn test_db_path_settings_from_config() {
82    use clap_verbosity_flag::Verbosity;
83
84    let cli = Cli {
85        db_path: Some("/var/lib/cid".to_string()),
86        config: "test_data/cloud-image-download.toml".to_string(),
87        verbose: Verbosity::new(0, 0),
88        concurrent_downloads: 2,
89        verify_skipped: false,
90    };
91
92    let settings = Settings::from_config(&cli);
93    assert_eq!(settings.db_path, Some("/var/lib/cid".to_string()));
94}
95
96// Tests default
97#[test]
98fn test_db_path_settings_default() {
99    use clap_verbosity_flag::Verbosity;
100
101    let cli = Cli {
102        db_path: None,
103        config: "test_data/no_db_path.toml".to_string(),
104        verbose: Verbosity::new(0, 0),
105        concurrent_downloads: 2,
106        verify_skipped: false,
107    };
108
109    let settings = Settings::from_config(&cli);
110    assert_eq!(settings.db_path, None);
111}