diff --git a/Cargo.lock b/Cargo.lock index f3948c5..692265f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -840,6 +840,41 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.68", +] + +[[package]] +name = "darling_macro" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.68", +] + [[package]] name = "dashmap" version = "5.5.3" @@ -883,6 +918,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", + "serde", ] [[package]] @@ -1086,6 +1122,15 @@ dependencies = [ "log", ] +[[package]] +name = "envsubst" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf2f29f6ee674d1229e5715dfc7e24f14395a20d66949e36032de68b31542643" +dependencies = [ + "thiserror", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -1573,6 +1618,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hmac" version = "0.12.1" @@ -1756,6 +1807,12 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.5.0" @@ -1789,6 +1846,7 @@ dependencies = [ "autocfg", "hashbrown 0.12.3", "rustc-rayon 0.5.0", + "serde", ] [[package]] @@ -2559,6 +2617,7 @@ dependencies = [ "console", "dashmap 6.0.1", "dialoguer", + "envsubst", "figment", "futures", "indicatif", @@ -2668,9 +2727,11 @@ dependencies = [ "kclvm-sema", "logcraft-runtime", "rayon", + "regex", "reqwest", "serde", "serde_json", + "serde_with", "serde_yaml_ng", "similar", "tempfile", @@ -4348,6 +4409,36 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.2.6", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time 0.3.36", +] + +[[package]] +name = "serde_with_macros" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.68", +] + [[package]] name = "serde_yaml" version = "0.9.34+deprecated" diff --git a/Cargo.toml b/Cargo.toml index fb9f7fc..305a648 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,7 @@ indicatif = "0.17" serde_json = "1.0" clap = { version = "4.5", features = ["derive", "env", "cargo"] } figment = { version = "0.10", features = ["yaml", "env"] } +envsubst = "0.2" # Local dependencies logcraft-common = { path = "crates/common", version = "0.1.1" } diff --git a/crates/common/src/utils.rs b/crates/common/src/utils.rs index 15b394d..2c3ebba 100644 --- a/crates/common/src/utils.rs +++ b/crates/common/src/utils.rs @@ -44,3 +44,12 @@ pub fn ensure_kebab_case(name: &str) -> Result<&str> { Ok(name) } + +pub fn env_forbidden_chars(s: &str) -> bool { + for c in s.chars() { + if c == '$' || c == '{' || c == '}' { + return true; + } + } + false +} \ No newline at end of file diff --git a/src/bin/lgc.rs b/src/bin/lgc.rs index 93f2c03..b930831 100644 --- a/src/bin/lgc.rs +++ b/src/bin/lgc.rs @@ -7,7 +7,7 @@ use anyhow::Result; use clap::builder::styling; use clap::{crate_version, Subcommand}; use clap::{CommandFactory, FromArgMatches, Parser}; -use figment::providers::{Format, Yaml}; +use figment::providers::{Env, Format, Yaml}; use figment::Figment; use lgc::commands::{ deploy::DeployCommand, destroy::DestroyCommand, diff::DiffCommand, @@ -15,6 +15,9 @@ use lgc::commands::{ services::ServicesCommands, validate::ValidateCommand, }; use logcraft_common::configuration::{ProjectConfiguration, LGC_CONFIG_PATH}; +use logcraft_common::utils::env_forbidden_chars; +use std::collections::HashMap; +use std::{env, fs}; use std::path::PathBuf; use tracing::Level; use tracing_subscriber::EnvFilter; @@ -89,10 +92,29 @@ impl LogCraftCli { LogCraftCommands::Init(cmd) => return cmd.run(), _ => { let configuration_path = PathBuf::from(LGC_CONFIG_PATH); + if configuration_path.is_file() { + let mut configuration_file = fs::read_to_string(configuration_path)?; + + // Environment variables substitution + if envsubst::is_templated(&configuration_file) { + configuration_file = envsubst::substitute( + configuration_file, + &env::vars() + .filter_map(|(key, value)| { + if !env_forbidden_chars(&key) && !env_forbidden_chars(&value) { + Some((key, value)) + } else { + None + } + }) + .collect::>() + )?; + } + cli.config = match Figment::new() - .merge(Yaml::file(LGC_CONFIG_PATH)) - // .merge(Env::prefixed("LGC_")) + .merge(Yaml::string(&configuration_file)) + .merge(Env::prefixed("LGC_").split("_")) .extract() { Ok(config) => config,