summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEllie Huxtable <ellie@elliehuxtable.com>2024-01-30 13:41:01 +0000
committerGitHub <noreply@github.com>2024-01-30 13:41:01 +0000
commit9597080825565b2ba8ea202b7027e91b02aaac7f (patch)
treefbd896580e6bd927416799874a4a51b54f7771ee
parent366b8ea97bbe36ad5e3dd8d45f1e787ee2a7f223 (diff)
feat: add store push (#1649)
* feat: add store push * only push for the current host unless specified * tidy up * tidy up some more * sort features
-rw-r--r--Cargo.lock1
-rw-r--r--atuin-client/src/record/mod.rs1
-rw-r--r--atuin/Cargo.toml1
-rw-r--r--atuin/src/command/client/history.rs6
-rw-r--r--atuin/src/command/client/store.rs60
-rw-r--r--atuin/src/command/client/store/push.rs68
-rw-r--r--atuin/src/command/client/store/rebuild.rs52
-rw-r--r--atuin/tests/common/mod.rs5
-rw-r--r--atuin/tests/sync.rs9
-rw-r--r--atuin/tests/users.rs12
10 files changed, 143 insertions, 72 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 688862e9..e7c52eef 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -202,6 +202,7 @@ dependencies = [
"tracing-subscriber",
"tracing-tree",
"unicode-width",
+ "uuid",
"whoami",
]
diff --git a/atuin-client/src/record/mod.rs b/atuin-client/src/record/mod.rs
index 8bc816ae..c40fd395 100644
--- a/atuin-client/src/record/mod.rs
+++ b/atuin-client/src/record/mod.rs
@@ -1,5 +1,6 @@
pub mod encryption;
pub mod sqlite_store;
pub mod store;
+
#[cfg(feature = "sync")]
pub mod sync;
diff --git a/atuin/Cargo.toml b/atuin/Cargo.toml
index 5da8d149..7664db5d 100644
--- a/atuin/Cargo.toml
+++ b/atuin/Cargo.toml
@@ -76,6 +76,7 @@ colored = "2.0.4"
ratatui = "0.25"
tracing = "0.1"
cli-clipboard = { version = "0.4.0", optional = true }
+uuid = { workspace = true }
[dependencies.tracing-subscriber]
diff --git a/atuin/src/command/client/history.rs b/atuin/src/command/client/history.rs
index 18ae17cf..29a0bdf3 100644
--- a/atuin/src/command/client/history.rs
+++ b/atuin/src/command/client/history.rs
@@ -13,7 +13,7 @@ use atuin_client::{
database::{current_context, Database},
encryption,
history::{store::HistoryStore, History},
- record::{self, sqlite_store::SqliteStore},
+ record::sqlite_store::SqliteStore,
settings::{
FilterMode::{Directory, Global, Session},
Settings,
@@ -21,7 +21,8 @@ use atuin_client::{
};
#[cfg(feature = "sync")]
-use atuin_client::sync;
+use atuin_client::{record, sync};
+
use log::{debug, warn};
use time::{macros::format_description, OffsetDateTime};
@@ -278,6 +279,7 @@ impl Cmd {
Ok(())
}
+ #[allow(unused_variables)]
async fn handle_end(
db: &impl Database,
store: SqliteStore,
diff --git a/atuin/src/command/client/store.rs b/atuin/src/command/client/store.rs
index 640a284b..0d132c50 100644
--- a/atuin/src/command/client/store.rs
+++ b/atuin/src/command/client/store.rs
@@ -1,65 +1,26 @@
-use clap::{Args, Subcommand};
-use eyre::{bail, Result};
+use clap::Subcommand;
+use eyre::Result;
use atuin_client::{
database::Database,
- encryption,
- history::store::HistoryStore,
record::{sqlite_store::SqliteStore, store::Store},
settings::Settings,
};
use time::OffsetDateTime;
-#[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(())
- }
+#[cfg(feature = "sync")]
+mod push;
- 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().expect("failed to get host_id");
- let history_store = HistoryStore::new(store, host_id, encryption_key);
-
- history_store.build(database).await?;
-
- Ok(())
- }
-}
+mod rebuild;
#[derive(Subcommand, Debug)]
#[command(infer_subcommands = true)]
pub enum Cmd {
Status,
- Rebuild(Rebuild),
+ Rebuild(rebuild::Rebuild),
+
+ #[cfg(feature = "sync")]
+ Push(push::Push),
}
impl Cmd {
@@ -72,6 +33,9 @@ impl Cmd {
match self {
Self::Status => self.status(store).await,
Self::Rebuild(rebuild) => rebuild.run(settings, store, database).await,
+
+ #[cfg(feature = "sync")]
+ Self::Push(push) => push.run(settings, store).await,
}
}
diff --git a/atuin/src/command/client/store/push.rs b/atuin/src/command/client/store/push.rs
new file mode 100644
index 00000000..a5bd2dd0
--- /dev/null
+++ b/atuin/src/command/client/store/push.rs
@@ -0,0 +1,68 @@
+use atuin_common::record::HostId;
+use clap::Args;
+use eyre::Result;
+use uuid::Uuid;
+
+use atuin_client::{
+ 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>,
+}
+
+impl Push {
+ pub async fn run(&self, settings: &Settings, store: SqliteStore) -> Result<()> {
+ let host_id = Settings::host_id().expect("failed to get host_id");
+ // 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 (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::Download { .. } => false,
+
+ // push, so yes plz to uploads!
+ Operation::Upload { host, tag, .. } => {
+ 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() {
+ if t != *tag {
+ return false;
+ }
+ }
+
+ true
+ }
+ })
+ .collect();
+
+ let (uploaded, _) = sync::sync_remote(operations, &store, settings).await?;
+
+ println!("Uploaded {uploaded} records");
+
+ Ok(())
+ }
+}
diff --git a/atuin/src/command/client/store/rebuild.rs b/atuin/src/command/client/store/rebuild.rs
new file mode 100644
index 00000000..880647b4
--- /dev/null
+++ b/atuin/src/command/client/store/rebuild.rs
@@ -0,0 +1,52 @@
+use clap::Args;
+use eyre::{bail, Result};
+
+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().expect("failed to get host_id");
+ let history_store = HistoryStore::new(store, host_id, encryption_key);
+
+ history_store.build(database).await?;
+
+ Ok(())
+ }
+}
diff --git a/atuin/tests/common/mod.rs b/atuin/tests/common/mod.rs
index bda6abd3..65679244 100644
--- a/atuin/tests/common/mod.rs
+++ b/atuin/tests/common/mod.rs
@@ -1,11 +1,10 @@
use std::{env, time::Duration};
use atuin_client::api_client;
-use atuin_common::{api::AddHistoryRequest, utils::uuid_v7};
+use atuin_common::utils::uuid_v7;
use atuin_server::{launch_with_tcp_listener, Settings as ServerSettings};
use atuin_server_postgres::{Postgres, PostgresSettings};
use futures_util::TryFutureExt;
-use time::OffsetDateTime;
use tokio::{net::TcpListener, sync::oneshot, task::JoinHandle};
use tracing::{dispatcher, Dispatch};
use tracing_subscriber::{layer::SubscriberExt, EnvFilter};
@@ -80,6 +79,7 @@ pub async fn register_inner<'a>(
api_client::Client::new(address, &registration_response.session, 5, 30).unwrap()
}
+#[allow(dead_code)]
pub async fn login(address: &str, username: String, password: String) -> api_client::Client<'_> {
// registration works
let login_respose = api_client::login(
@@ -92,6 +92,7 @@ pub async fn login(address: &str, username: String, password: String) -> api_cli
api_client::Client::new(address, &login_respose.session, 5, 30).unwrap()
}
+#[allow(dead_code)]
pub async fn register(address: &str) -> api_client::Client<'_> {
let username = uuid_v7().as_simple().to_string();
let password = uuid_v7().as_simple().to_string();
diff --git a/atuin/tests/sync.rs b/atuin/tests/sync.rs
index 1835b20b..7e25d1c2 100644
--- a/atuin/tests/sync.rs
+++ b/atuin/tests/sync.rs
@@ -1,14 +1,5 @@
-use std::{env, time::Duration};
-
-use atuin_client::api_client;
use atuin_common::{api::AddHistoryRequest, utils::uuid_v7};
-use atuin_server::{launch_with_tcp_listener, Settings as ServerSettings};
-use atuin_server_postgres::{Postgres, PostgresSettings};
-use futures_util::TryFutureExt;
use time::OffsetDateTime;
-use tokio::{net::TcpListener, sync::oneshot, task::JoinHandle};
-use tracing::{dispatcher, Dispatch};
-use tracing_subscriber::{layer::SubscriberExt, EnvFilter};
mod common;
diff --git a/atuin/tests/users.rs b/atuin/tests/users.rs
index 8580d64c..95fb533b 100644
--- a/atuin/tests/users.rs
+++ b/atuin/tests/users.rs
@@ -1,14 +1,4 @@
-use std::{env, time::Duration};
-
-use atuin_client::api_client;
-use atuin_common::{api::AddHistoryRequest, utils::uuid_v7};
-use atuin_server::{launch_with_tcp_listener, Settings as ServerSettings};
-use atuin_server_postgres::{Postgres, PostgresSettings};
-use futures_util::TryFutureExt;
-use time::OffsetDateTime;
-use tokio::{net::TcpListener, sync::oneshot, task::JoinHandle};
-use tracing::{dispatcher, Dispatch};
-use tracing_subscriber::{layer::SubscriberExt, EnvFilter};
+use atuin_common::utils::uuid_v7;
mod common;