diff options
author | Ellie Huxtable <ellie@elliehuxtable.com> | 2024-04-23 14:45:07 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-23 14:45:07 +0100 |
commit | bf88b42cec26ee2912c5e25eaadd5764b3a480f0 (patch) | |
tree | 3ddd529084a13b2c2b0ef1f1941797be4d176a63 | |
parent | 8b8844887b94a4b750fbfe128317ef4c2a042485 (diff) |
fix(dotfiles): unquote aliases before quoting (#1976)
* fix(dotfiles): unquote aliases before quoting
* tests
-rw-r--r-- | crates/atuin-common/src/utils.rs | 26 | ||||
-rw-r--r-- | crates/atuin-dotfiles/src/store.rs | 32 |
2 files changed, 55 insertions, 3 deletions
diff --git a/crates/atuin-common/src/utils.rs b/crates/atuin-common/src/utils.rs index 7c533663..3815085e 100644 --- a/crates/atuin-common/src/utils.rs +++ b/crates/atuin-common/src/utils.rs @@ -2,6 +2,8 @@ use std::borrow::Cow; use std::env; use std::path::PathBuf; +use eyre::{eyre, Result}; + use rand::RngCore; use uuid::Uuid; @@ -144,6 +146,30 @@ pub trait Escapable: AsRef<str> { } } +pub fn unquote(s: &str) -> Result<String> { + if s.chars().count() < 2 { + return Err(eyre!("not enough chars")); + } + + let quote = s.chars().next().unwrap(); + + // not quoted, do nothing + if quote != '"' && quote != '\'' && quote != '`' { + return Ok(s.to_string()); + } + + if s.chars().last().unwrap() != quote { + return Err(eyre!("unexpected eof, quotes do not match")); + } + + // removes quote characters + // the sanity checks performed above ensure that the quotes will be ASCII and this will not + // panic + let s = &s[1..s.len() - 1]; + + Ok(s.to_string()) +} + impl<T: AsRef<str>> Escapable for T {} #[cfg(test)] diff --git a/crates/atuin-dotfiles/src/store.rs b/crates/atuin-dotfiles/src/store.rs index 425a5e1e..b7984c1c 100644 --- a/crates/atuin-dotfiles/src/store.rs +++ b/crates/atuin-dotfiles/src/store.rs @@ -6,6 +6,7 @@ use atuin_client::record::sqlite_store::SqliteStore; // While we will support a range of shell config, I'd rather have a larger number of small records // + stores, rather than one mega config store. use atuin_common::record::{DecryptedData, Host, HostId}; +use atuin_common::utils::unquote; use eyre::{bail, ensure, eyre, Result}; use atuin_client::record::encryption::PASETO_V4; @@ -142,7 +143,11 @@ impl AliasStore { let mut config = String::new(); for alias in aliases { - config.push_str(&format!("alias {}='{}'\n", alias.name, alias.value)); + // If it's quoted, remove the quotes. If it's not quoted, do nothing. + let value = unquote(alias.value.as_str()).unwrap_or(alias.value.clone()); + + // we're about to quote it ourselves anyway! + config.push_str(&format!("alias {}='{}'\n", alias.name, value)); } Ok(config) @@ -336,14 +341,17 @@ mod tests { let alias = AliasStore::new(store, host_id, key); alias.set("k", "kubectl").await.unwrap(); - alias.set("gp", "git push").await.unwrap(); + alias + .set("kgap", "'kubectl get pods --all-namespaces'") + .await + .unwrap(); let mut aliases = alias.aliases().await.unwrap(); aliases.sort_by_key(|a| a.name.clone()); - assert_eq!(aliases.len(), 2); + assert_eq!(aliases.len(), 3); assert_eq!( aliases[0], @@ -360,5 +368,23 @@ mod tests { value: String::from("kubectl") } ); + + assert_eq!( + aliases[2], + Alias { + name: String::from("kgap"), + value: String::from("'kubectl get pods --all-namespaces'") + } + ); + + let build = alias.posix().await.expect("failed to build aliases"); + + assert_eq!( + build, + "alias gp='git push' +alias k='kubectl' +alias kgap='kubectl get pods --all-namespaces' +" + ) } } |