From fc1a48a4f204dfe77bd8d4f82cfb3e64ade9d028 Mon Sep 17 00:00:00 2001 From: Conrad Ludgate Date: Tue, 26 Sep 2023 14:52:45 +0100 Subject: [PATCH] handle missing entries (fixes #1236) (#1253) * fix #1236 * lints --- atuin-client/src/database.rs | 23 ++++++----------------- atuin-client/src/history.rs | 14 +++++++++----- atuin-client/src/secrets.rs | 2 +- atuin-client/src/sync.rs | 2 +- atuin/src/command/client/history.rs | 10 +++++++--- 5 files changed, 24 insertions(+), 27 deletions(-) diff --git a/atuin-client/src/database.rs b/atuin-client/src/database.rs index 16a4a43f..1a3dea16 100644 --- a/atuin-client/src/database.rs +++ b/atuin-client/src/database.rs @@ -73,7 +73,7 @@ pub trait Database: Send + Sync + 'static { async fn save(&mut self, h: &History) -> Result<()>; async fn save_bulk(&mut self, h: &[History]) -> Result<()>; - async fn load(&self, id: &str) -> Result; + async fn load(&self, id: &str) -> Result>; async fn list( &self, filter: FilterMode, @@ -86,8 +86,7 @@ pub trait Database: Send + Sync + 'static { async fn update(&self, h: &History) -> Result<()>; async fn history_count(&self) -> Result; - async fn first(&self) -> Result; - async fn last(&self) -> Result; + async fn last(&self) -> Result>; async fn before(&self, timestamp: OffsetDateTime, count: i64) -> Result>; async fn delete(&self, mut h: History) -> Result<()>; @@ -216,13 +215,13 @@ impl Database for Sqlite { Ok(()) } - async fn load(&self, id: &str) -> Result { + async fn load(&self, id: &str) -> Result> { debug!("loading history item {}", id); let res = sqlx::query("select * from history where id = ?1") .bind(id) .map(Self::query_history) - .fetch_one(&self.pool) + .fetch_optional(&self.pool) .await?; Ok(res) @@ -308,22 +307,12 @@ impl Database for Sqlite { Ok(res) } - async fn first(&self) -> Result { - let res = - sqlx::query("select * from history where duration >= 0 order by timestamp asc limit 1") - .map(Self::query_history) - .fetch_one(&self.pool) - .await?; - - Ok(res) - } - - async fn last(&self) -> Result { + async fn last(&self) -> Result> { let res = sqlx::query( "select * from history where duration >= 0 order by timestamp desc limit 1", ) .map(Self::query_history) - .fetch_one(&self.pool) + .fetch_optional(&self.pool) .await?; Ok(res) diff --git a/atuin-client/src/history.rs b/atuin-client/src/history.rs index f4c0a8eb..fbcb169c 100644 --- a/atuin-client/src/history.rs +++ b/atuin-client/src/history.rs @@ -210,9 +210,11 @@ mod tests { // Test that we don't save history where necessary #[test] fn privacy_test() { - let mut settings = Settings::default(); - settings.cwd_filter = RegexSet::new(["^/supasecret"]).unwrap(); - settings.history_filter = RegexSet::new(["^psql"]).unwrap(); + let settings = Settings { + cwd_filter: RegexSet::new(["^/supasecret"]).unwrap(), + history_filter: RegexSet::new(["^psql"]).unwrap(), + ..Settings::default() + }; let normal_command: History = History::capture() .timestamp(time::OffsetDateTime::now_utc()) @@ -258,8 +260,10 @@ mod tests { #[test] fn disable_secrets() { - let mut settings = Settings::default(); - settings.secrets_filter = false; + let settings = Settings { + secrets_filter: false, + ..Settings::default() + }; let stripe_key: History = History::capture() .timestamp(time::OffsetDateTime::now_utc()) diff --git a/atuin-client/src/secrets.rs b/atuin-client/src/secrets.rs index ba6aee66..0f751a8a 100644 --- a/atuin-client/src/secrets.rs +++ b/atuin-client/src/secrets.rs @@ -46,7 +46,7 @@ mod tests { fn test_secrets() { for (name, regex, test) in SECRET_PATTERNS { let re = - Regex::new(regex).expect(format!("Failed to compile regex for {name}").as_str()); + Regex::new(regex).unwrap_or_else(|_| panic!("Failed to compile regex for {name}")); assert!(re.is_match(test), "{name} test failed!"); } diff --git a/atuin-client/src/sync.rs b/atuin-client/src/sync.rs index bd2ff474..ebfb47c1 100644 --- a/atuin-client/src/sync.rs +++ b/atuin-client/src/sync.rs @@ -109,7 +109,7 @@ async fn sync_download( for i in remote_status.deleted { // we will update the stored history to have this data // pretty much everything can be nullified - if let Ok(h) = db.load(i.as_str()).await { + if let Some(h) = db.load(i.as_str()).await? { db.delete(h).await?; } else { info!( diff --git a/atuin/src/command/client/history.rs b/atuin/src/command/client/history.rs index 1321a61b..3ca6dc4c 100644 --- a/atuin/src/command/client/history.rs +++ b/atuin/src/command/client/history.rs @@ -18,7 +18,7 @@ use atuin_client::{ #[cfg(feature = "sync")] use atuin_client::sync; -use log::debug; +use log::{debug, warn}; use time::{macros::format_description, OffsetDateTime}; use super::search::format_duration_into; @@ -233,7 +233,10 @@ impl Cmd { return Ok(()); } - let mut h = db.load(id).await?; + let Some(mut h) = db.load(id).await? else { + warn!("history entry is missing"); + return Ok(()); + }; if h.duration > 0 { debug!("cannot end history - already has duration"); @@ -329,8 +332,9 @@ impl Cmd { format, } => { let last = db.last().await?; + let last = last.as_ref().map(std::slice::from_ref).unwrap_or_default(); print_list( - &[last], + last, ListMode::from_flags(human, cmd_only), format.as_deref(), );