4 Commits

Author SHA1 Message Date
0cdd0bbc07 chore: Release 2025-04-06 15:05:33 -04:00
a5d442f7ff feat: Default env variables 2025-04-06 14:21:17 -04:00
ac948f193b chore: Release 2025-01-30 22:02:21 -05:00
2d7d6cf641 fix: Better enforce typing for commands 2025-01-30 22:02:07 -05:00
8 changed files with 149 additions and 12 deletions

View File

@@ -2,12 +2,32 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## [1.4.0] - 2025-04-06
### 🚀 Features
- Default env variables
## [1.3.1] - 2025-01-31
### 🐛 Bug Fixes
- Better enforce typing for commands
### ⚙️ Miscellaneous Tasks
- Release
## [1.3.0] - 2025-01-31 ## [1.3.0] - 2025-01-31
### 🚀 Features ### 🚀 Features
- Pipe - Pipe
### ⚙️ Miscellaneous Tasks
- Release
## [1.2.0] - 2025-01-14 ## [1.2.0] - 2025-01-14
### 🚀 Features ### 🚀 Features

4
Cargo.lock generated
View File

@@ -40,7 +40,7 @@ dependencies = [
[[package]] [[package]]
name = "comlexr" name = "comlexr"
version = "1.3.0" version = "1.4.0"
dependencies = [ dependencies = [
"comlexr_macro", "comlexr_macro",
"rstest", "rstest",
@@ -51,7 +51,7 @@ dependencies = [
[[package]] [[package]]
name = "comlexr_macro" name = "comlexr_macro"
version = "1.3.0" version = "1.4.0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View File

@@ -4,7 +4,7 @@ members = ["macro"]
[workspace.package] [workspace.package]
description = "Dynamically build Command objects with conditional expressions" description = "Dynamically build Command objects with conditional expressions"
repository = "https://gitlab.com/wunker-bunker/comlexr" repository = "https://gitlab.com/wunker-bunker/comlexr"
version = "1.3.0" version = "1.4.0"
edition = "2021" edition = "2021"
rust-version = "1.60" rust-version = "1.60"
license = "MIT" license = "MIT"
@@ -43,7 +43,7 @@ pre-release-replacements = [
all-features = true all-features = true
[dependencies] [dependencies]
comlexr_macro = { version = "=1.3.0", path = "./macro" } comlexr_macro = { version = "=1.4.0", path = "./macro" }
thiserror = "1.0.65" thiserror = "1.0.65"
[dev-dependencies] [dev-dependencies]

View File

@@ -8,7 +8,7 @@ Add `comlexr` to your project's `Cargo.toml`:
```toml ```toml
[dependencies] [dependencies]
comlexr = "1.3.0" comlexr = "1.4.0"
``` ```
## MSRV ## MSRV
@@ -185,6 +185,27 @@ let command = cmd!(
assert_eq!(format!("{command:?}"), r#"NEW_VAR="new_var" TEST="test" "echo" "test""#); 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 #### Current Directory and Env Variable Order Matters
Environment variable declarations **MUST** come after the current directory declaration. Environment variable declarations **MUST** come after the current directory declaration.

View File

@@ -437,23 +437,49 @@ impl ToTokens for EnvVars {
struct EnvVar { struct EnvVar {
key: Value, key: Value,
value: Value, value: Value,
conditional: bool,
} }
impl Parse for EnvVar { impl Parse for EnvVar {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let key = input.parse()?; let key = input.parse()?;
_ = input.parse::<Token![:]>()?; _ = input.parse::<Token![:]>()?;
let conditional = if input.lookahead1().peek(Token![?]) {
input.parse::<Token![?]>()?;
true
} else {
false
};
let value = input.parse()?; let value = input.parse()?;
Ok(Self { key, value }) Ok(Self {
key,
value,
conditional,
})
} }
} }
impl ToTokens for EnvVar { impl ToTokens for EnvVar {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { 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); });
}
} }
} }

View File

@@ -56,6 +56,26 @@ mod pipe;
/// assert_eq!(format!("{command:?}"), r#"NEW_VAR="new_var" TEST="test" "echo" "test""#); /// 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 /// ### Current Directory and Environment Variable Order
/// ``` /// ```
/// # use comlexr_macro::cmd; /// # use comlexr_macro::cmd;

View File

@@ -6,7 +6,7 @@ use syn::{
Error, Token, Error, Token,
}; };
use crate::{cmd::Value, macros::enum_to_tokens}; use crate::cmd::Value;
pub struct Pipe { pub struct Pipe {
stdin: Option<Value>, stdin: Option<Value>,
@@ -47,7 +47,7 @@ impl ToTokens for Pipe {
let first_command = commands_iter.next().unwrap(); let first_command = commands_iter.next().unwrap();
let initial = quote! { let initial = quote! {
let mut _c_0 = #first_command; let mut _c_0: #first_command;
_c_0.stdout(::std::process::Stdio::piped()); _c_0.stdout(::std::process::Stdio::piped());
_c_0.stdin(::std::process::Stdio::piped()); _c_0.stdin(::std::process::Stdio::piped());
let mut _child_0 = _c_0.spawn()?; let mut _child_0 = _c_0.spawn()?;
@@ -95,7 +95,7 @@ impl ToTokens for Pipe {
}); });
} }
let mut #com_ident = #command; let mut #com_ident: #command;
#com_ident.stdout(::std::process::Stdio::piped()); #com_ident.stdout(::std::process::Stdio::piped());
#com_ident.stdin(::std::process::Stdio::piped()); #com_ident.stdin(::std::process::Stdio::piped());
@@ -171,4 +171,21 @@ impl Parse for CommandExpr {
} }
} }
enum_to_tokens! {CommandExpr: Macro, Reference, Function, Block} impl ToTokens for CommandExpr {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
tokens.extend(match self {
Self::Macro(macr) => quote! {
::std::process::Command = #macr
},
Self::Reference(refer) => quote! {
&mut ::std::process::Command = #refer
},
Self::Function(fun) => quote! {
::std::process::Command = #fun
},
Self::Block(block) => quote! {
::std::process::Command = #block
},
});
}
}

View File

@@ -1,6 +1,8 @@
extern crate comlexr; extern crate comlexr;
extern crate rstest; extern crate rstest;
use std::env;
use comlexr::cmd; use comlexr::cmd;
use rstest::rstest; use rstest::rstest;
@@ -35,6 +37,37 @@ fn env_vars() {
assert_eq!(format!("{command:?}"), r#"TEST="test" "echo" "test""#); 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] #[test]
fn cd_env_vars() { fn cd_env_vars() {
let command = cmd!( let command = cmd!(