gravel/init/
config.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
use abi_stable::std_types::{RStr, RString};
use gravel_core::config::{ConfigManager, DEFAULT_CONFIG};
use gravel_core::paths::config_dir;
use gravel_ffi::config::__private_api::{ConfigLayer, ConfigSource, MergeStrategy};
use std::env::consts;

/// Reads and deserializes the configuration from multiple sources, see [`sources`].
///
/// Each layer can override the values of the previous layers.
pub fn config() -> ConfigManager {
	log::trace!("loading config");

	ConfigManager::new(sources())
}

/// Returns configuration layers:
/// - Baked-in default config (config.yml in crate root)
/// - User config file in `$XDG_CONFIG_HOME/gravel/config.yml`
/// - Platform-specific user config file in e.g.
///   `$XDG_CONFIG_HOME/gravel/platform/linux.yml`
/// - Host-specific user config file in e.g.
///   `$XDG_CONFIG_HOME/gravel/host/yourhostname.yml`
fn sources() -> Vec<ConfigLayer> {
	let user_config_dir = config_dir();
	let user_config_path = user_config_dir.join("config.yml");
	let platform_config_path = user_config_dir.join(format!("platform/{}.yml", consts::OS));
	let host_config_path = user_config_dir.join(format!("host/{}.yml", hostname()));

	log::debug!("reading configs from {user_config_path:?}; {platform_config_path:?}; {host_config_path:?}");

	let user_config_path = RString::from(user_config_path.to_string_lossy());
	let platform_config_path = RString::from(platform_config_path.to_string_lossy());
	let host_config_path = RString::from(host_config_path.to_string_lossy());

	use {ConfigSource as C, MergeStrategy as S};
	vec![
		ConfigLayer(C::String(RStr::from(DEFAULT_CONFIG)), S::Merge),
		ConfigLayer(C::File(user_config_path), S::Merge),
		ConfigLayer(C::File(platform_config_path), S::AdMerge),
		ConfigLayer(C::File(host_config_path), S::AdMerge),
	]
}

fn hostname() -> String {
	match hostname::get() {
		Ok(h) => h.to_string_lossy().into_owned(),
		Err(e) => {
			log::warn!("unable to get hostname, falling back to 'default'. error: {e}");
			String::from("default")
		}
	}
}