From ccc1068d9fd894334feef7d50a7a2b6930c7a34f Mon Sep 17 00:00:00 2001 From: Michael Aaron Murphy Date: Fri, 14 Feb 2025 21:44:08 +0100 Subject: [PATCH] feat(cosmic_config): add ConfigGet::get_{local,system_default} Required by https://github.com/pop-os/cosmic-settings/pull/975 to a modify a config containing a HashMap which is used to partially-override the system default config in the compositor. --- cosmic-config/src/lib.rs | 60 ++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/cosmic-config/src/lib.rs b/cosmic-config/src/lib.rs index f915da71d24..0a3e0c9e7cc 100644 --- a/cosmic-config/src/lib.rs +++ b/cosmic-config/src/lib.rs @@ -33,6 +33,7 @@ pub enum Error { Io(std::io::Error), NoConfigDirectory, Notify(notify::Error), + NotFound, Ron(ron::Error), RonSpanned(ron::error::SpannedError), GetKey(String, std::io::Error), @@ -46,6 +47,7 @@ impl fmt::Display for Error { Self::Io(err) => err.fmt(f), Self::NoConfigDirectory => write!(f, "cosmic config directory not found"), Self::Notify(err) => err.fmt(f), + Self::NotFound => write!(f, "cosmic config key not configured"), Self::Ron(err) => err.fmt(f), Self::RonSpanned(err) => err.fmt(f), Self::GetKey(key, err) => write!(f, "failed to get key '{}': {}", key, err), @@ -55,6 +57,15 @@ impl fmt::Display for Error { impl std::error::Error for Error {} +impl Error { + /// Whether the reason for the missing config is caused by an error. + /// + /// Useful for determining if it is appropriate to log as an error. + pub fn is_err(&self) -> bool { + matches!(self, Self::NoConfigDirectory | Self::NotFound) + } +} + impl From> for Error { fn from(f: atomicwrites::Error) -> Self { Self::AtomicWrites(f) @@ -87,7 +98,15 @@ impl From for Error { pub trait ConfigGet { /// Get a configuration value + /// + /// Fallback to the system default if a local user override is not defined. fn get(&self, key: &str) -> Result; + + /// Get a locally-defined configuration value from the user's local config. + fn get_local(&self, key: &str) -> Result; + + /// Get the system-defined default configuration value. + fn get_system_default(&self, key: &str) -> Result; } pub trait ConfigSet { @@ -216,7 +235,7 @@ impl Config { } // Start a transaction (to set multiple configs at the same time) - pub fn transaction<'a>(&'a self) -> ConfigTransaction<'a> { + pub fn transaction(&self) -> ConfigTransaction { ConfigTransaction { config: self, updates: Mutex::new(Vec::new()), @@ -288,6 +307,7 @@ impl Config { Ok(system_path.join(sanitize_name(key)?)) } + /// Get the path of the key in the user's local config directory. fn key_path(&self, key: &str) -> Result { let Some(user_path) = self.user_path.as_ref() else { return Err(Error::NoConfigDirectory); @@ -300,22 +320,34 @@ impl Config { impl ConfigGet for Config { //TODO: check for transaction fn get(&self, key: &str) -> Result { + match self.get_local(key) { + Ok(value) => Ok(value), + Err(Error::NotFound) => self.get_system_default(key), + Err(why) => Err(why), + } + } + + fn get_local(&self, key: &str) -> Result { // If key path exists - let key_path = self.key_path(key); - let data = match key_path { - Ok(key_path) if key_path.is_file() => { + match self.key_path(key)? { + key_path if key_path.is_file() => { // Load user override - fs::read_to_string(key_path).map_err(|err| Error::GetKey(key.to_string(), err))? - } - _ => { - // Load system default - let default_path = self.default_path(key)?; - fs::read_to_string(default_path) - .map_err(|err| Error::GetKey(key.to_string(), err))? + let data = fs::read_to_string(key_path) + .map_err(|err| Error::GetKey(key.to_string(), err))?; + + Ok(ron::from_str(&data)?) } - }; - let t = ron::from_str(&data)?; - Ok(t) + + _ => Err(Error::NotFound), + } + } + + fn get_system_default(&self, key: &str) -> Result { + // Load system default + let default_path = self.default_path(key)?; + let data = + fs::read_to_string(default_path).map_err(|err| Error::GetKey(key.to_string(), err))?; + Ok(ron::from_str(&data)?) } }