Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions examples/async_source/main.rs → examples/async_source.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Example below presents sample configuration server and client.

use std::{error::Error, fmt::Debug};

use async_trait::async_trait;
Expand All @@ -7,11 +9,6 @@ use config::{
use futures::{FutureExt, select};
use warp::Filter;

// Example below presents sample configuration server and client.
//
// Server serves simple configuration on HTTP endpoint.
// Client consumes it using custom HTTP AsyncSource built on top of reqwest.

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
select! {
Expand All @@ -20,6 +17,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
}
}

/// Serve simple configuration on HTTP endpoint.
async fn run_server() -> Result<(), Box<dyn Error>> {
let service = warp::path("configuration").map(|| r#"{ "value" : 123 }"#);

Expand All @@ -30,6 +28,7 @@ async fn run_server() -> Result<(), Box<dyn Error>> {
Ok(())
}

/// Consumes the server's configuration using custom HTTP `AsyncSource` built on top of reqwest.
async fn run_client() -> Result<(), Box<dyn Error>> {
// Good enough for an example to allow server to start
tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
Expand All @@ -47,8 +46,7 @@ async fn run_client() -> Result<(), Box<dyn Error>> {
Ok(())
}

// Actual implementation of AsyncSource can be found below

/// `AsyncSource` to read configuration from an HTTP server
#[derive(Debug)]
struct HttpSource<F: Format> {
uri: String,
Expand Down
4 changes: 2 additions & 2 deletions examples/custom_file_format/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ fn main() {

// Deserialize the config object into your Settings struct:
let settings: Settings = settings.try_deserialize().unwrap();

println!("{settings:#?}");
}

Expand Down Expand Up @@ -65,8 +66,7 @@ impl Format for PemFile {
}
}

// A slice of extensions associated to this format, when an extension
// is omitted from a file source, these will be tried implicitly:
// When an extension is omitted from a file source, these will be tried implicitly:
impl FileStoredFormat for PemFile {
fn file_extensions(&self) -> &'static [&'static str] {
&["pem"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use config::{Config, File, FileStoredFormat, Format, Map, Value, ValueKind};

fn main() {
let config = Config::builder()
.add_source(File::from_str("bad", MyFormat))
.add_source(File::from_str("good", MyFormat))
.add_source(File::from_str("bad", CustomFormat))
.add_source(File::from_str("good", CustomFormat))
.build();

match config {
Expand All @@ -13,9 +13,9 @@ fn main() {
}

#[derive(Debug, Clone)]
pub struct MyFormat;
pub struct CustomFormat;

impl Format for MyFormat {
impl Format for CustomFormat {
fn parse(
&self,
uri: Option<&String>,
Expand All @@ -40,11 +40,14 @@ impl Format for MyFormat {
}
}

// As strange as it seems for config sourced from a string, legacy demands its sacrifice
// It is only required for File source, custom sources can use Format without caring for extensions
static MY_FORMAT_EXT: Vec<&'static str> = vec![];
impl FileStoredFormat for MyFormat {
impl FileStoredFormat for CustomFormat {
fn file_extensions(&self) -> &'static [&'static str] {
&MY_FORMAT_EXT
&NO_EXTS
}
}

/// In-memory format doesn't have any file extensions
///
/// It is only required for File source,
/// custom sources can use Format without caring for extensions
static NO_EXTS: Vec<&'static str> = vec![];
24 changes: 0 additions & 24 deletions examples/env-list/main.rs

This file was deleted.

67 changes: 0 additions & 67 deletions examples/glob/main.rs

This file was deleted.

10 changes: 0 additions & 10 deletions examples/hierarchical-env/main.rs

This file was deleted.

63 changes: 35 additions & 28 deletions examples/hierarchical-env/settings.rs → examples/modal/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,11 @@ use std::env;
use config::{Config, ConfigError, Environment, File};
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[allow(unused)]
struct Database {
url: String,
}
fn main() {
let settings = Settings::new();

#[derive(Debug, Deserialize)]
#[allow(unused)]
struct Sparkpost {
key: String,
token: String,
url: String,
version: u8,
}

#[derive(Debug, Deserialize)]
#[allow(unused)]
struct Twitter {
consumer_token: String,
consumer_secret: String,
}

#[derive(Debug, Deserialize)]
#[allow(unused)]
struct Braintree {
merchant_id: String,
public_key: String,
private_key: String,
// Print out our settings
println!("{settings:?}");
}

#[derive(Debug, Deserialize)]
Expand Down Expand Up @@ -62,7 +39,7 @@ impl Settings {
.add_source(File::with_name("examples/hierarchical-env/config/local").required(false))
// Add in settings from the environment (with a prefix of APP)
// Eg.. `APP_DEBUG=1 ./target/app` would set the `debug` key
.add_source(Environment::with_prefix("app"))
.add_source(Environment::with_prefix("APP"))
// You may also programmatically change settings
.set_override("database.url", "postgres://")?
.build()?;
Expand All @@ -75,3 +52,33 @@ impl Settings {
s.try_deserialize()
}
}

#[derive(Debug, Deserialize)]
#[allow(unused)]
struct Database {
url: String,
}

#[derive(Debug, Deserialize)]
#[allow(unused)]
struct Sparkpost {
key: String,
token: String,
url: String,
version: u8,
}

#[derive(Debug, Deserialize)]
#[allow(unused)]
struct Twitter {
consumer_token: String,
consumer_secret: String,
}

#[derive(Debug, Deserialize)]
#[allow(unused)]
struct Braintree {
merchant_id: String,
public_key: String,
private_key: String,
}
File renamed without changes.
23 changes: 23 additions & 0 deletions examples/priority/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//! Gather all conf files from conf.d/ using glob and put in 1 merge call.

use std::collections::HashMap;

use config::{Config, File};
use glob::glob;

fn main() {
// Glob results are sorted, ensuring user priority is preserved
let files = glob("examples/glob/conf.d/*")
.unwrap()
.map(|path| File::from(path.unwrap()))
.collect::<Vec<_>>();
let settings = Config::builder().add_source(files).build().unwrap();

// Print out our settings (as a HashMap)
println!(
"\n{:?} \n\n-----------",
settings
.try_deserialize::<HashMap<String, String>>()
.unwrap()
);
}
File renamed without changes.
4 changes: 2 additions & 2 deletions examples/simple/main.rs → examples/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use config::Config;

fn main() {
let settings = Config::builder()
// Add in `./Settings.toml`
.add_source(config::File::with_name("examples/simple/Settings"))
// Add in `./settings.toml`
.add_source(config::File::with_name("examples/settings"))
// Add in settings from the environment (with a prefix of APP)
// Eg.. `APP_DEBUG=1 ./target/app` would set the `debug` key
.add_source(config::Environment::with_prefix("APP"))
Expand Down
31 changes: 19 additions & 12 deletions examples/static_env.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
//! Use `config` as a higher-level API over `std::env::var_os`

use std::sync::OnceLock;

use config::Config;

fn main() {
println!("APP_STRING={:?}", get::<String>("string"));
println!("APP_INT={:?}", get::<i32>("int"));
println!("APP_STRLIST={:?}", get::<Vec<i32>>("strlist"));
}

/// Get a configuration value from the environment
pub fn get<'a, T: serde::Deserialize<'a>>(path: &str) -> Option<T> {
config().get::<T>(path).ok()
}

fn config() -> &'static Config {
static CONFIG: OnceLock<Config> = OnceLock::new();
CONFIG.get_or_init(|| {
Config::builder()
.add_source(config::Environment::with_prefix("APP_NAME").separator("_"))
.add_source(
config::Environment::with_prefix("APP")
.try_parsing(true)
.separator("_")
.list_separator(","),
)
.build()
.unwrap()
})
}

/// Get a configuration value from the static configuration object
pub fn get<'a, T: serde::Deserialize<'a>>(key: &str) -> T {
// You shouldn't probably do it like that and actually handle that error that might happen
// here, but for the sake of simplicity, we do it like this here
config().get::<T>(key).unwrap()
}

fn main() {
println!("{:?}", get::<String>("foo"));
}
Loading
Loading