diff --git a/Cargo.lock b/Cargo.lock index d24996f..de45632 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -226,6 +226,7 @@ dependencies = [ "shellexpand", "strum", "syscall-numbers", + "tempfile", "which", ] @@ -416,7 +417,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom", + "getrandom 0.2.8", "once_cell", "tiny-keccak", ] @@ -674,9 +675,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.8" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", "windows-sys 0.52.0", @@ -702,6 +703,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "flate2" version = "1.0.25" @@ -754,6 +761,18 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + [[package]] name = "gimli" version = "0.27.1" @@ -1004,9 +1023,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "line-wrap" @@ -1035,6 +1054,12 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + [[package]] name = "log" version = "0.4.22" @@ -1310,6 +1335,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" version = "0.3.23" @@ -1372,7 +1403,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom", + "getrandom 0.2.8", "redox_syscall", "thiserror", ] @@ -1479,12 +1510,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" dependencies = [ "bitflags 2.4.0", - "errno 0.3.8", + "errno 0.3.14", "libc", "linux-raw-sys 0.4.13", "windows-sys 0.52.0", ] +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags 2.4.0", + "errno 0.3.14", + "libc", + "linux-raw-sys 0.11.0", + "windows-sys 0.52.0", +] + [[package]] name = "rustversion" version = "1.0.11" @@ -1705,6 +1749,19 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "084e382bf467cd3381fdec080d883505792ee0d16a004b1b090abf2db5dc2a29" +[[package]] +name = "tempfile" +version = "3.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix 1.1.3", + "windows-sys 0.52.0", +] + [[package]] name = "termcolor" version = "1.4.0" @@ -1968,6 +2025,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "which" version = "6.0.1" @@ -2239,6 +2305,12 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/Cargo.toml b/Cargo.toml index 3e17bbd..b9ea1ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,3 +56,6 @@ which = "6.0.1" inherits = "release" debug = true split-debuginfo = "packed" + +[dev-dependencies] +tempfile = "3.24.0" diff --git a/src/config/mod.rs b/src/config/mod.rs index 92d7b3a..1807f99 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -97,7 +97,11 @@ impl BoxxyConfig { )) .build()?; - let rules = config.try_deserialize::()?; + let mut rules = config.try_deserialize::()?; + + for rule in &mut rules.rules { + rule.rewrite = shellexpand::env(&rule.rewrite)?.to_string(); + } Ok(rules) } @@ -105,33 +109,33 @@ impl BoxxyConfig { pub fn load_rules_from_cli_flag(rules: &[String]) -> Result { let rules = rules .iter() - .map(|s| { + .map(|s| -> Result { let parts: Vec<&str> = s.split(':').collect(); match parts.as_slice() { - [src, dest] => Rule { + [src, dest] => Ok(Rule { name: format!("cli-loaded rule: {src} -> {dest}"), target: src.to_string(), - rewrite: dest.to_string(), + rewrite: shellexpand::env(dest)?.to_string(), mode: crate::enclosure::rule::RuleMode::File, context: vec![], only: vec![], env: HashMap::new(), - }, + }), - [src, dest, mode] => Rule { + [src, dest, mode] => Ok(Rule { name: format!("cli-loaded rule: {src} -> {dest} ({mode})"), target: src.to_string(), - rewrite: dest.to_string(), + rewrite: shellexpand::env(dest)?.to_string(), mode: mode.parse().unwrap(), context: vec![], only: vec![], env: HashMap::new(), - }, + }), _ => panic!("invalid format for cli rule: {s}"), } }) - .collect(); + .collect::>>()?; Ok(BoxxyRules { rules }) } @@ -191,3 +195,80 @@ impl BoxxyConfig { }) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_simple_cli() { + let rules = BoxxyConfig::load_rules_from_cli_flag(&["/src:/dest".to_string()]).unwrap(); + + assert_eq!(rules.rules[0].rewrite, "/dest"); + } + + #[test] + fn test_simple_file() -> Result<()> { + let config_content = r#" +rules: + - name: test + target: /src + rewrite: /dest +"#; + let mut config_file = tempfile::NamedTempFile::new()?; + std::io::Write::write_all(&mut config_file, config_content.as_bytes())?; + + let rules = BoxxyConfig::load_rules_from_path(config_file.path())?; + assert_eq!(rules.rules[0].rewrite, "/dest"); + Ok(()) + } + + #[test] + fn test_tilde_cli() { + let rules = BoxxyConfig::load_rules_from_cli_flag(&["/src:~/dest".to_string()]).unwrap(); + + assert_eq!(rules.rules[0].rewrite, "~/dest"); + } + + #[test] + fn test_tilde_file() -> Result<()> { + let config_content = r#" +rules: + - name: test + target: /src + rewrite: ~/dest +"#; + let mut config_file = tempfile::NamedTempFile::new()?; + std::io::Write::write_all(&mut config_file, config_content.as_bytes())?; + + let rules = BoxxyConfig::load_rules_from_path(config_file.path())?; + assert_eq!(rules.rules[0].rewrite, "~/dest"); + Ok(()) + } + + #[test] + fn test_expand_rewrite_cli() { + std::env::set_var("TEST_VAR_CLI", "/expanded/path/cli"); + let rules = BoxxyConfig::load_rules_from_cli_flag(&["/src:$TEST_VAR_CLI/dest".to_string()]) + .unwrap(); + + assert_eq!(rules.rules[0].rewrite, "/expanded/path/cli/dest"); + } + + #[test] + fn test_expand_rewrite_file() -> Result<()> { + std::env::set_var("TEST_VAR_FILE", "/expanded/path/file"); + let config_content = r#" +rules: + - name: test + target: /src + rewrite: $TEST_VAR_FILE/dest +"#; + let mut config_file = tempfile::NamedTempFile::new()?; + std::io::Write::write_all(&mut config_file, config_content.as_bytes())?; + + let rules = BoxxyConfig::load_rules_from_path(config_file.path())?; + assert_eq!(rules.rules[0].rewrite, "/expanded/path/file/dest"); + Ok(()) + } +}