diff options
Diffstat (limited to '')
| -rw-r--r-- | crates/client/src/command/client/daemon.rs | 2 | ||||
| -rw-r--r-- | crates/client/src/command/client/history/end.rs | 30 | ||||
| -rw-r--r-- | crates/client/src/command/client/history/list.rs | 39 | ||||
| -rw-r--r-- | crates/client/src/command/client/history/mod.rs | 14 | ||||
| -rw-r--r-- | crates/client/src/command/client/history/start.rs | 18 | ||||
| -rw-r--r-- | crates/client/src/command/client/history/tail.rs | 29 | ||||
| -rw-r--r-- | crates/client/src/command/client/info.rs | 2 | ||||
| -rw-r--r-- | crates/client/src/command/client/stats.rs | 20 | ||||
| -rw-r--r-- | crates/client/src/command/client/sync.rs | 17 | ||||
| -rw-r--r-- | crates/client/src/command/client/wrapped.rs | 5 |
10 files changed, 118 insertions, 58 deletions
diff --git a/crates/client/src/command/client/daemon.rs b/crates/client/src/command/client/daemon.rs index 08ce7a96..e9b0ea4c 100644 --- a/crates/client/src/command/client/daemon.rs +++ b/crates/client/src/command/client/daemon.rs @@ -1,7 +1,7 @@ use clap::Subcommand; use eyre::Result; -use turtle::client::{Probe, probe}; +use turtle_api::client::{Probe, probe}; use crate::atuin_client::settings::Settings; diff --git a/crates/client/src/command/client/history/end.rs b/crates/client/src/command/client/history/end.rs index 0e1e6b91..290f7697 100644 --- a/crates/client/src/command/client/history/end.rs +++ b/crates/client/src/command/client/history/end.rs @@ -1,28 +1,34 @@ +use std::time::Duration; + use crate::atuin_client::settings::Settings; use eyre::{Result, eyre}; -use turtle::client::{HistoryClient, daemon_matches_expected, daemon_mismatch_message}; +use turtle_api::client::{HistoryClient, daemon_matches_expected, daemon_mismatch_message}; pub(super) async fn handle( settings: &Settings, id: &str, exit: i64, - duration: Option<u64>, + duration: Option<Duration>, ) -> Result<()> { - end_history(settings, id.to_string(), duration.unwrap_or(0), exit).await?; + end_history( + settings, + id.to_string(), + duration.unwrap_or(Duration::ZERO), + exit, + ) + .await?; Ok(()) } -async fn end_history(settings: &Settings, id: String, duration: u64, exit: i64) -> Result<()> { - match async { - HistoryClient::new(settings.daemon.socket_path.clone()) - .await? - .end_history(id.clone(), duration, exit) - .await - } - .await - { +async fn end_history(settings: &Settings, id: String, duration: Duration, exit: i64) -> Result<()> { + let response = HistoryClient::new(settings.daemon.socket_path.clone()) + .await? + .end_history(id.clone(), duration, exit) + .await; + + match response { Ok(resp) => { if daemon_matches_expected(resp.protocol) { return Ok(()); diff --git a/crates/client/src/command/client/history/list.rs b/crates/client/src/command/client/history/list.rs new file mode 100644 index 00000000..0fc59f6a --- /dev/null +++ b/crates/client/src/command/client/history/list.rs @@ -0,0 +1,39 @@ +use std::{fmt::Display, time::Duration}; + +use crate::{atuin_client::settings::Settings, command::client::history::format_duration_into}; + +use eyre::Result; +use turtle_api::client::HistoryClient; + +pub(super) async fn handle(settings: &Settings) -> Result<()> { + const CSI: &str = "\x1b["; + const CSE: &str = "m"; + fn col(v: impl Display, num: u32) -> String { + format!("{CSI}{num}{CSE}{v}{CSI}0{CSE}") + } + + struct F(Duration); + impl Display for F { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + format_duration_into(self.0, f) + } + } + + let mut client = HistoryClient::new(settings.daemon.socket_path.clone()).await?; + + let hists = client.history(None).await?; + + for hist in hists { + println!( + "{}@{}: {} at {} for {} [{}]", + hist.author, + hist.hostname, + col(hist.command, 36), + col(hist.cwd, 32), + F(hist.duration), + col(hist.exit, 31) + ); + } + + Ok(()) +} diff --git a/crates/client/src/command/client/history/mod.rs b/crates/client/src/command/client/history/mod.rs index b6bfe6a1..f32ad83d 100644 --- a/crates/client/src/command/client/history/mod.rs +++ b/crates/client/src/command/client/history/mod.rs @@ -7,11 +7,12 @@ use std::{ use clap::Subcommand; use eyre::Result; use time::macros::format_description; -use turtle::history::History; +use turtle_api::history::History; use crate::atuin_client::settings::Settings; mod end; +mod list; mod start; mod tail; @@ -43,12 +44,16 @@ pub(crate) enum Cmd { #[arg(long, short)] exit: i64, + /// The duration this command ran, specified as nano seconds. #[arg(long, short)] duration: Option<u64>, }, /// Stream history events from the daemon as they are received Tail, + + /// Very basic listing of tracked history. + List, } impl Cmd { @@ -74,10 +79,11 @@ impl Cmd { Ok(()) } - Self::End { id, exit, duration } => end::handle(settings, &id, exit, duration).await, - Self::Tail => { - return tail::handle(settings).await; + Self::End { id, exit, duration } => { + end::handle(settings, &id, exit, duration.map(Duration::from_nanos)).await } + Self::Tail => tail::handle(settings).await, + Self::List => list::handle(settings).await, } } } diff --git a/crates/client/src/command/client/history/start.rs b/crates/client/src/command/client/history/start.rs index cb8f1b0c..c462755e 100644 --- a/crates/client/src/command/client/history/start.rs +++ b/crates/client/src/command/client/history/start.rs @@ -9,7 +9,7 @@ use crate::{ use eyre::{Result, eyre}; use time::OffsetDateTime; use tracing::debug; -use turtle::{ +use turtle_api::{ client::{HistoryClient, daemon_matches_expected, daemon_mismatch_message}, history::{History, SettingsFilter}, }; @@ -51,7 +51,7 @@ pub(super) async fn handle( Ok(id) => id, Err(e) => { debug!("failed to start history via daemon: {e}"); - h.id.0.clone() + h.id.to_string() } }; @@ -59,14 +59,12 @@ pub(super) async fn handle( } async fn start_history(settings: &Settings, history: History) -> Result<String> { - match async { - HistoryClient::new(settings.daemon.socket_path.clone()) - .await? - .start_history(history.clone()) - .await - } - .await - { + let response = HistoryClient::new(settings.daemon.socket_path.clone()) + .await? + .start_history(history.clone()) + .await; + + match response { Ok(resp) => { if daemon_matches_expected(resp.protocol) { return Ok(resp.id); diff --git a/crates/client/src/command/client/history/tail.rs b/crates/client/src/command/client/history/tail.rs index 212d7fcd..2cad5dd6 100644 --- a/crates/client/src/command/client/history/tail.rs +++ b/crates/client/src/command/client/history/tail.rs @@ -7,7 +7,7 @@ use colored::Colorize; use eyre::{Context, Result, bail}; use serde::Serialize; use time::OffsetDateTime; -use turtle::{ +use turtle_api::{ client::{ HistoryClient, HistoryEventKind, Probe, TailHistoryReply, history_entry_to_history, probe, }, @@ -56,9 +56,7 @@ struct TailJsonHistory<'a> { #[serde(skip_serializing_if = "Option::is_none")] exit: Option<i64>, #[serde(skip_serializing_if = "Option::is_none")] - duration_ns: Option<i64>, - #[serde(skip_serializing_if = "Option::is_none")] - duration: Option<String>, + duration: Option<Duration>, #[serde(skip_serializing_if = "Option::is_none")] success: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] @@ -98,7 +96,7 @@ impl TailEvent { let payload = TailJsonEvent { event: self.kind.as_str(), history: TailJsonHistory { - id: &self.history.id.0, + id: &self.history.id.to_string(), timestamp: format_history_time(self.history.timestamp, tz)?, timestamp_unix_ns: u64::try_from(self.history.timestamp.unix_timestamp_nanos()) .context("history timestamp predates unix epoch")?, @@ -111,8 +109,7 @@ impl TailEvent { author: &self.history.author, intent: self.history.intent.as_deref(), exit: self.exit_value(), - duration_ns: self.duration_value(), - duration: self.duration_value().map(format_duration_ns), + duration: self.duration_value(), success: self.success_value(), finished_at: self .finished_at() @@ -158,7 +155,7 @@ impl TailEvent { &format_history_time(self.history.timestamp, tz) .unwrap_or_else(|_| "invalid".to_owned()), ); - push_pretty_field(&mut out, "history", &self.history.id.0); + push_pretty_field(&mut out, "history", &self.history.id.to_string()); push_pretty_field(&mut out, "session", &self.history.session); push_pretty_field(&mut out, "exit", &self.exit_display()); push_pretty_field(&mut out, "duration", &self.duration_display()); @@ -204,7 +201,7 @@ impl TailEvent { matches!(self.kind, TailKind::Ended).then_some(self.history.exit) } - fn duration_value(&self) -> Option<i64> { + fn duration_value(&self) -> Option<Duration> { matches!(self.kind, TailKind::Ended).then_some(self.history.duration) } @@ -214,8 +211,12 @@ impl TailEvent { fn finished_at(&self) -> Option<OffsetDateTime> { self.duration_value() - .filter(|duration| *duration >= 0) - .map(time::Duration::nanoseconds) + .filter(|duration| *duration >= Duration::ZERO) + .map(|d| { + time::Duration::nanoseconds_i128( + i128::try_from(d.as_nanos()).expect("to be small enough"), + ) + }) .and_then(|duration| self.history.timestamp.checked_add(duration)) } @@ -229,7 +230,7 @@ impl TailEvent { fn duration_display(&self) -> String { match self.duration_value() { - Some(duration) if duration >= 0 => format_duration_ns(duration), + Some(duration) if duration >= Duration::ZERO => format_duration_ns(duration), Some(_) => "unknown".bright_yellow().to_string(), None => "running".bright_yellow().to_string(), } @@ -274,7 +275,7 @@ fn push_pretty_field(out: &mut String, label: &str, value: &str) { } } -fn format_duration_ns(duration_ns: i64) -> String { +fn format_duration_ns(duration: Duration) -> String { struct F(Duration); impl Display for F { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -282,7 +283,7 @@ fn format_duration_ns(duration_ns: i64) -> String { } } - F(Duration::from_nanos(duration_ns.max(0).cast_unsigned())).to_string() + F(duration).to_string() } fn format_history_time(timestamp: OffsetDateTime, tz: Timezone) -> Result<String> { diff --git a/crates/client/src/command/client/info.rs b/crates/client/src/command/client/info.rs index c4839c38..1af8ee39 100644 --- a/crates/client/src/command/client/info.rs +++ b/crates/client/src/command/client/info.rs @@ -2,7 +2,7 @@ use crate::atuin_client::settings::Settings; use crate::{SHA, VERSION};
use eyre::Result;
-use turtle::client::ControlClient;
+use turtle_api::client::ControlClient;
pub(crate) async fn run(settings: &Settings) -> Result<()> {
let config = turtle_common::utils::config_dir();
diff --git a/crates/client/src/command/client/stats.rs b/crates/client/src/command/client/stats.rs index 88734bb6..9f74ecc3 100644 --- a/crates/client/src/command/client/stats.rs +++ b/crates/client/src/command/client/stats.rs @@ -2,12 +2,11 @@ use clap::Parser; use eyre::Result; use interim::{Dialect, parse_date_string}; use time::{Duration, OffsetDateTime, Time}; -use turtle::client::{HistoryClient, Range}; +use turtle_api::client::{HistoryClient, Range}; use crate::atuin_client::settings::Settings; use crate::atuin_history::stats::{compute, pretty_print}; -use crate::command::current_session; fn parse_ngram_size(s: &str) -> Result<usize, String> { let value = s @@ -38,7 +37,6 @@ pub(crate) struct Cmd { impl Cmd { pub(crate) async fn run(&self, settings: &Settings) -> Result<()> { - let session = current_session()?; let mut client = HistoryClient::new(settings.daemon.socket_path.clone()).await?; let words = if self.period.is_empty() { @@ -50,30 +48,32 @@ impl Cmd { let now = OffsetDateTime::now_utc().to_offset(settings.timezone.0); let last_night = now.replace_time(Time::MIDNIGHT); - let history = if words.as_str() == "all" { - client.history(session, None).await? + let range = if words.as_str() == "all" { + None } else if words.trim() == "today" { let start = last_night; let end = start + Duration::days(1); - client.history(session, Some(Range { start, end })).await? + Some(Range { start, end }) } else if words.trim() == "month" { let end = last_night; let start = end - Duration::days(31); - client.history(session, Some(Range { start, end })).await? + Some(Range { start, end }) } else if words.trim() == "week" { let end = last_night; let start = end - Duration::days(7); - client.history(session, Some(Range { start, end })).await? + Some(Range { start, end }) } else if words.trim() == "year" { let end = last_night; let start = end - Duration::days(365); - client.history(session, Some(Range { start, end })).await? + Some(Range { start, end }) } else { let start = parse_date_string(&words, now, Dialect::Uk)?; let end = start + Duration::days(1); - client.history(session, Some(Range { start, end })).await? + Some(Range { start, end }) }; + let history = client.history(range).await?; + let stats = compute(settings, &history, self.count, self.ngram_size); if let Some(stats) = stats { diff --git a/crates/client/src/command/client/sync.rs b/crates/client/src/command/client/sync.rs index 77ae97ba..7297c659 100644 --- a/crates/client/src/command/client/sync.rs +++ b/crates/client/src/command/client/sync.rs @@ -1,7 +1,8 @@ use clap::Subcommand; use eyre::{Result, bail}; -use turtle::client::{Probe, probe}; +use tracing::info; +use turtle_api::client::{Probe, probe}; use crate::atuin_client::settings::Settings; @@ -74,8 +75,18 @@ async fn perform_cmd(settings: &Settings) -> Result<()> { match probe(settings.daemon.socket_path.clone()).await { Probe::Ready(mut control_client) => { let reply = control_client.force_sync().await?; - if !reply.accepted { - bail!("Daemon refused to accept sync request"); + + match reply.error { + Some(err) => { + bail!("Daemon failed to sync: {err}"); + } + None => { + info!( + down = reply.downloaded, + up = reply.uploaded, + "Sync completed." + ); + } } } Probe::NeedsRestart(msg) => { diff --git a/crates/client/src/command/client/wrapped.rs b/crates/client/src/command/client/wrapped.rs index 8c15a5d3..a47b81a1 100644 --- a/crates/client/src/command/client/wrapped.rs +++ b/crates/client/src/command/client/wrapped.rs @@ -2,7 +2,7 @@ use crossterm::style::{ResetColor, SetAttribute}; use eyre::Result; use std::collections::{HashMap, HashSet}; use time::{Date, Duration, Month, OffsetDateTime, Time}; -use turtle::{ +use turtle_api::{ client::{HistoryClient, Range}, history::History, }; @@ -274,7 +274,6 @@ fn print_fun_facts(wrapped_stats: &WrappedStats, stats: &Stats, year: i32) { } pub(crate) async fn run(year: Option<i32>, settings: &Settings) -> Result<()> { - let session = current_session()?; let mut client = HistoryClient::new(settings.daemon.socket_path.clone()).await?; let now = OffsetDateTime::now_utc().to_offset(settings.timezone.0); @@ -300,7 +299,7 @@ pub(crate) async fn run(year: Option<i32>, settings: &Settings) -> Result<()> { now.offset(), ); - let history = client.history(session, Some(Range { start, end })).await?; + let history = client.history(Some(Range { start, end })).await?; if history.is_empty() { println!( "Your history for {year} is empty!\nMaybe 'atuin import' could help you import your previous history 🪄" |
