From a5d442f7ff5bdb1a8cca613dbb4dd746c7acf336 Mon Sep 17 00:00:00 2001 From: Gerald Pinder Date: Sun, 6 Apr 2025 14:21:17 -0400 Subject: [PATCH] feat: Default env variables --- README.md | 21 +++++++++++++++++++++ macro/src/cmd.rs | 32 +++++++++++++++++++++++++++++--- macro/src/lib.rs | 20 ++++++++++++++++++++ tests/cmd.rs | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4b7226a..9f04c92 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,27 @@ let command = cmd!( assert_eq!(format!("{command:?}"), r#"NEW_VAR="new_var" TEST="test" "echo" "test""#); ``` +#### Conditional +You can have a default value set for an environment variable. + +```rust +use comlexr::cmd; + +const NEW_VAR: &str = "NEW_VAR"; +std::env::set_var("TEST", "realvalue"); + +let command = cmd!( + env { + "TEST":? "test", + NEW_VAR: "new_var" + }; + "echo", + "test", +); + +assert_eq!(format!("{command:?}"), r#"NEW_VAR="new_var" "echo" "test""#); +``` + #### Current Directory and Env Variable Order Matters Environment variable declarations **MUST** come after the current directory declaration. diff --git a/macro/src/cmd.rs b/macro/src/cmd.rs index 7f2cbd5..bcfda32 100644 --- a/macro/src/cmd.rs +++ b/macro/src/cmd.rs @@ -437,23 +437,49 @@ impl ToTokens for EnvVars { struct EnvVar { key: Value, value: Value, + conditional: bool, } impl Parse for EnvVar { fn parse(input: syn::parse::ParseStream) -> syn::Result { let key = input.parse()?; + _ = input.parse::()?; + + let conditional = if input.lookahead1().peek(Token![?]) { + input.parse::()?; + true + } else { + false + }; + let value = input.parse()?; - Ok(Self { key, value }) + Ok(Self { + key, + value, + conditional, + }) } } impl ToTokens for EnvVar { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - let Self { key, value } = self; + let Self { + key, + value, + conditional, + } = self; - tokens.extend(quote! { _c.env(#key, #value); }); + if *conditional { + tokens.extend(quote! { + if ::std::env::var(#key).ok().is_none() { + _c.env(#key, #value); + } + }); + } else { + tokens.extend(quote! { _c.env(#key, #value); }); + } } } diff --git a/macro/src/lib.rs b/macro/src/lib.rs index c6593f9..0535a45 100644 --- a/macro/src/lib.rs +++ b/macro/src/lib.rs @@ -56,6 +56,26 @@ mod pipe; /// assert_eq!(format!("{command:?}"), r#"NEW_VAR="new_var" TEST="test" "echo" "test""#); /// ``` /// +/// #### Conditional +/// You can have a default value set for an environment variable. +/// +/// ```rust +/// # use comlexr_macro::cmd; +/// const NEW_VAR: &str = "NEW_VAR"; +/// std::env::set_var("TEST", "realvalue"); +/// +/// let command = cmd!( +/// env { +/// "TEST":? "test", +/// NEW_VAR: "new_var" +/// }; +/// "echo", +/// "test", +/// ); +/// +/// assert_eq!(format!("{command:?}"), r#"NEW_VAR="new_var" "echo" "test""#); +/// ``` +/// /// ### Current Directory and Environment Variable Order /// ``` /// # use comlexr_macro::cmd; diff --git a/tests/cmd.rs b/tests/cmd.rs index ba4bc41..320b092 100644 --- a/tests/cmd.rs +++ b/tests/cmd.rs @@ -1,6 +1,8 @@ extern crate comlexr; extern crate rstest; +use std::env; + use comlexr::cmd; use rstest::rstest; @@ -35,6 +37,37 @@ fn env_vars() { assert_eq!(format!("{command:?}"), r#"TEST="test" "echo" "test""#); } +#[test] +fn conditional_env_vars() { + env::set_var("TEST", "realvalue"); + env::set_var("TEST2", "won't see"); + + let command = cmd!( + env { + "TEST":? "test", + "TEST2": "test2" + }; + "echo", + "test", + ); + + assert_eq!(format!("{command:?}"), r#"TEST2="test2" "echo" "test""#); + + let command = cmd!( + env { + "TEST": "test", + "TEST2": "test2" + }; + "echo", + "test", + ); + + assert_eq!( + format!("{command:?}"), + r#"TEST="test" TEST2="test2" "echo" "test""# + ); +} + #[test] fn cd_env_vars() { let command = cmd!(