aboutsummaryrefslogtreecommitdiffstats
path: root/crates/atuin/src/command/client/store
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/atuin/src/command/client/store
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/atuin/src/command/client/store')
-rw-r--r--crates/atuin/src/command/client/store/pull.rs94
-rw-r--r--crates/atuin/src/command/client/store/purge.rs26
-rw-r--r--crates/atuin/src/command/client/store/push.rs112
-rw-r--r--crates/atuin/src/command/client/store/rebuild.rs58
-rw-r--r--crates/atuin/src/command/client/store/rekey.rs41
-rw-r--r--crates/atuin/src/command/client/store/verify.rs26
6 files changed, 0 insertions, 357 deletions
diff --git a/crates/atuin/src/command/client/store/pull.rs b/crates/atuin/src/command/client/store/pull.rs
deleted file mode 100644
index 25b925c7..00000000
--- a/crates/atuin/src/command/client/store/pull.rs
+++ /dev/null
@@ -1,94 +0,0 @@
-use clap::Args;
-use eyre::Result;
-
-use atuin_client::{
- database::Database,
- encryption::load_key,
- record::store::Store,
- record::sync::Operation,
- record::{sqlite_store::SqliteStore, sync},
- settings::Settings,
-};
-
-#[derive(Args, Debug)]
-pub struct Pull {
- /// The tag to push (eg, 'history'). Defaults to all tags
- #[arg(long, short)]
- pub tag: Option<String>,
-
- /// Force push records
- /// This will first wipe the local store, and then download all records from the remote
- #[arg(long, default_value = "false")]
- pub force: bool,
-
- /// Page Size
- /// How many records to download at once. Defaults to 100
- #[arg(long, default_value = "100")]
- pub page: u64,
-}
-
-impl Pull {
- pub async fn run(
- &self,
- settings: &Settings,
- store: SqliteStore,
- db: &dyn Database,
- ) -> Result<()> {
- if self.force {
- println!("Forcing local overwrite!");
- println!("Clearing local store");
-
- store.delete_all().await?;
- }
-
- // We can actually just use the existing diff/etc to push
- // 1. Diff
- // 2. Get operations
- // 3. Filter operations by
- // a) are they a download op?
- // b) are they for the host/tag we are pushing here?
- let client = sync::build_client(settings).await?;
- let (diff, remote_index) = sync::diff(&client, &store).await?;
-
- // Skip on --force: local was already wiped above, mismatch is the user's call.
- if !self.force {
- let key: [u8; 32] = load_key(settings)?.into();
- sync::check_encryption_key(&client, &remote_index, &key)
- .await
- .map_err(crate::print_error::format_sync_error)?;
- }
-
- let operations = sync::operations(diff, &store).await?;
-
- let operations = operations
- .into_iter()
- .filter(|op| match op {
- // No noops or downloads thx
- Operation::Noop { .. } | Operation::Upload { .. } => false,
-
- // pull, so yes plz to downloads!
- Operation::Download { tag, .. } => {
- if self.force {
- return true;
- }
-
- if let Some(t) = self.tag.clone()
- && t != *tag
- {
- return false;
- }
-
- true
- }
- })
- .collect();
-
- let (_, downloaded) = sync::sync_remote(&client, operations, &store, self.page).await?;
-
- println!("Downloaded {} records", downloaded.len());
-
- crate::sync::build(settings, &store, db, Some(&downloaded)).await?;
-
- Ok(())
- }
-}
diff --git a/crates/atuin/src/command/client/store/purge.rs b/crates/atuin/src/command/client/store/purge.rs
deleted file mode 100644
index ad2369ce..00000000
--- a/crates/atuin/src/command/client/store/purge.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-use clap::Args;
-use eyre::Result;
-
-use atuin_client::{
- encryption::load_key,
- record::{sqlite_store::SqliteStore, store::Store},
- settings::Settings,
-};
-
-#[derive(Args, Debug)]
-pub struct Purge {}
-
-impl Purge {
- pub async fn run(&self, settings: &Settings, store: SqliteStore) -> Result<()> {
- println!("Purging local records that cannot be decrypted");
-
- let key = load_key(settings)?;
-
- match store.purge(&key.into()).await {
- Ok(()) => println!("Local store purge completed OK"),
- Err(e) => println!("Failed to purge local store: {e:?}"),
- }
-
- Ok(())
- }
-}
diff --git a/crates/atuin/src/command/client/store/push.rs b/crates/atuin/src/command/client/store/push.rs
deleted file mode 100644
index d8569e1e..00000000
--- a/crates/atuin/src/command/client/store/push.rs
+++ /dev/null
@@ -1,112 +0,0 @@
-use atuin_common::record::HostId;
-use clap::Args;
-use eyre::Result;
-use uuid::Uuid;
-
-use atuin_client::{
- api_client::Client,
- encryption::load_key,
- record::sync::Operation,
- record::{sqlite_store::SqliteStore, sync},
- settings::Settings,
-};
-
-#[derive(Args, Debug)]
-pub struct Push {
- /// The tag to push (eg, 'history'). Defaults to all tags
- #[arg(long, short)]
- pub tag: Option<String>,
-
- /// The host to push, in the form of a UUID host ID. Defaults to the current host.
- #[arg(long)]
- pub host: Option<Uuid>,
-
- /// Force push records
- /// This will override both host and tag, to be all hosts and all tags. First clear the remote store, then upload all of the
- /// local store
- #[arg(long, default_value = "false")]
- pub force: bool,
-
- /// Page Size
- /// How many records to upload at once. Defaults to 100
- #[arg(long, default_value = "100")]
- pub page: u64,
-}
-
-impl Push {
- pub async fn run(&self, settings: &Settings, store: SqliteStore) -> Result<()> {
- let host_id = Settings::host_id().await?;
-
- if self.force {
- println!("Forcing remote store overwrite!");
- println!("Clearing remote store");
-
- let client = Client::new(
- &settings.sync_address,
- settings.sync_auth_token().await?,
- settings.network_connect_timeout,
- settings.network_timeout * 10, // we may be deleting a lot of data... so up the
- // timeout
- )
- .expect("failed to create client");
-
- client.delete_store().await?;
- }
-
- // We can actually just use the existing diff/etc to push
- // 1. Diff
- // 2. Get operations
- // 3. Filter operations by
- // a) are they an upload op?
- // b) are they for the host/tag we are pushing here?
- let client = sync::build_client(settings).await?;
- let (diff, remote_index) = sync::diff(&client, &store).await?;
-
- // Skip on --force: that path intentionally replaces remote with local.
- if !self.force {
- let key: [u8; 32] = load_key(settings)?.into();
- sync::check_encryption_key(&client, &remote_index, &key)
- .await
- .map_err(crate::print_error::format_sync_error)?;
- }
-
- let operations = sync::operations(diff, &store).await?;
-
- let operations = operations
- .into_iter()
- .filter(|op| match op {
- // No noops or downloads thx
- Operation::Noop { .. } | Operation::Download { .. } => false,
-
- // push, so yes plz to uploads!
- Operation::Upload { host, tag, .. } => {
- if self.force {
- return true;
- }
-
- if let Some(h) = self.host {
- if HostId(h) != *host {
- return false;
- }
- } else if *host != host_id {
- return false;
- }
-
- if let Some(t) = self.tag.clone()
- && t != *tag
- {
- return false;
- }
-
- true
- }
- })
- .collect();
-
- let (uploaded, _) = sync::sync_remote(&client, operations, &store, self.page).await?;
-
- println!("Uploaded {uploaded} records");
-
- Ok(())
- }
-}
diff --git a/crates/atuin/src/command/client/store/rebuild.rs b/crates/atuin/src/command/client/store/rebuild.rs
deleted file mode 100644
index b9f2837b..00000000
--- a/crates/atuin/src/command/client/store/rebuild.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-use clap::Args;
-use eyre::{Result, bail};
-
-#[cfg(feature = "daemon")]
-use crate::command::client::daemon as daemon_cmd;
-
-use atuin_client::{
- database::Database, encryption, history::store::HistoryStore,
- record::sqlite_store::SqliteStore, settings::Settings,
-};
-
-#[derive(Args, Debug)]
-pub struct Rebuild {
- pub tag: String,
-}
-
-impl Rebuild {
- pub async fn run(
- &self,
- settings: &Settings,
- store: SqliteStore,
- database: &dyn Database,
- ) -> Result<()> {
- // keep it as a string and not an enum atm
- // would be super cool to build this dynamically in the future
- // eg register handles for rebuilding various tags without having to make this part of the
- // binary big
- match self.tag.as_str() {
- "history" => {
- self.rebuild_history(settings, store.clone(), database)
- .await?;
- }
-
- tag => bail!("unknown tag: {tag}"),
- }
-
- Ok(())
- }
-
- async fn rebuild_history(
- &self,
- settings: &Settings,
- store: SqliteStore,
- database: &dyn Database,
- ) -> Result<()> {
- let encryption_key: [u8; 32] = encryption::load_key(settings)?.into();
-
- let host_id = Settings::host_id().await?;
- let history_store = HistoryStore::new(store, host_id, encryption_key);
-
- history_store.build(database).await?;
-
- #[cfg(feature = "daemon")]
- daemon_cmd::emit_event(settings, atuin_daemon::DaemonEvent::HistoryRebuilt).await;
-
- Ok(())
- }
-}
diff --git a/crates/atuin/src/command/client/store/rekey.rs b/crates/atuin/src/command/client/store/rekey.rs
deleted file mode 100644
index c92d2555..00000000
--- a/crates/atuin/src/command/client/store/rekey.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-use clap::Args;
-use eyre::Result;
-use tokio::{fs::File, io::AsyncWriteExt};
-
-use atuin_client::{
- encryption::{decode_key, generate_encoded_key, load_key},
- record::sqlite_store::SqliteStore,
- record::store::Store,
- settings::Settings,
-};
-
-#[derive(Args, Debug)]
-pub struct Rekey {
- /// The new key to use for encryption. Omit for a randomly-generated key
- key: Option<String>,
-}
-
-impl Rekey {
- pub async fn run(&self, settings: &Settings, store: SqliteStore) -> Result<()> {
- let key = if let Some(key) = self.key.clone() {
- println!("Re-encrypting store with specified key");
-
- key
- } else {
- println!("Re-encrypting store with freshly-generated key");
- let (_, encoded) = generate_encoded_key()?;
- encoded
- };
-
- let current_key: [u8; 32] = load_key(settings)?.into();
- let new_key: [u8; 32] = decode_key(key.clone())?.into();
-
- store.re_encrypt(&current_key, &new_key).await?;
-
- println!("Store rewritten. Saving new key");
- let mut file = File::create(settings.key_path.clone()).await?;
- file.write_all(key.as_bytes()).await?;
-
- Ok(())
- }
-}
diff --git a/crates/atuin/src/command/client/store/verify.rs b/crates/atuin/src/command/client/store/verify.rs
deleted file mode 100644
index 84bec96a..00000000
--- a/crates/atuin/src/command/client/store/verify.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-use clap::Args;
-use eyre::Result;
-
-use atuin_client::{
- encryption::load_key,
- record::{sqlite_store::SqliteStore, store::Store},
- settings::Settings,
-};
-
-#[derive(Args, Debug)]
-pub struct Verify {}
-
-impl Verify {
- pub async fn run(&self, settings: &Settings, store: SqliteStore) -> Result<()> {
- println!("Verifying local store can be decrypted with the current key");
-
- let key = load_key(settings)?;
-
- match store.verify(&key.into()).await {
- Ok(()) => println!("Local store encryption verified OK"),
- Err(e) => println!("Failed to verify local store encryption: {e:?}"),
- }
-
- Ok(())
- }
-}