diff --git a/Cargo.lock b/Cargo.lock index ae4cad3..02d33e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -94,6 +94,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + [[package]] name = "anyhow" version = "1.0.62" @@ -873,12 +879,6 @@ dependencies = [ "syn 1.0.99", ] -[[package]] -name = "difflib" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" - [[package]] name = "digest" version = "0.9.0" @@ -1053,15 +1053,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "float-cmp" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" -dependencies = [ - "num-traits", -] - [[package]] name = "fnv" version = "1.0.7" @@ -1095,9 +1086,9 @@ dependencies = [ [[package]] name = "fragile" -version = "1.2.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85dcb89d2b10c5f6133de2efd8c11959ce9dbb46a2f7a4cab208c4eeda6ce1ab" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "fsevent-sys" @@ -1586,18 +1577,18 @@ checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" [[package]] name = "itertools" -version = "0.10.5" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] [[package]] name = "itertools" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" dependencies = [ "either", ] @@ -1828,9 +1819,9 @@ dependencies = [ [[package]] name = "mockall" -version = "0.11.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2be9a9090bc1cac2930688fa9478092a64c6a92ddc6ae0692d46b37d9cab709" +checksum = "43766c2b5203b10de348ffe19f7e54564b64f3d6018ff7648d1e2d6d3a0f0a48" dependencies = [ "cfg-if 1.0.0", "downcast", @@ -1843,14 +1834,14 @@ dependencies = [ [[package]] name = "mockall_derive" -version = "0.11.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d702a0530a0141cf4ed147cf5ec7be6f2c187d4e37fcbefc39cf34116bfe8f" +checksum = "af7cbce79ec385a1d4f54baa90a76401eb15d9cab93685f62e7e9f942aa00ae2" dependencies = [ "cfg-if 1.0.0", "proc-macro2 1.0.74", "quote 1.0.35", - "syn 1.0.99", + "syn 2.0.46", ] [[package]] @@ -1925,25 +1916,19 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "normalize-line-endings" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" - [[package]] name = "north" -version = "0.1.4" +version = "0.1.9" dependencies = [ "aragog", "async-trait", "derive_more", "futures", "hyper", - "itertools 0.11.0", + "itertools 0.12.0", "mockall", - "north-common 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "north-derives 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "north-common 0.0.3", + "north-derives 0.1.2", "poem", "poem-openapi", "rstest", @@ -1976,12 +1961,13 @@ dependencies = [ [[package]] name = "north-common" version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38905c5732e7c0001e8335f4c8a0a8de9ddb3fe40b0e93e727d62cbc858fffdf" dependencies = [ "async-trait", "chrono", "log", "log4rs", - "rstest", "serde", "serde_json", "serde_yaml 0.9.10", @@ -1991,14 +1977,13 @@ dependencies = [ [[package]] name = "north-common" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38905c5732e7c0001e8335f4c8a0a8de9ddb3fe40b0e93e727d62cbc858fffdf" +version = "0.1.9" dependencies = [ "async-trait", "chrono", "log", "log4rs", + "rstest", "serde", "serde_json", "serde_yaml 0.9.10", @@ -2008,7 +1993,7 @@ dependencies = [ [[package]] name = "north-config" -version = "0.0.31" +version = "0.1.9" dependencies = [ "async-std", "async-trait", @@ -2046,7 +2031,7 @@ dependencies = [ [[package]] name = "north-consul" -version = "0.0.3" +version = "0.1.9" dependencies = [ "async-trait", "base64 0.13.0", @@ -2067,8 +2052,10 @@ dependencies = [ [[package]] name = "north-derives" version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc1bad4ded7608abf1bd245dc796aec2a581b2a89fc6705852f2743b64c8b93" dependencies = [ - "north-common 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "north-common 0.0.3", "poem", "quote 1.0.35", "syn 1.0.99", @@ -2076,11 +2063,9 @@ dependencies = [ [[package]] name = "north-derives" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc1bad4ded7608abf1bd245dc796aec2a581b2a89fc6705852f2743b64c8b93" +version = "0.1.9" dependencies = [ - "north-common 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "north-common 0.0.3", "poem", "quote 1.0.35", "syn 1.0.99", @@ -2088,7 +2073,7 @@ dependencies = [ [[package]] name = "north-service" -version = "0.1.1" +version = "0.1.9" dependencies = [ "async-trait", "async-zeroconf", @@ -2668,16 +2653,13 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "predicates" -version = "2.1.1" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c" +checksum = "6dfc28575c2e3f19cb3c73b93af36460ae898d426eba6fc15b9bd2a5220758a0" dependencies = [ - "difflib", - "float-cmp", - "itertools 0.10.5", - "normalize-line-endings", + "anstyle", + "itertools 0.11.0", "predicates-core", - "regex", ] [[package]] diff --git a/crates/north-config/src/config_source.rs b/crates/north-config/src/config_source.rs index d1a3e8c..1ae813f 100644 --- a/crates/north-config/src/config_source.rs +++ b/crates/north-config/src/config_source.rs @@ -102,12 +102,15 @@ pub trait CustomConfigSource: CustomConfigSourceClone + Send + Sync { /// ## Using `Custom` variant with a custom implementation /// /// ``` -/// use north_config::{ConfigSource, CustomConfigSource}; -/// +/// use north_config::{ConfigSource, CustomConfigSource, Error}; +/// #[derive(Clone, Debug)] /// struct MyCustomSource; /// /// impl CustomConfigSource for MyCustomSource { /// // implementation details here +/// fn get_config_value(&self) -> Result { +/// todo!() +/// } /// } /// /// let source = ConfigSource::Custom(Box::new(MyCustomSource)); @@ -333,15 +336,23 @@ pub async fn new_config( /// # Example /// /// ```rust -/// use serde_derive::Deserialize; +/// use north_config::{NorthConfigOptions, NorthConfig, EnvSourceOptions, ConfigSource}; +/// +/// envmnt::set("NORTH_NAMES__0__FIRST", "Run"); /// -/// #[derive(Debug, Deserialize)] +/// let mut env_opts = EnvSourceOptions::default(); +/// env_opts.prefix = Some("NORTH".to_string()); +///#[derive(Clone, serde::Deserialize, serde::Serialize, Debug)] +///struct Names { +/// pub first: String +///} +/// #[derive(Debug, serde::Deserialize, Clone)] /// struct MyConfig { -/// // add fields here +/// pub names: Vec /// } /// -/// let option = NorthConfigOptions::new(); // replace with actual options -/// let config: NorthConfig = new_config(option); +/// let option = NorthConfigOptions::new(vec![ConfigSource::Env(env_opts)]); // replace with actual options +/// let config: NorthConfig = crate::north_config::new_config(option); /// ``` /// /// # Panics @@ -654,12 +665,13 @@ fn resolve_file_source( /// Kebab, /// } /// -/// fn process_envs(option: EnvSourceOptions) -> Result { +/// fn process_envs(option: EnvSourceOptions) -> Result { /// // Implementation goes here +/// Ok(Value::default()) /// } /// ``` fn process_envs(option: EnvSourceOptions) -> Result { - let temp_prefix = option.prefix.unwrap_or_else(|| "NORTH".to_string()); + let temp_prefix = option.prefix.unwrap_or_else(|| "NORTH_".to_string()); let prefix: &str = temp_prefix.as_str(); let nested_separator = option.nested_separator.unwrap_or_else(|| "__".to_string()); @@ -674,16 +686,7 @@ fn process_envs(option: EnvSourceOptions) -> Result { } let new_key = key.strip_prefix(prefix).expect("env var prefix missing"); - let mut dot_key: String = String::new(); - for sub_keys in new_key.split(separator) { - if dot_key.is_empty() { - dot_key.push_str(sub_keys.to_case(case).as_str()); - } else { - dot_key.push('.'); - dot_key.push_str(sub_keys.to_case(case).as_str()); - } - } - + let dot_key: String = new_key.replace(separator.clone(), ".").clone().to_case(case); obj.dot_set(dot_key.as_str(), value).unwrap(); } diff --git a/crates/north-config/src/lib.rs b/crates/north-config/src/lib.rs index f3a3530..fe0105b 100644 --- a/crates/north-config/src/lib.rs +++ b/crates/north-config/src/lib.rs @@ -56,6 +56,7 @@ mod tests { let config_options = NorthConfigOptions { sources: vec![ConfigSource::File( "../../examples/configs/test.{{env}}.json".to_string(), + None, )], }; let config = crate::new_config::(config_options).await; @@ -84,6 +85,7 @@ mod tests { let config_options = NorthConfigOptions { sources: vec![ConfigSource::File( "../../examples/configs/test.{{env}}.json".to_string(), + None, )], }; let config = crate::new_config::(config_options); @@ -97,6 +99,7 @@ mod tests { let config_options = NorthConfigOptions { sources: vec![ConfigSource::File( "../../examples/configs/test.debug.json".to_string(), + None, )], }; let config = crate::new_config::(config_options).await; @@ -125,6 +128,7 @@ mod tests { let config_options = NorthConfigOptions { sources: vec![ConfigSource::File( "../../examples/configs/test.debug.json".to_string(), + None, )], }; let config = crate::new_config::(config_options); @@ -137,8 +141,8 @@ mod tests { async fn merge_and_overwrite_duplicate_keys_from_two_config_file() { let config_options = NorthConfigOptions { sources: vec![ - ConfigSource::File("../../examples/configs/test.debug.json".to_string()), - ConfigSource::File("../../examples/configs/test.release.json".to_string()), + ConfigSource::File("../../examples/configs/test.debug.json".to_string(), None), + ConfigSource::File("../../examples/configs/test.release.json".to_string(), None), ], }; let config = crate::new_config::(config_options).await; @@ -152,8 +156,8 @@ mod tests { fn merge_and_overwrite_duplicate_keys_from_two_config_file() { let config_options = NorthConfigOptions { sources: vec![ - ConfigSource::File("../../examples/configs/test.debug.json".to_string()), - ConfigSource::File("../../examples/configs/test.release.json".to_string()), + ConfigSource::File("../../examples/configs/test.debug.json".to_string(), None), + ConfigSource::File("../../examples/configs/test.release.json".to_string(), None), ], }; let config = crate::new_config::(config_options); @@ -166,8 +170,8 @@ mod tests { fn merge_two_files_from_json_and_yaml_sources() { let config_options = NorthConfigOptions { sources: vec![ - ConfigSource::File("../../examples/configs/test.release.json".to_string()), - ConfigSource::File("../../examples/configs/test.release.yaml".to_string()), + ConfigSource::File("../../examples/configs/test.release.json".to_string(), None), + ConfigSource::File("../../examples/configs/test.release.yaml".to_string(), None), ], }; let config = crate::new_config::(config_options); @@ -181,9 +185,9 @@ mod tests { fn merge_three_files_from_json_toml_and_yaml_sources() { let config_options = NorthConfigOptions { sources: vec![ - ConfigSource::File("../../examples/configs/test.release.json".to_string()), - ConfigSource::File("../../examples/configs/test.release.yaml".to_string()), - ConfigSource::File("../../examples/configs/test.release.toml".to_string()), + ConfigSource::File("../../examples/configs/test.release.json".to_string(), None), + ConfigSource::File("../../examples/configs/test.release.yaml".to_string(), None), + ConfigSource::File("../../examples/configs/test.release.toml".to_string(), None), ], }; let config = crate::new_config::(config_options); @@ -196,8 +200,8 @@ mod tests { fn merge_deep_nested_objects() { let config_options = NorthConfigOptions { sources: vec![ - ConfigSource::File("../../examples/configs/test.release.json".to_string()), - ConfigSource::File("../../examples/configs/test.debug.json".to_string()), + ConfigSource::File("../../examples/configs/test.release.json".to_string(), None), + ConfigSource::File("../../examples/configs/test.debug.json".to_string(), None), ], }; let config = crate::new_config::(config_options); @@ -217,9 +221,12 @@ mod tests { let config_options = NorthConfigOptions { sources: vec![ - ConfigSource::File("../../examples/configs/test.release.json".to_string()), - ConfigSource::File("../../examples/configs/test.debug.json".to_string()), - ConfigSource::Env(EnvSourceOptions::default()), + ConfigSource::File("../../examples/configs/test.release.json".to_string(), None), + ConfigSource::File("../../examples/configs/test.debug.json".to_string(), None), + ConfigSource::Env(EnvSourceOptions{ + prefix: Some("NORTH_".to_string()), + ..Default::default() + }), ], }; let config = crate::new_config::(config_options); @@ -231,6 +238,8 @@ mod tests { assert_eq!(nested.foo, "env foo"); assert_eq!(nested.bar, "env bar"); + envmnt::remove("NORTH_HOST"); + envmnt::remove("NORTH_NESTED__FOO"); destroy_env(); } @@ -280,12 +289,43 @@ mod tests { envmnt::remove("TESTNORTH_NESTED__BAR"); } + #[test] + fn read_deep_array_config_from_env_sources() { + #[derive(Clone, serde::Deserialize, serde::Serialize, Debug)] + struct Names { + pub first: String + } + #[derive(Clone, serde::Deserialize, serde::Serialize, Debug)] + struct TestStr { + pub names: Vec + } + + envmnt::set("NORTH_NAMES__0__FIRST", "Run"); + + let mut env_opts = EnvSourceOptions::default(); + env_opts.prefix = Some("NORTH".to_string()); + + let config_options = NorthConfigOptions { + sources: vec![ConfigSource::Env(env_opts)], + }; + + let config = crate::new_config::(config_options); + let config = config.get_value().clone(); + let names = config.names; + + assert_eq!(names.len(), 1); + assert_eq!(names[0].first, "Run"); + + envmnt::remove("NORTH_NAMES__0__FIRST"); + } + #[cfg(feature = "ron")] #[test] fn read_config_from_ron_source() { let config_options = NorthConfigOptions { sources: vec![ConfigSource::File( "../../examples/configs/test.release.ron".to_string(), + None )], }; let config = crate::new_config::(config_options); diff --git a/crates/north-config/src/utils.rs b/crates/north-config/src/utils.rs index 62b5841..337762a 100644 --- a/crates/north-config/src/utils.rs +++ b/crates/north-config/src/utils.rs @@ -6,11 +6,6 @@ use std::fs; /// - Imports environment variables from the ".env" file in the root directory. /// - Sets the default value for the "RUST_LOG" environment variable if it is not already set. /// - Initializes the logging configuration for the application. -/// -/// # Examples -/// -/// ```rust -/// preamble(); /// ``` pub(crate) fn preamble() { import_env_vars("/.env"); @@ -28,14 +23,6 @@ pub(crate) fn preamble() { /// /// * `file_path` - A string slice containing the path to the file to import. /// -/// # Example -/// -/// ```rust -/// use crate::my_module::import_env_vars; -/// -/// import_env_vars("config.env"); -/// ``` -/// /// # Panics /// /// This function panics if the specified file does not exist or if there is an error while @@ -58,17 +45,6 @@ pub(crate) fn import_env_vars(file_path: &str) { /// # Returns /// /// Returns `true` if a file or directory exists at the given path, and `false` otherwise. -/// -/// # Examples -/// -/// ```rust -/// let exists = path_exists("/path/to/file.txt"); -/// if exists { -/// println!("File exists!"); -/// } else { -/// println!("File does not exist."); -/// } -/// ``` pub(crate) fn path_exists(path: &str) -> bool { fs::metadata(path).is_ok() }