diff options
| author | Ellie Huxtable <ellie@elliehuxtable.com> | 2024-04-03 10:19:24 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-03 10:19:24 +0100 |
| commit | 894eaa6faff86e1839510e114427b949b2440d39 (patch) | |
| tree | 7bbda2eebb75b79292f3095017c44ebc97387654 /atuin-dotfiles/src | |
| parent | feat: add 'ctrl-a a' to jump to beginning of line (#1917) (diff) | |
| download | atuin-894eaa6faff86e1839510e114427b949b2440d39.zip | |
perf(dotfiles): cache aliases and read straight from file (#1918)
* cache aliases when set locally
* handle rebuild on sync and tidy things a bit
* support all shells except nu
* make clippy happy
* fmt
* fix for no features
Diffstat (limited to 'atuin-dotfiles/src')
| -rw-r--r-- | atuin-dotfiles/src/shell/bash.rs | 41 | ||||
| -rw-r--r-- | atuin-dotfiles/src/shell/fish.rs | 42 | ||||
| -rw-r--r-- | atuin-dotfiles/src/shell/xonsh.rs | 41 | ||||
| -rw-r--r-- | atuin-dotfiles/src/shell/zsh.rs | 41 | ||||
| -rw-r--r-- | atuin-dotfiles/src/store.rs | 54 |
5 files changed, 191 insertions, 28 deletions
diff --git a/atuin-dotfiles/src/shell/bash.rs b/atuin-dotfiles/src/shell/bash.rs index c5bd87b2..5bdd7dce 100644 --- a/atuin-dotfiles/src/shell/bash.rs +++ b/atuin-dotfiles/src/shell/bash.rs @@ -1,12 +1,39 @@ -use super::Alias; +use std::path::PathBuf; -// Configuration for bash -pub fn build(aliases: &[Alias]) -> String { - let mut config = String::new(); +use crate::store::AliasStore; - for alias in aliases { - config.push_str(&format!("alias {}='{}'\n", alias.name, alias.value)); +async fn cached_aliases(path: PathBuf, store: &AliasStore) -> String { + match tokio::fs::read_to_string(path).await { + Ok(aliases) => aliases, + Err(r) => { + // we failed to read the file for some reason, but the file does exist + // fallback to generating new aliases on the fly + + store.posix().await.unwrap_or_else(|e| { + format!("echo 'Atuin: failed to read and generate aliases: \n{r}\n{e}'",) + }) + } + } +} + +/// Return bash dotfile config +/// +/// Do not return an error. We should not prevent the shell from starting. +/// +/// In the worst case, Atuin should not function but the shell should start correctly. +/// +/// While currently this only returns aliases, it will be extended to also return other synced dotfiles +pub async fn config(store: &AliasStore) -> String { + // First try to read the cached config + let aliases = atuin_common::utils::dotfiles_cache_dir().join("aliases.bash"); + + if aliases.exists() { + return cached_aliases(aliases, store).await; + } + + if let Err(e) = store.build().await { + return format!("echo 'Atuin: failed to generate aliases: {}'", e); } - config + cached_aliases(aliases, store).await } diff --git a/atuin-dotfiles/src/shell/fish.rs b/atuin-dotfiles/src/shell/fish.rs index c6277f34..bf4e1a3b 100644 --- a/atuin-dotfiles/src/shell/fish.rs +++ b/atuin-dotfiles/src/shell/fish.rs @@ -1,12 +1,40 @@ -use super::Alias; - // Configuration for fish -pub fn build(aliases: &[Alias]) -> String { - let mut config = String::new(); +use std::path::PathBuf; + +use crate::store::AliasStore; + +async fn cached_aliases(path: PathBuf, store: &AliasStore) -> String { + match tokio::fs::read_to_string(path).await { + Ok(aliases) => aliases, + Err(r) => { + // we failed to read the file for some reason, but the file does exist + // fallback to generating new aliases on the fly + + store.posix().await.unwrap_or_else(|e| { + format!("echo 'Atuin: failed to read and generate aliases: \n{r}\n{e}'",) + }) + } + } +} + +/// Return fish dotfile config +/// +/// Do not return an error. We should not prevent the shell from starting. +/// +/// In the worst case, Atuin should not function but the shell should start correctly. +/// +/// While currently this only returns aliases, it will be extended to also return other synced dotfiles +pub async fn config(store: &AliasStore) -> String { + // First try to read the cached config + let aliases = atuin_common::utils::dotfiles_cache_dir().join("aliases.fish"); + + if aliases.exists() { + return cached_aliases(aliases, store).await; + } - for alias in aliases { - config.push_str(&format!("alias {}='{}'\n", alias.name, alias.value)); + if let Err(e) = store.build().await { + return format!("echo 'Atuin: failed to generate aliases: {}'", e); } - config + cached_aliases(aliases, store).await } diff --git a/atuin-dotfiles/src/shell/xonsh.rs b/atuin-dotfiles/src/shell/xonsh.rs index 8b61ff4c..383df4ec 100644 --- a/atuin-dotfiles/src/shell/xonsh.rs +++ b/atuin-dotfiles/src/shell/xonsh.rs @@ -1,12 +1,39 @@ -use super::Alias; +use std::path::PathBuf; -// Configuration for xonsh -pub fn build(aliases: &[Alias]) -> String { - let mut config = String::new(); +use crate::store::AliasStore; - for alias in aliases { - config.push_str(&format!("aliases['{}'] ='{}'\n", alias.name, alias.value)); +async fn cached_aliases(path: PathBuf, store: &AliasStore) -> String { + match tokio::fs::read_to_string(path).await { + Ok(aliases) => aliases, + Err(r) => { + // we failed to read the file for some reason, but the file does exist + // fallback to generating new aliases on the fly + + store.xonsh().await.unwrap_or_else(|e| { + format!("echo 'Atuin: failed to read and generate aliases: \n{r}\n{e}'",) + }) + } + } +} + +/// Return xonsh dotfile config +/// +/// Do not return an error. We should not prevent the shell from starting. +/// +/// In the worst case, Atuin should not function but the shell should start correctly. +/// +/// While currently this only returns aliases, it will be extended to also return other synced dotfiles +pub async fn config(store: &AliasStore) -> String { + // First try to read the cached config + let aliases = atuin_common::utils::dotfiles_cache_dir().join("aliases.xsh"); + + if aliases.exists() { + return cached_aliases(aliases, store).await; + } + + if let Err(e) = store.build().await { + return format!("echo 'Atuin: failed to generate aliases: {}'", e); } - config + cached_aliases(aliases, store).await } diff --git a/atuin-dotfiles/src/shell/zsh.rs b/atuin-dotfiles/src/shell/zsh.rs index 6f81ed55..d863b261 100644 --- a/atuin-dotfiles/src/shell/zsh.rs +++ b/atuin-dotfiles/src/shell/zsh.rs @@ -1,12 +1,39 @@ -use super::Alias; +use std::path::PathBuf; -// Configuration for zsh -pub fn build(aliases: &[Alias]) -> String { - let mut config = String::new(); +use crate::store::AliasStore; - for alias in aliases { - config.push_str(&format!("alias {}='{}'\n", alias.name, alias.value)); +async fn cached_aliases(path: PathBuf, store: &AliasStore) -> String { + match tokio::fs::read_to_string(path).await { + Ok(aliases) => aliases, + Err(r) => { + // we failed to read the file for some reason, but the file does exist + // fallback to generating new aliases on the fly + + store.posix().await.unwrap_or_else(|e| { + format!("echo 'Atuin: failed to read and generate aliases: \n{r}\n{e}'",) + }) + } + } +} + +/// Return zsh dotfile config +/// +/// Do not return an error. We should not prevent the shell from starting. +/// +/// In the worst case, Atuin should not function but the shell should start correctly. +/// +/// While currently this only returns aliases, it will be extended to also return other synced dotfiles +pub async fn config(store: &AliasStore) -> String { + // First try to read the cached config + let aliases = atuin_common::utils::dotfiles_cache_dir().join("aliases.zsh"); + + if aliases.exists() { + return cached_aliases(aliases, store).await; + } + + if let Err(e) = store.build().await { + return format!("echo 'Atuin: failed to generate aliases: {}'", e); } - config + cached_aliases(aliases, store).await } diff --git a/atuin-dotfiles/src/store.rs b/atuin-dotfiles/src/store.rs index 96e0fb32..425a5e1e 100644 --- a/atuin-dotfiles/src/store.rs +++ b/atuin-dotfiles/src/store.rs @@ -136,6 +136,54 @@ impl AliasStore { } } + pub async fn posix(&self) -> Result<String> { + let aliases = self.aliases().await?; + + let mut config = String::new(); + + for alias in aliases { + config.push_str(&format!("alias {}='{}'\n", alias.name, alias.value)); + } + + Ok(config) + } + + pub async fn xonsh(&self) -> Result<String> { + let aliases = self.aliases().await?; + + let mut config = String::new(); + + for alias in aliases { + config.push_str(&format!("aliases['{}'] ='{}'\n", alias.name, alias.value)); + } + + Ok(config) + } + + pub async fn build(&self) -> Result<()> { + let dir = atuin_common::utils::dotfiles_cache_dir(); + tokio::fs::create_dir_all(dir.clone()).await?; + + // Build for all supported shells + let posix = self.posix().await?; + let xonsh = self.xonsh().await?; + + // All the same contents, maybe optimize in the future or perhaps there will be quirks + // per-shell + // I'd prefer separation atm + let zsh = dir.join("aliases.zsh"); + let bash = dir.join("aliases.bash"); + let fish = dir.join("aliases.fish"); + let xsh = dir.join("aliases.xsh"); + + tokio::fs::write(zsh, &posix).await?; + tokio::fs::write(bash, &posix).await?; + tokio::fs::write(fish, &posix).await?; + tokio::fs::write(xsh, &xonsh).await?; + + Ok(()) + } + pub async fn set(&self, name: &str, value: &str) -> Result<()> { if name.len() + value.len() > CONFIG_SHELL_ALIAS_FIELD_MAX_LEN { return Err(eyre!( @@ -169,6 +217,9 @@ impl AliasStore { .push(&record.encrypt::<PASETO_V4>(&self.encryption_key)) .await?; + // set mutates shell config, so build again + self.build().await?; + Ok(()) } @@ -202,6 +253,9 @@ impl AliasStore { .push(&record.encrypt::<PASETO_V4>(&self.encryption_key)) .await?; + // delete mutates shell config, so build again + self.build().await?; + Ok(()) } |
