From 27c50992e3bc8d4297dbe743c3636abaa55095b8 Mon Sep 17 00:00:00 2001 From: Will Hutchinson Date: Sat, 15 Jun 2024 11:24:56 -0400 Subject: [PATCH] feat: env vars in path (#4) * add: regex crate * feat: add in ability to use {{ENV_VAR}} inside of the path * chg: update documentation to include env var usage --- Cargo.lock | 43 +++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 1 + README.md | 12 ++++++++++-- src/cache.rs | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 98 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7d4b0a0..df74a1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "anstream" version = "0.3.2" @@ -132,6 +141,7 @@ version = "0.3.0" dependencies = [ "anyhow", "clap", + "regex", "serde", "serde_json", "sha2", @@ -333,9 +343,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "miniz_oxide" @@ -438,6 +448,35 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + [[package]] name = "rustc-demangle" version = "0.1.24" diff --git a/Cargo.toml b/Cargo.toml index 3d028ea..2171c07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ keywords = [ [dependencies] anyhow = "1.0.72" clap = { version="4.3.12", features=["derive"] } +regex = "1.10.4" serde = {version = "1.0.171", features = ["derive"]} serde_json = "1.0.117" sha2 = "0.10.8" diff --git a/README.md b/README.md index 0ae70c6..5842bf8 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ A simple configurable cd wrapper that provides powerful utilities for customizin ## Features -- **Per Directory Environment Variables** +- **Per Directory Environment Variables** - **Auto Load .env files in Directories** - **Auto Execute Commands in Directories** - **Per Directory Aliases** @@ -178,7 +178,7 @@ dirs = [ ] ``` -## Configuration +## Configuration ### Global Configuration Options ```toml [config] @@ -244,6 +244,14 @@ dirs = [ ] ``` +### Using CDWE Environment Variables in the paths + +If you want to use something like **$HOME** or any other environment variable +set in a path, you can do so by wrapping the environment variable inside of +`{{}}`. Using **$HOME** as an example, you would do {{HOME}}. This can make +using one cdwe.toml across many machines nice if you have different users but a +similar directory structure for each user. + ## Uninstalling 1. Run cdwe-remove to clean up all shell artifacts ```bash diff --git a/src/cache.rs b/src/cache.rs index 29454c0..fea4077 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -23,6 +23,19 @@ pub struct Cache { values: DirCacheMap, } +/// Inserts any cdwe path environment variables into itself and returns +/// updated path +fn insert_env_var_into_path(re: ®ex::Regex, path: &str) -> String { + re.replace_all(path, |caps: ®ex::Captures| { + if let Some(value) = std::env::var(&caps[1]).ok() { + value // If the env var exists, replace with its value + } else { + caps[0].to_string() // If not, keep the original text + } + }) + .to_string() +} + impl Cache { pub fn new(shell: String, hash: String, values: DirCacheMap) -> Self { Cache { @@ -35,6 +48,9 @@ impl Cache { pub fn from_config(config: &Config, config_hash: &str) -> Self { let mut values: DirCacheMap = HashMap::new(); + // Captures the content within {{}} + let re = regex::Regex::new(r"\{\{(.*?)\}\}").unwrap(); + for directory in &config.directories { let variables: Vec = match &directory.vars { Some(EnvVariableStruct::HashMap(hash_map)) => hash_map @@ -67,7 +83,8 @@ impl Cache { aliases, }; - values.insert(directory.path.clone(), dir_cache); + let result = insert_env_var_into_path(&re, directory.path.as_str()); + values.insert(result, dir_cache); } let shell = match &config.config { @@ -116,3 +133,31 @@ pub fn write_cache(cache: &Cache, home: &str) -> Result<()> { Ok(()) } + +#[cfg(test)] +mod tests { + use super::insert_env_var_into_path; + + #[test] + fn test_insert_env_var_into_path() { + let re = regex::Regex::new(r"\{\{(.*?)\}\}").unwrap(); + std::env::set_var("TEST_HOME", "/home/user"); + std::env::set_var("TEST_NAME", "testing"); + assert_eq!( + insert_env_var_into_path(&re, "{{TEST_HOME}}/testing"), + "/home/user/testing" + ); + assert_eq!( + insert_env_var_into_path(&re, "{{TEST_HOME}}/{{TEST_NAME}}"), + "/home/user/testing" + ); + assert_eq!( + insert_env_var_into_path(&re, "{{DOES_NOT_EXIST}}/{{TEST_NAME}}"), + "{{DOES_NOT_EXIST}}/testing" + ); + assert_eq!( + insert_env_var_into_path(&re, "/home/user/testing"), + "/home/user/testing" + ); + } +}