Skip to main content

hugo_server/
config.rs

1use std::net::Ipv4Addr;
2use std::path::PathBuf;
3use std::{env, fs};
4
5use anyhow::{Context, Result};
6use serde::Deserialize;
7use url::Url;
8
9#[must_use]
10#[derive(Deserialize)]
11pub struct Config {
12    pub server: ServerConfig,
13    pub https: HttpsConfig,
14    pub hugo: HugoConfig,
15    pub algolia: AlgoliaConfig,
16}
17
18impl Config {
19    pub fn load_config<T>(file_name: T) -> Result<Self>
20    where
21        T: AsRef<str>,
22    {
23        let file_name = file_name.as_ref();
24
25        let mut current_dir = env::current_dir()?;
26        loop {
27            let candidate = current_dir.join(file_name);
28            if candidate.try_exists()? {
29                tracing::info!("Load config file from `{}`", candidate.display());
30
31                let mut config: Self = toml::from_str(&fs::read_to_string(candidate)?)?;
32                config.canonicalize()?;
33
34                return Ok(config);
35            }
36
37            if !current_dir.pop() {
38                anyhow::bail!("cannot find `{file_name}`");
39            }
40        }
41    }
42
43    fn canonicalize(&mut self) -> Result<()> {
44        self.https.cert_path = self
45            .https
46            .cert_path
47            .canonicalize()
48            .context(format!("can not find `{}`", self.https.cert_path.display()))?;
49        self.https.key_path = self
50            .https
51            .key_path
52            .canonicalize()
53            .context(format!("can not find `{}`", self.https.key_path.display()))?;
54        self.hugo.repo_dst = env::current_dir()?.join(&self.hugo.repo_dst);
55
56        Ok(())
57    }
58}
59
60#[must_use]
61#[derive(Deserialize)]
62pub struct ServerConfig {
63    pub host: Ipv4Addr,
64    pub port: u16,
65}
66
67#[must_use]
68#[derive(Deserialize)]
69pub struct HttpsConfig {
70    pub cert_path: PathBuf,
71    pub key_path: PathBuf,
72}
73
74#[must_use]
75#[derive(Deserialize)]
76pub struct HugoConfig {
77    pub repo_url: Url,
78    pub repo_dst: PathBuf,
79}
80
81#[must_use]
82#[derive(Deserialize)]
83pub struct AlgoliaConfig {
84    pub records_file_name: PathBuf,
85    pub application_id: String,
86    pub api_key: String,
87    pub index_name: String,
88}
89
90#[cfg(test)]
91mod tests {
92    use testresult::TestResult;
93    use tracing_test::traced_test;
94
95    use super::*;
96
97    #[test]
98    #[traced_test]
99    fn test_load_config() -> TestResult {
100        let _ = Config::load_config(".config.toml")?;
101
102        Ok(())
103    }
104}