mirror of
https://github.com/Steffo99/micronfig.git
synced 2024-11-21 15:44:20 +00:00
Improve and fix documentation
This commit is contained in:
parent
d414d3cc90
commit
a457be6a31
4 changed files with 114 additions and 34 deletions
22
src/any.rs
22
src/any.rs
|
@ -5,14 +5,14 @@ use crate::var;
|
||||||
use crate::file;
|
use crate::file;
|
||||||
|
|
||||||
|
|
||||||
/// Get a configuration value from the first available source and convert it to the given `Type`, additionally returning information about how the value was retrieved.
|
/// Get a value from the first available source and convert it to the given `Type`, additionally returning information about how the value was retrieved.
|
||||||
///
|
///
|
||||||
/// # Process
|
/// # Process
|
||||||
///
|
///
|
||||||
/// This function tries to get a configuration value:
|
/// This function tries to get a configuration value:
|
||||||
///
|
///
|
||||||
/// 1. with [`var::get`] using `name`, returning a [`Source::Var`]
|
/// 1. with [`var::get`] using `key`, returning a [`Source::Var`]
|
||||||
/// 2. with [`file::get`] using `name + file_suffix`, returning a [`Source::File`]
|
/// 2. with [`file::get`] using `key + key_suffix_file`, returning a [`Source::File`]
|
||||||
///
|
///
|
||||||
/// If none of these options successfully resulted in the successful retrieval of the configuration value, [`Source::NotFound`] is returned instead.
|
/// If none of these options successfully resulted in the successful retrieval of the configuration value, [`Source::NotFound`] is returned instead.
|
||||||
///
|
///
|
||||||
|
@ -50,23 +50,23 @@ use crate::file;
|
||||||
/// if let Source::NotFound = value {} else { panic!() }
|
/// if let Source::NotFound = value {} else { panic!() }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
pub fn get<KeyVar, KeyFile, Type>(name: KeyVar, file_suffix: KeyFile) -> Source<Type>
|
pub fn get<Key, KeySuffixFile, Type>(key: Key, key_suffix_file: KeySuffixFile) -> Source<Type>
|
||||||
where KeyVar: AsRef<std::ffi::OsStr>,
|
where Key: AsRef<std::ffi::OsStr>,
|
||||||
KeyFile: AsRef<std::ffi::OsStr>,
|
KeySuffixFile: AsRef<std::ffi::OsStr>,
|
||||||
Type: std::str::FromStr,
|
Type: std::str::FromStr,
|
||||||
<Type as std::str::FromStr>::Err: std::fmt::Debug,
|
<Type as std::str::FromStr>::Err: std::fmt::Debug,
|
||||||
{
|
{
|
||||||
let v = var::get(&name);
|
let v = var::get(&key);
|
||||||
|
|
||||||
match v {
|
match v {
|
||||||
Err(var::Error::CannotReadEnvVar(_)) => {},
|
Err(var::Error::CannotReadEnvVar(_)) => {},
|
||||||
_ => return Source::Var(v),
|
_ => return Source::Var(v),
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut name_file = OsString::new();
|
let mut key_file = OsString::new();
|
||||||
name_file.push(name);
|
key_file.push(key);
|
||||||
name_file.push(file_suffix);
|
key_file.push(key_suffix_file);
|
||||||
let v = file::get(name_file);
|
let v = file::get(key_file);
|
||||||
|
|
||||||
match v {
|
match v {
|
||||||
Err(file::Error::CannotReadEnvVar(_)) => {},
|
Err(file::Error::CannotReadEnvVar(_)) => {},
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
//! Module defining the [`get`] low-level function for environment files, and its associated types.
|
//! Module defining the [`get`] low-level function for environment files, and its associated types.
|
||||||
|
|
||||||
|
|
||||||
/// Get a configuration value from the file at the path contained in the environment variable with the given `name`, and convert it to the desired `Type`.
|
/// Get a configuration value from the file at the path contained in the environment variable with the given `key`, and convert it to the desired `Type`.
|
||||||
pub fn get<Key, Type>(name: Key) -> Result<Type>
|
pub fn get<Key, Type>(key: Key) -> Result<Type>
|
||||||
where Key: AsRef<std::ffi::OsStr>,
|
where Key: AsRef<std::ffi::OsStr>,
|
||||||
Type: std::str::FromStr,
|
Type: std::str::FromStr,
|
||||||
<Type as std::str::FromStr>::Err: std::fmt::Debug,
|
<Type as std::str::FromStr>::Err: std::fmt::Debug,
|
||||||
{
|
{
|
||||||
let path = std::env::var(name)
|
let path = std::env::var(key)
|
||||||
.map_err(Error::CannotReadEnvVar)?;
|
.map_err(Error::CannotReadEnvVar)?;
|
||||||
let path = std::ffi::OsString::from(path);
|
let path = std::ffi::OsString::from(path);
|
||||||
let path = std::path::PathBuf::from(path);
|
let path = std::path::PathBuf::from(path);
|
||||||
|
|
114
src/lib.rs
114
src/lib.rs
|
@ -1,24 +1,104 @@
|
||||||
//! Tiny crate for [twelve-factor app configuration](https://12factor.net/config).
|
//! Tiny crate for [twelve-factor app configuration](https://12factor.net/config).
|
||||||
//!
|
//!
|
||||||
//! # Goals
|
|
||||||
//!
|
|
||||||
//! This crate aims to simplify developing and deploying Docker-compatible services in Rust.
|
|
||||||
//!
|
|
||||||
//! # Features
|
//! # Features
|
||||||
//!
|
//!
|
||||||
//! This crate handles:
|
//! This crate handles:
|
||||||
//!
|
//!
|
||||||
//! 1. Retrieval of configuration values from multiple sources
|
//! - Retrieval of values of configuration properties from multiple sources, such as environment variables or files
|
||||||
//! 1. The environment
|
//! - Parsing of retrieved data
|
||||||
//! 2. Files specified in the environment
|
//! - Displaying human-readable errors if case a step does not succeed
|
||||||
//! 2. Conversion to a value of an arbitrary type
|
//!
|
||||||
//! 3. Displaying a operator-friendly error if case one of this steps did not succeed
|
//! # Usage
|
||||||
|
//!
|
||||||
|
//! Each configurable property of the dependent binary must have an arbitrary *key*, a name used to define its value, usually in `SCREAMING_SNAKE_CASE`.
|
||||||
|
//!
|
||||||
|
//! For example, some keys may be:
|
||||||
|
//!
|
||||||
|
//! - `TELEGRAM_API_KEY`
|
||||||
|
//! - `OAUTH2_CLIENT_SECRET`
|
||||||
|
//! - `SCREEN_RESOLUTION`
|
||||||
|
//!
|
||||||
|
//! ## High-level API
|
||||||
|
//!
|
||||||
|
//! The recommended usage of this crate is via the high-level API, which comprises the [`required`] and [`optional`] functions.
|
||||||
|
//!
|
||||||
|
//! They automatically try to retrieve a value from the following sources, in this order, returning as soon as one is found:
|
||||||
|
//!
|
||||||
|
//! 1. the contents of the environment variable `{key}`;
|
||||||
|
//! 2. the contents of the file located at path specified in the environment variable `{key}_FILE`.
|
||||||
|
//!
|
||||||
|
//! If no value is found, or if an error occurred while trying to retrieve it, the function panics with a human-readable error message.
|
||||||
|
//!
|
||||||
|
//! Additionally, they try to parse the value into the requested Rust type using its [`FromStr`] trait.
|
||||||
|
//!
|
||||||
|
//! If the conversion fails, the function panics, again providing a human-readable error message.
|
||||||
|
//!
|
||||||
|
//! ### Examples
|
||||||
|
//!
|
||||||
|
//! To require a `IP_ADDRESS` property to be configured, and to parse it as an [`IpAddr`], you may write the following code:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! use std::net::IpAddr;
|
||||||
|
//!
|
||||||
|
//! # std::env::set_var("IP_ADDRESS", "192.168.1.1");
|
||||||
|
//! let ip_addr: IpAddr = micronfig::required("IP_ADDRESS");
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! To allow the user to not specify it, and provide a default, you may write:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! use std::net::{IpAddr, Ipv4Addr};
|
||||||
|
//!
|
||||||
|
//! # std::env::remove_var("IP_ADDRESS");
|
||||||
|
//! let ip_addr: IpAddr = micronfig::optional("IP_ADDRESS").unwrap_or(IpAddr::V4(Ipv4Addr::LOCALHOST));
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Middle-level API
|
||||||
|
//!
|
||||||
|
//! If you want more control on how errors are handled or on how the key is manipulated to access values, you can use the middle-level API, comprised of the [`any::get`] function and the [`any::Source`] enum.
|
||||||
|
//!
|
||||||
|
//! [`any::get`] works similarly to the [`required`] and [`optional`] functions, but returns a [`any::Source`] enum variant instead, which denotes the source a result was obtained from, and contains the raw [`Result`] of the operation.
|
||||||
|
//!
|
||||||
|
//! ### Example
|
||||||
|
//!
|
||||||
|
//! To customize the handling of the same `IP_ADDRESS` as earlier, so that something is printed instead of the binary panicking, you may write the following code:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! use std::net::IpAddr;
|
||||||
|
//! use micronfig::any::{get, Source};
|
||||||
|
//!
|
||||||
|
//! let ip_addr: Source<IpAddr> = get("IP_ADDRESS", "_FILE");
|
||||||
|
//!
|
||||||
|
//! match ip_addr {
|
||||||
|
//! Source::Var(Ok(addr)) | Source::File(Ok(addr)) => println!("Success! · {}", &addr),
|
||||||
|
//! _ => println!("Failure..."),
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Low-level API
|
||||||
|
//!
|
||||||
|
//! Finally, if you want to override the accessed sources, you may use the low level API directly, comprised of the following modules:
|
||||||
|
//!
|
||||||
|
//! - [`var`] for accessing environment variable
|
||||||
|
//! - [`file`] for accessing files with the path defined in environment variables
|
||||||
|
//!
|
||||||
|
//! ### Example
|
||||||
|
//!
|
||||||
|
//! To retrieve the `IP_ADDRESS` only from the environment variable, and ignoring other sources:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! use std::net::IpAddr;
|
||||||
|
//! use micronfig::var::get;
|
||||||
|
//!
|
||||||
|
//! # std::env::set_var("IP_ADDRESS", "192.168.1.1");
|
||||||
|
//! let ip_addr: IpAddr = get("IP_ADDRESS").expect("IP_ADDRESS envvar to be defined");
|
||||||
|
//! ```
|
||||||
|
|
||||||
pub mod any;
|
pub mod any;
|
||||||
pub mod var;
|
pub mod var;
|
||||||
pub mod file;
|
pub mod file;
|
||||||
|
|
||||||
/// Get the configuration value with the given `name` and convert it to the given `Type`.
|
/// Get the configuration value with the given `key` and convert it to the given `Type`.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
|
@ -50,31 +130,31 @@ pub mod file;
|
||||||
///
|
///
|
||||||
/// [`any::get`], the function called by this one to get the configuration value.
|
/// [`any::get`], the function called by this one to get the configuration value.
|
||||||
///
|
///
|
||||||
pub fn required<Type>(name: &str) -> Type
|
pub fn required<Type>(key: &str) -> Type
|
||||||
where Type: std::str::FromStr,
|
where Type: std::str::FromStr,
|
||||||
<Type as std::str::FromStr>::Err: std::fmt::Debug,
|
<Type as std::str::FromStr>::Err: std::fmt::Debug,
|
||||||
{
|
{
|
||||||
use crate::any::{get, Source};
|
use crate::any::{get, Source};
|
||||||
|
|
||||||
match get(name, "_FILE") {
|
match get(key, "_FILE") {
|
||||||
Source::Var(Ok(v)) => v,
|
Source::Var(Ok(v)) => v,
|
||||||
Source::Var(Err(var::Error::CannotConvertValue(err))) =>
|
Source::Var(Err(var::Error::CannotConvertValue(err))) =>
|
||||||
panic!("The contents of the {} environment variable could not be converted to a {}: {:?}", &name, &std::any::type_name::<Type>(), &err),
|
panic!("The contents of the {} environment variable could not be converted to a {}: {:?}", &key, &std::any::type_name::<Type>(), &err),
|
||||||
Source::Var(Err(var::Error::CannotReadEnvVar(_))) =>
|
Source::Var(Err(var::Error::CannotReadEnvVar(_))) =>
|
||||||
panic!("Something unexpected happened in micronfig. Please report this as a bug!"),
|
panic!("Something unexpected happened in micronfig. Please report this as a bug!"),
|
||||||
|
|
||||||
Source::File(Ok(v)) => v,
|
Source::File(Ok(v)) => v,
|
||||||
Source::File(Err(file::Error::CannotConvertValue(err))) =>
|
Source::File(Err(file::Error::CannotConvertValue(err))) =>
|
||||||
panic!("The contents of the file at {} could not be converted to a {}: {:?}", &name, &std::any::type_name::<Type>(), &err),
|
panic!("The contents of the file at {} could not be converted to a {}: {:?}", &key, &std::any::type_name::<Type>(), &err),
|
||||||
Source::File(Err(file::Error::CannotOpenFile(err))) =>
|
Source::File(Err(file::Error::CannotOpenFile(err))) =>
|
||||||
panic!("The file at {} could not be opened: {}", &name, &err),
|
panic!("The file at {} could not be opened: {}", &key, &err),
|
||||||
Source::File(Err(file::Error::CannotReadFile(err))) =>
|
Source::File(Err(file::Error::CannotReadFile(err))) =>
|
||||||
panic!("The contents of the file at {} could not be read: {}", &name, &err),
|
panic!("The contents of the file at {} could not be read: {}", &key, &err),
|
||||||
Source::File(Err(file::Error::CannotReadEnvVar(_))) =>
|
Source::File(Err(file::Error::CannotReadEnvVar(_))) =>
|
||||||
panic!("Something unexpected happened in micronfig. Please report this as a bug!"),
|
panic!("Something unexpected happened in micronfig. Please report this as a bug!"),
|
||||||
|
|
||||||
Source::NotFound =>
|
Source::NotFound =>
|
||||||
panic!("The configuration value {} is not defined.", &name),
|
panic!("The configuration value {} is not defined.", &key),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
//! Module defining the [`get`] low-level function for environment variables, and its associated types.
|
//! Module defining the [`get`] low-level function for environment variables, and its associated types.
|
||||||
|
|
||||||
|
|
||||||
/// Get a configuration value from the environment variable with the given `name`, and convert it to the desired `Type`.
|
/// Get a configuration value from the environment variable with the given `key`, and convert it to the desired `Type`.
|
||||||
pub fn get<Key, Type>(name: Key) -> Result<Type>
|
pub fn get<Key, Type>(key: Key) -> Result<Type>
|
||||||
where Key: AsRef<std::ffi::OsStr>,
|
where Key: AsRef<std::ffi::OsStr>,
|
||||||
Type: std::str::FromStr,
|
Type: std::str::FromStr,
|
||||||
<Type as std::str::FromStr>::Err: std::fmt::Debug,
|
<Type as std::str::FromStr>::Err: std::fmt::Debug,
|
||||||
{
|
{
|
||||||
let data = std::env::var(name)
|
let data = std::env::var(key)
|
||||||
.map_err(Error::CannotReadEnvVar)?;
|
.map_err(Error::CannotReadEnvVar)?;
|
||||||
|
|
||||||
let value = Type::from_str(&data)
|
let value = Type::from_str(&data)
|
||||||
|
|
Loading…
Reference in a new issue