diff --git a/src/config/general.rs b/src/config/general.rs index 1ef4807a0c56388d2270aa7a11892676755e8111..7ed6c33f5efa1367aa09ab4e0bad295306c458df 100644 --- a/src/config/general.rs +++ b/src/config/general.rs @@ -5,3 +5,11 @@ pub struct GeneralConfig { pub repo_binary: Option<bool>, pub efi_partition_size: Option<u32>, //MiB } + +impl GeneralConfig { + pub(super) fn merge(&mut self, other: GeneralConfig) { + self.prompt = other.prompt; + self.repo_binary = other.repo_binary.or(self.repo_binary); + self.efi_partition_size = other.efi_partition_size.or(self.efi_partition_size); + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs index 712803b2c8f6e4de1ce416433cbfd97954fa10c2..e6ff206cb23f8184718157149486853f10d82957 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use std::fs; -use std::path::Path; +use std::mem; +use std::path::{Path, PathBuf}; pub mod file; pub mod general; @@ -9,6 +10,8 @@ pub mod user; #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct Config { + #[serde(default)] + pub include: Vec<PathBuf>, pub general: general::GeneralConfig, #[serde(default)] pub packages: BTreeMap<String, package::PackageConfig>, @@ -20,7 +23,7 @@ pub struct Config { impl Config { pub fn from_file(path: &Path) -> Result<Self, failure::Error> { - let config = match fs::read_to_string(&path) { + let mut config: Config = match fs::read_to_string(&path) { Ok(config_data) => match toml::from_str(&config_data) { Ok(config) => config, Err(err) => { @@ -31,6 +34,46 @@ impl Config { return Err(format_err!("{}: failed to read: {}", path.display(), err)); } }; + + let config_dir = path.parent().unwrap(); + + let mut configs = mem::take(&mut config.include) + .into_iter() + .map(|path| Config::from_file(&config_dir.join(path))) + .collect::<Result<Vec<Config>, failure::Error>>()?; + configs.push(config); // Put ourself last to ensure that it overwrites anything else. + + config = configs.remove(0); + + for other_config in configs { + config.merge(other_config); + } + Ok(config) } + + pub fn merge(&mut self, other: Config) { + assert!(self.include.is_empty()); + assert!(other.include.is_empty()); + + let Config { + include: _, + general: other_general, + packages: other_packages, + files: other_files, + users: other_users, + } = other; + + self.general.merge(other_general); + + for (package, package_config) in other_packages { + self.packages.insert(package, package_config); + } + + self.files.extend(other_files); + + for (user, user_config) in other_users { + self.users.insert(user, user_config); + } + } }