8个版本
0.4.2 | 2022年12月10日 |
---|---|
0.4.1 | 2020年2月23日 |
0.3.2 | 2018年10月16日 |
0.3.0 | 2018年9月11日 |
0.1.0 | 2018年8月6日 |
#1349 in 编码
每月44次下载
用于 libdeadmock
43KB
792 行
tomlenv
从TOML文件生成特定运行时配置。
lib.rs
:
tomlenv
允许您使用TOML来驱动环境配置。 Environments
结构体持有一个从您的环境层次结构到特定环境相关配置的引用,即。
prod_key
->prod_config
stage_key
->stage_config
dev_key
->dev_config
在键的方面,您可以使用由该库定义的 Environment
层次结构(Prod -> Stage -> Test -> Dev -> Local),或者您可以定义自己的自定义层次结构以与 Environments
结构体一起使用。如果您定义了自定义层次结构,您必须实现 Deserialize
、Serialize
、Ord
、PartialOrd
和 TryFrom<String>
特性。更多信息请参见下面的 自定义环境层次结构 部分。
用法
首先,定义一个表示您的环境配置的结构体。对于在某个环境中出现但在另一个环境中不出现的项,使用 Option
。请参见下面的示例中的键字段。
其次,从您的TOML生成一个 Reader
。通常,TOML 被定义为 Path
,并使用 from_path
方法。您还可以向 from_reader
方法提供一个泛型 Read
实现如下。
第三,将TOML反序列化为你的Environments
结构体。在这个阶段,你可以使用current
方法来访问由环境变量env
指定的环境的配置。
#
/// Define your environment specific configuration.
/// *NOTE*: This must implement `Deserialize` and `Serialize`
#[derive(Debug, Deserialize, Getters, Serialize)]
struct MyAppEnv {
/// The display name of this environment.
#[get]
name: String,
/// The secret key only used in the Prod environment.
#[get]
key: Option<String>,
}
/// Grab your environment TOML. This would usually be in a file and can
/// be read to a string such as below.
let toml = r#"[envs.prod]
name = "Production"
key = "abcd-123-efg-45"
[envs.stage]
name = "Stage"
[envs.test]
name = "Test"
[envs.dev]
name = "Development"
[envs.local]
name = "Local"
"#;
// Deserialize the TOML config into your environment structs. This example
// is using the `Enrivorment` hierarchy supplied by the library.
let mut cursor = Cursor::new(toml);
let envs: Environments<Environment, MyAppEnv> = Environments::from_reader(&mut cursor)?;
// Check the `Production` environment.
env::set_var("env", "prod");
let mut current = envs.current()?;
assert_eq!(current.name(), "Production");
assert_eq!(current.key(), &Some("abcd-123-efg-45".to_string()));
// Switch to the `Development` environment.
env::set_var("env", "dev");
current = envs.current()?;
assert_eq!(current.name(), "Development");
assert_eq!(current.key(), &None);
自定义环境层次结构
如果你不想使用此库提供的Environment
层次结构,请实现一个自定义的层次结构。为了与Environments
一起工作,你必须实现几个特性。
必需
Deserialize
和Serialize
:这些特性用于将数据从TOML中转换出来或转换到TOML。Ord
和PartialOrd
:这些特性用于维护层次结构的正确排序,并确保序列化的TOML始终以相同的顺序。TryFrom<String>
:此特性用于将环境变量env
转换为你的层次结构类型。
可选
Display
:用于将你的层次结构类型转换为格式化的字符串。如果你需要显示正在使用哪个环境,这很有用。TryFrom<&'a str>
:在这种情况下,由自定义反序列化器使用。
下面是一个自定义层次结构的示例。此示例包含自定义序列化器/反序列化器,但这并不是所有情况都必要的。
#
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum MyHierarchy {
/// Production
Prod,
/// Certification
Cert,
/// Sandbox
Sandbox,
/// Local
Local,
}
impl fmt::Display for MyHierarchy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let env = match *self {
MyHierarchy::Prod => "prod",
MyHierarchy::Cert => "ce",
MyHierarchy::Sandbox => "sb",
MyHierarchy::Local => "local",
};
write!(f, "{}", env)
}
}
impl<'a> TryFrom<&'a str> for MyHierarchy {
type Error = Error;
fn try_from(env: &str) -> Result<Self> {
match env {
"prod" => Ok(MyHierarchy::Prod),
"ce" => Ok(MyHierarchy::Cert),
"sb" => Ok(MyHierarchy::Sandbox),
"local" => Ok(MyHierarchy::Local),
_ => Err(Error::invalid_runtime_environment(env)),
}
}
}
impl TryFrom<String> for MyHierarchy {
type Error = Error;
fn try_from(env: String) -> Result<Self> {
match &env[..] {
"prod" => Ok(MyHierarchy::Prod),
"ce" => Ok(MyHierarchy::Cert),
"sb" => Ok(MyHierarchy::Sandbox),
"local" => Ok(MyHierarchy::Local),
_ => Err(Error::invalid_runtime_environment(&env)),
}
}
}
impl Serialize for MyHierarchy {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl<'de> Deserialize<'de> for MyHierarchy {
fn deserialize<D>(deserializer: D) -> std::result::Result<MyHierarchy, D::Error>
where
D: Deserializer<'de>,
{
struct MyHierarchyVisitor;
impl<'de> de::Visitor<'de> for MyHierarchyVisitor {
type Value = MyHierarchy;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("any valid environment")
}
fn visit_str<E>(self, value: &str) -> std::result::Result<MyHierarchy, E>
where
E: de::Error,
{
TryFrom::try_from(value).map_err(de::Error::custom)
}
}
deserializer.deserialize_string(MyHierarchyVisitor)
}
}
#[derive(Debug, De, Getters, Ser)]
struct MyAppEnv {
/// The display name of this environment.
#[get]
name: String,
/// The secret key only used in the Prod environment.
#[get]
key: Option<String>,
}
#
/// Grab your environment TOML. This would usually be in a file and can
/// be read to a string such as below.
let toml = r#"[envs.prod]
name = "Production"
key = "abcd-123-efg-45"
[envs.ce]
name = "Certification"
[envs.sb]
name = "Sandbox"
[envs.local]
name = "Local"
"#;
// Deserialize the TOML config into your environment structs. This example
// is using the custom `MyHierarchy` hierarchy.
let mut cursor = Cursor::new(toml);
let envs: Environments<MyHierarchy, MyAppEnv> = Environments::from_reader(&mut cursor)?;
// Check the `Production` environment.
env::set_var("env", "prod");
let mut current = envs.current()?;
assert_eq!(current.name(), "Production");
assert_eq!(current.key(), &Some("abcd-123-efg-45".to_string()));
// Switch to the `Sandbox` environment.
env::set_var("env", "sb");
current = envs.current()?;
assert_eq!(current.name(), "Sandbox");
assert_eq!(current.key(), &None);
fn main() {
foo().unwrap()
}
依赖项
~2.5MB
~52K SLoC