aboutsummaryrefslogtreecommitdiffstats
path: root/crates/client/src/command/client.rs
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-07-20 12:57:36 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-07-20 12:57:36 +0200
commit73be69cd99f5a4784fe69f5d78f423c72e837284 (patch)
treecb47246d2c7edd8cd828abb25a033b732d2289ae /crates/client/src/command/client.rs
parentchore: Move more stuff out of atuin-client (diff)
downloadatuin-73be69cd99f5a4784fe69f5d78f423c72e837284.zip
chore: Commit
Diffstat (limited to '')
-rw-r--r--crates/client/src/command/client.rs198
1 files changed, 5 insertions, 193 deletions
diff --git a/crates/client/src/command/client.rs b/crates/client/src/command/client.rs
index 6c0e70e8..42e72e21 100644
--- a/crates/client/src/command/client.rs
+++ b/crates/client/src/command/client.rs
@@ -1,19 +1,12 @@
-use std::fs::{self, OpenOptions};
+use std::fs::{self};
use std::path::{Path, PathBuf};
use clap::Subcommand;
use eyre::{Result, WrapErr};
-use tracing_subscriber::util::SubscriberInitExt;
-use tracing_appender::rolling::{RollingFileAppender, Rotation};
-use tracing_subscriber::{
- Layer, filter::EnvFilter, filter::LevelFilter, fmt, fmt::format::FmtSpan,
- prelude::__tracing_subscriber_SubscriberExt,
-};
+use tracing_subscriber::filter::EnvFilter;
-use crate::atuin_client::{
- database::ClientSqlite, record::sqlite_store::SqliteStore, settings::Settings,
-};
+use crate::atuin_client::settings::Settings;
fn cleanup_old_logs(log_dir: &Path, prefix: &str, retention_days: u64) {
let cutoff = std::time::SystemTime::now()
@@ -44,13 +37,9 @@ fn cleanup_old_logs(log_dir: &Path, prefix: &str, retention_days: u64) {
}
mod config;
-mod daemon;
mod default_config;
mod history;
mod info;
-mod init;
-mod search;
-mod server;
mod stats;
mod store;
mod sync;
@@ -63,25 +52,14 @@ pub(crate) enum Cmd {
#[command(subcommand)]
History(history::Cmd),
- /// Interactive history search
- Search(search::Cmd),
-
#[command(subcommand)]
/// Request a sync or view sync status
Sync(sync::Cmd),
- /// Manage the atuin server
- #[command(subcommand)]
- Server(server::Cmd),
-
/// Manage the atuin data store
#[command(subcommand)]
Store(store::Cmd),
- /// Print Atuin's shell init script
- #[command()]
- Init(init::Cmd),
-
/// Information about dotfiles locations and ENV vars
#[command()]
Info,
@@ -93,10 +71,6 @@ pub(crate) enum Cmd {
/// Display a recap of your last year's history
Wrapped { year: Option<i32> },
- /// *Experimental* Manage the background daemon
- #[command()]
- Daemon(daemon::Cmd),
-
/// Print the default atuin configuration (config.toml)
#[command()]
DefaultConfig,
@@ -108,28 +82,11 @@ pub(crate) enum Cmd {
impl Cmd {
pub(crate) fn run(self) -> Result<()> {
- // Daemonize before creating the async runtime – fork() inside a live
- // tokio runtime corrupts its internal state.
- #[cfg(unix)]
- if let Self::Daemon(ref cmd) = self
- && cmd.should_daemonize()
- {
- daemon::daemonize_current_process()?;
- }
-
let mut runtime = tokio::runtime::Builder::new_current_thread();
let runtime = runtime.enable_all().build().unwrap();
- // Start the server before descending into the client-specific setup code.
- // We simply cannot setup settings or a theme on the server, because the client-specific
- // stuff will error out.
- let res = if let Self::Server(server) = self {
- runtime.block_on(server.run())
- } else {
- // For non-history commands, we want to initialize logging and the theme manager before
- // doing anything else. History commands are performance-sensitive and run before and after
- // every shell command, so we want to skip any unnecessary initialization for them.
+ let res = {
let settings = Settings::new().wrap_err("could not load client settings")?;
runtime.block_on(self.run_inner(settings))
@@ -140,7 +97,6 @@ impl Cmd {
res
}
- #[expect(clippy::too_many_lines)]
async fn run_inner(self, mut settings: Settings) -> Result<()> {
// ATUIN_LOG env var overrides config file level settings
let env_log_set = std::env::var("ATUIN_LOG").is_ok();
@@ -149,137 +105,6 @@ impl Cmd {
let base_filter =
EnvFilter::from_env("ATUIN_LOG").add_directive("sqlx_sqlite::regexp=off".parse()?);
- let is_interactive_search = matches!(&self, Self::Search(cmd) if cmd.is_interactive());
- // Use file-based logging for interactive search (TUI mode)
- let use_search_logging = is_interactive_search && settings.logs.search_enabled();
-
- // Use file-based logging for daemon
- let use_daemon_logging = matches!(&self, Self::Daemon(_)) && settings.logs.daemon_enabled();
-
- // Check if daemon should also log to console
- let daemon_show_logs = matches!(&self, Self::Daemon(cmd) if cmd.show_logs());
-
- // Set up span timing JSON logs if ATUIN_SPAN is set
- let span_path = std::env::var("ATUIN_SPAN").ok().map(|p| {
- if p.is_empty() {
- "atuin-spans.json".to_string()
- } else {
- p
- }
- });
-
- // Helper to create span timing layer
- macro_rules! make_span_layer {
- ($path:expr) => {{
- let span_file = OpenOptions::new()
- .create(true)
- .truncate(true)
- .write(true)
- .open($path)?;
- Some(
- fmt::layer()
- .json()
- .with_writer(span_file)
- .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
- .with_filter(LevelFilter::TRACE),
- )
- }};
- }
-
- // Build the subscriber with all configured layers
- if use_search_logging {
- let search_filename = settings.logs.search.file.clone();
- let log_dir = PathBuf::from(&settings.logs.dir);
- fs::create_dir_all(&log_dir)?;
-
- // Clean up old log files
- cleanup_old_logs(&log_dir, &search_filename, settings.logs.search_retention());
-
- let file_appender =
- RollingFileAppender::new(Rotation::DAILY, &log_dir, &search_filename);
-
- // Use config level unless ATUIN_LOG is set
- let filter = if env_log_set {
- base_filter
- } else {
- EnvFilter::default()
- .add_directive(settings.logs.search_level().as_directive().parse()?)
- .add_directive("sqlx_sqlite::regexp=off".parse()?)
- };
-
- let base = tracing_subscriber::registry().with(
- fmt::layer()
- .with_writer(file_appender)
- .with_ansi(false)
- .with_filter(filter),
- );
-
- match &span_path {
- Some(sp) => {
- base.with(make_span_layer!(sp)).init();
- }
- None => {
- base.init();
- }
- }
- } else if use_daemon_logging {
- let daemon_filename = settings.logs.daemon.file.clone();
- let log_dir = PathBuf::from(&settings.logs.dir);
- fs::create_dir_all(&log_dir)?;
-
- // Clean up old log files
- cleanup_old_logs(&log_dir, &daemon_filename, settings.logs.daemon_retention());
-
- let file_appender =
- RollingFileAppender::new(Rotation::DAILY, &log_dir, &daemon_filename);
-
- // Use config level unless ATUIN_LOG is set
- let file_filter = if env_log_set {
- base_filter
- } else {
- EnvFilter::default()
- .add_directive(settings.logs.daemon_level().as_directive().parse()?)
- .add_directive("sqlx_sqlite::regexp=off".parse()?)
- };
-
- let file_layer = fmt::layer()
- .with_writer(file_appender)
- .with_ansi(false)
- .with_filter(file_filter);
-
- // Optionally add console layer for --show-logs
- if daemon_show_logs {
- let console_filter = EnvFilter::from_env("ATUIN_LOG")
- .add_directive("sqlx_sqlite::regexp=off".parse()?);
-
- let console_layer = fmt::layer().with_filter(console_filter);
-
- let base = tracing_subscriber::registry()
- .with(file_layer)
- .with(console_layer);
-
- match &span_path {
- Some(sp) => {
- base.with(make_span_layer!(sp)).init();
- }
- None => {
- base.init();
- }
- }
- } else {
- let base = tracing_subscriber::registry().with(file_layer);
-
- match &span_path {
- Some(sp) => {
- base.with(make_span_layer!(sp)).init();
- }
- None => {
- base.init();
- }
- }
- }
- }
-
tracing::trace!(command = ?self, "client command");
// Skip initializing any databases for history
@@ -287,23 +112,12 @@ impl Cmd {
// runs
match self {
Self::History(history) => return history.run(&settings).await,
- Self::Init(init) => {
- init.run(&settings);
- return Ok(());
- }
Self::Config(config) => return config.run(&settings).await,
_ => {}
}
- let db_path = PathBuf::from(settings.db_path.as_str());
- let record_store_path = PathBuf::from(settings.record_store_path.as_str());
-
- let db = ClientSqlite::new(db_path, settings.local_timeout).await?;
- let sqlite_store = SqliteStore::new(record_store_path, settings.local_timeout).await?;
-
match self {
Self::Stats(stats) => stats.run(&db, &settings).await,
- Self::Search(search) => search.run(db, &mut settings, sqlite_store).await,
Self::Wrapped { year } => wrapped::run(year, &db, &settings).await,
Self::Sync(sync) => sync.run(settings, &db, sqlite_store).await,
@@ -317,9 +131,7 @@ impl Cmd {
Ok(())
}
- Self::Daemon(cmd) => cmd.run(settings, sqlite_store, db).await,
-
- Self::History(_) | Self::Init(_) | Self::Config(_) | Self::Server(_) => {
+ Self::History(_) | Self::Config(_) => {
unreachable!()
}
}