hyprshell_config_lib/
load.rs

1use crate::Config;
2use crate::migrate::check_migration_needed;
3use anyhow::{Context, bail};
4use ron::Options;
5use ron::extensions::Extensions;
6use serde::de::DeserializeOwned;
7use std::ffi::OsStr;
8use std::path::Path;
9use tracing::{debug, debug_span, info, trace, warn};
10
11pub fn load_and_migrate_config(config_path: &Path, allow_migrate: bool) -> anyhow::Result<Config> {
12    let _span = debug_span!("load_config", path =? config_path).entered();
13    if !config_path.exists() {
14        bail!("Config file does not exist, create it using `hyprshell config generate`");
15    }
16
17    if check_migration_needed(config_path)
18        .inspect_err(|e| warn!("Failed to check if migration is needed: {e:?}"))
19        .unwrap_or(false)
20    {
21        info!("Config needs migration");
22        if !allow_migrate {
23            bail!("Config file needs migration, but migration is not allowed.");
24        }
25        let migrated = crate::migrate::migrate(config_path);
26        match migrated {
27            Ok(config) => {
28                info!("Config migrated successfully");
29                crate::check(&config)?;
30                return Ok(config);
31            }
32            Err(err) => {
33                warn!("Migration failed: \n{err:?}");
34            }
35        }
36    } else {
37        trace!("No migration needed");
38    }
39
40    let config: Config = load_config_file(config_path).with_context(|| {
41        format!(
42            "Failed to load config from file ({})",
43            config_path.display()
44        )
45    })?;
46    debug!("Loaded config");
47
48    crate::check(&config)?;
49
50    Ok(config)
51}
52
53pub fn load_config_file<T: DeserializeOwned>(config_path: &Path) -> anyhow::Result<T> {
54    let config_path_display = config_path.display();
55    match config_path.extension().and_then(OsStr::to_str) {
56        None | Some("ron") => {
57            let options = Options::default()
58                .with_default_extension(Extensions::IMPLICIT_SOME)
59                .with_default_extension(Extensions::UNWRAP_NEWTYPES)
60                .with_default_extension(Extensions::UNWRAP_VARIANT_NEWTYPES);
61            let file = std::fs::File::open(config_path)
62                .with_context(|| format!("Failed to open RON config at ({config_path_display})"))?;
63            options
64                .from_reader(file)
65                .with_context(|| format!("Failed to read RON config at ({config_path_display})"))
66        }
67        #[cfg(not(feature = "json5_config"))]
68        Some("json") => {
69            let file = std::fs::File::open(config_path).with_context(|| {
70                format!("Failed to open JSON5 config at ({config_path_display})")
71            })?;
72            serde_json::from_reader(file)
73                .with_context(|| format!("Failed to read JSON5 config at ({config_path_display})"))
74        }
75        #[cfg(feature = "json5_config")]
76        Some("json5" | "json") => {
77            let file = std::fs::File::open(config_path).with_context(|| {
78                format!("Failed to open JSON5 config at ({config_path_display})")
79            })?;
80            serde_json5::from_reader(file)
81                .with_context(|| format!("Failed to read JSON5 config at ({config_path_display})"))
82        }
83        Some("toml") => {
84            use std::io::Read;
85            let mut file = std::fs::File::open(config_path).with_context(|| {
86                format!("Failed to open TOML config at ({config_path_display})")
87            })?;
88            let mut content = String::new();
89            file.read_to_string(&mut content).with_context(|| {
90                format!("Failed to read TOML config at ({config_path_display})")
91            })?;
92            toml::from_str(&content).context("Failed to parse TOML config")
93        }
94        Some(ext) => bail!(
95            "Invalid config file extension: {} (run with -vv and check `FEATURES: ` debug log to see enabled extensions)",
96            ext
97        ),
98    }
99}