mirror of
https://github.com/atuinsh/atuin.git
synced 2025-01-17 03:39:49 +01:00
feat: add store pull
This allows the user to 1. Specify that they want to sync, but ONLY pull new data 2. Specify that they wish to force pull, which will wipe the local store and download it from the remote With the other set of changes, this allows the user to perform sufficient maintenance to recovery from most errors I can think of right now.
This commit is contained in:
parent
c9a453289e
commit
374255dd58
@ -154,6 +154,12 @@ impl Store for SqliteStore {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete_all(&self) -> Result<()> {
|
||||
sqlx::query("delete from store").execute(&self.pool).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn last(&self, host: HostId, tag: &str) -> Result<Option<Record<EncryptedData>>> {
|
||||
let res =
|
||||
sqlx::query("select * from store where host=?1 and tag=?2 order by idx desc limit 1")
|
||||
|
@ -21,7 +21,9 @@ pub trait Store {
|
||||
) -> Result<()>;
|
||||
|
||||
async fn get(&self, id: RecordId) -> Result<Record<EncryptedData>>;
|
||||
|
||||
async fn delete(&self, id: RecordId) -> Result<()>;
|
||||
async fn delete_all(&self) -> Result<()>;
|
||||
|
||||
async fn len(&self, host: HostId, tag: &str) -> Result<u64>;
|
||||
async fn len_tag(&self, tag: &str) -> Result<u64>;
|
||||
|
@ -11,6 +11,9 @@ use time::OffsetDateTime;
|
||||
#[cfg(feature = "sync")]
|
||||
mod push;
|
||||
|
||||
#[cfg(feature = "sync")]
|
||||
mod pull;
|
||||
|
||||
mod purge;
|
||||
mod rebuild;
|
||||
mod rekey;
|
||||
@ -27,6 +30,9 @@ pub enum Cmd {
|
||||
|
||||
#[cfg(feature = "sync")]
|
||||
Push(push::Push),
|
||||
|
||||
#[cfg(feature = "sync")]
|
||||
Pull(pull::Pull),
|
||||
}
|
||||
|
||||
impl Cmd {
|
||||
@ -45,6 +51,9 @@ impl Cmd {
|
||||
|
||||
#[cfg(feature = "sync")]
|
||||
Self::Push(push) => push.run(settings, store).await,
|
||||
|
||||
#[cfg(feature = "sync")]
|
||||
Self::Pull(pull) => pull.run(settings, store, database).await,
|
||||
}
|
||||
}
|
||||
|
||||
|
86
atuin/src/command/client/store/pull.rs
Normal file
86
atuin/src/command/client/store/pull.rs
Normal file
@ -0,0 +1,86 @@
|
||||
use clap::Args;
|
||||
use eyre::{Result, WrapErr};
|
||||
|
||||
use atuin_client::{
|
||||
database::Database,
|
||||
encryption,
|
||||
history::store::HistoryStore,
|
||||
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,
|
||||
}
|
||||
|
||||
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 (diff, _) = sync::diff(settings, &store).await?;
|
||||
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() {
|
||||
if t != *tag {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let (_, downloaded) = sync::sync_remote(operations, &store, settings).await?;
|
||||
|
||||
println!("Downloaded {} records", downloaded.len());
|
||||
|
||||
let encryption_key: [u8; 32] = encryption::load_key(settings)
|
||||
.context("could not load encryption key")?
|
||||
.into();
|
||||
|
||||
let host_id = Settings::host_id().expect("failed to get host_id");
|
||||
let history_store = HistoryStore::new(store.clone(), host_id, encryption_key);
|
||||
history_store.incremental_build(db, &downloaded).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user