aboutsummaryrefslogtreecommitdiffstats
path: root/crates/turtle/src/command/client/sync.rs
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-06-11 00:54:30 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-06-11 00:54:30 +0200
commit5c39e7cf284a1f6e9a1657f2deb44e359fc47eb8 (patch)
treec64baa8d5866c8e339eaf660dd3f94f30a3f7d8a /crates/turtle/src/command/client/sync.rs
parentchore: Somewhat simplify sync code (diff)
downloadatuin-5c39e7cf284a1f6e9a1657f2deb44e359fc47eb8.zip
chore: Move everything into one big crate
That helps remove duplicated code and rustc/cargo will now also show dead code correctly.
Diffstat (limited to 'crates/turtle/src/command/client/sync.rs')
-rw-r--r--crates/turtle/src/command/client/sync.rs120
1 files changed, 120 insertions, 0 deletions
diff --git a/crates/turtle/src/command/client/sync.rs b/crates/turtle/src/command/client/sync.rs
new file mode 100644
index 00000000..a4839b5f
--- /dev/null
+++ b/crates/turtle/src/command/client/sync.rs
@@ -0,0 +1,120 @@
+use clap::Subcommand;
+use eyre::{Result, WrapErr};
+
+use crate::atuin_client::{
+ database::Database,
+ encryption,
+ history::store::HistoryStore,
+ record::{sqlite_store::SqliteStore, store::Store, sync},
+ settings::Settings,
+};
+
+mod status;
+
+use crate::command::client::account;
+
+#[derive(Subcommand, Debug)]
+#[command(infer_subcommands = true)]
+pub enum Cmd {
+ /// Sync with the configured server
+ Sync {
+ /// Force re-download everything
+ #[arg(long, short)]
+ force: bool,
+ },
+
+ /// Login to the configured server
+ Login(account::login::Cmd),
+
+ /// Log out
+ Logout,
+
+ /// Register with the configured server
+ Register(account::register::Cmd),
+
+ /// Print the encryption key for transfer to another machine
+ Key {},
+
+ /// Display the sync status
+ Status,
+}
+
+impl Cmd {
+ pub async fn run(
+ self,
+ settings: Settings,
+ db: &impl Database,
+ store: SqliteStore,
+ ) -> Result<()> {
+ match self {
+ Self::Sync { force } => run(&settings, force, db, store).await,
+ Self::Login(l) => l.run(&settings, &store).await,
+ Self::Logout => account::logout::run().await,
+ Self::Register(r) => r.run(&settings).await,
+ Self::Status => status::run(&settings).await,
+ Self::Key {} => {
+ use crate::atuin_client::encryption::{encode_key, load_key};
+ let key = load_key(&settings).wrap_err("could not load encryption key")?;
+
+ let encode = encode_key(&key).wrap_err("could not encode encryption key")?;
+ println!("{encode}");
+
+ Ok(())
+ }
+ }
+ }
+}
+
+async fn run(
+ settings: &Settings,
+ force: bool,
+ db: &impl Database,
+ store: SqliteStore,
+) -> Result<()> {
+ let encryption_key: [u8; 32] = encryption::load_key(settings)
+ .context("could not load encryption key")?
+ .into();
+
+ let host_id = Settings::host_id().await?;
+ let history_store = HistoryStore::new(store.clone(), host_id, encryption_key);
+
+ let (uploaded, downloaded) = sync::sync(settings, &store, &encryption_key)
+ .await
+ .map_err(crate::print_error::format_sync_error)?;
+
+ crate::sync::build(settings, &store, db, Some(&downloaded)).await?;
+
+ println!("{uploaded}/{} up/down to record store", downloaded.len());
+
+ let history_length = db.history_count(true).await?;
+ let store_history_length = store.len_tag("history").await?;
+
+ #[expect(clippy::cast_sign_loss)]
+ if history_length as u64 > store_history_length {
+ println!("{history_length} in history index, but {store_history_length} in history store");
+ println!("Running automatic history store init...");
+
+ // Internally we use the global filter mode, so this context is ignored.
+ // don't recurse or loop here.
+ history_store.init_store(db).await?;
+
+ println!("Re-running sync due to new records locally");
+
+ // we'll want to run sync once more, as there will now be stuff to upload
+ let (uploaded, downloaded) = sync::sync(settings, &store, &encryption_key)
+ .await
+ .map_err(crate::print_error::format_sync_error)?;
+
+ crate::sync::build(settings, &store, db, Some(&downloaded)).await?;
+
+ println!("{uploaded}/{} up/down to record store", downloaded.len());
+ }
+
+ println!(
+ "Sync complete! {} items in history database, force: {}",
+ db.history_count(true).await?,
+ force
+ );
+
+ Ok(())
+}