mirror of
https://github.com/atuinsh/atuin.git
synced 2025-08-17 10:31:42 +02:00
chore: migrate to rust 2024 (#2635)
* chore: upgrade to 2024 edition * ugh unsafe * format * nixxxxxxxxxxx why
This commit is contained in:
1119
Cargo.lock
generated
1119
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "atuin-client"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
description = "client library for atuin"
|
||||
|
||||
rust-version = { workspace = true }
|
||||
|
@ -2,12 +2,16 @@ use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::time::Duration;
|
||||
|
||||
use eyre::{bail, Result};
|
||||
use eyre::{Result, bail};
|
||||
use reqwest::{
|
||||
header::{HeaderMap, AUTHORIZATION, USER_AGENT},
|
||||
Response, StatusCode, Url,
|
||||
header::{AUTHORIZATION, HeaderMap, USER_AGENT},
|
||||
};
|
||||
|
||||
use atuin_common::{
|
||||
api::{ATUIN_CARGO_VERSION, ATUIN_HEADER_VERSION, ATUIN_VERSION},
|
||||
record::{EncryptedData, HostId, Record, RecordIdx},
|
||||
};
|
||||
use atuin_common::{
|
||||
api::{
|
||||
AddHistoryRequest, ChangePasswordRequest, CountResponse, DeleteHistoryRequest,
|
||||
@ -17,14 +21,10 @@ use atuin_common::{
|
||||
},
|
||||
record::RecordStatus,
|
||||
};
|
||||
use atuin_common::{
|
||||
api::{ATUIN_CARGO_VERSION, ATUIN_HEADER_VERSION, ATUIN_VERSION},
|
||||
record::{EncryptedData, HostId, Record, RecordIdx},
|
||||
};
|
||||
|
||||
use semver::Version;
|
||||
use time::format_description::well_known::Rfc3339;
|
||||
use time::OffsetDateTime;
|
||||
use time::format_description::well_known::Rfc3339;
|
||||
|
||||
use crate::{history::History, sync::hash_str, utils::get_host_user};
|
||||
|
||||
@ -126,7 +126,9 @@ pub fn ensure_version(response: &Response) -> Result<bool> {
|
||||
|
||||
// If the client is newer than the server
|
||||
if version.major < ATUIN_VERSION.major {
|
||||
println!("Atuin version mismatch! In order to successfully sync, the server needs to run a newer version of Atuin");
|
||||
println!(
|
||||
"Atuin version mismatch! In order to successfully sync, the server needs to run a newer version of Atuin"
|
||||
);
|
||||
println!("Client: {}", ATUIN_CARGO_VERSION);
|
||||
println!("Server: {}", version);
|
||||
|
||||
@ -157,10 +159,14 @@ async fn handle_resp_error(resp: Response) -> Result<Response> {
|
||||
bail!("Invalid request to the service: {status} - {reason}.")
|
||||
}
|
||||
|
||||
bail!("There was an error with the atuin sync service, server error {status}: {reason}.\nIf the problem persists, contact the host")
|
||||
bail!(
|
||||
"There was an error with the atuin sync service, server error {status}: {reason}.\nIf the problem persists, contact the host"
|
||||
)
|
||||
}
|
||||
|
||||
bail!("There was an error with the atuin sync service: Status {status:?}.\nIf the problem persists, contact the host")
|
||||
bail!(
|
||||
"There was an error with the atuin sync service: Status {status:?}.\nIf the problem persists, contact the host"
|
||||
)
|
||||
}
|
||||
|
||||
Ok(resp)
|
||||
|
@ -10,14 +10,14 @@ use async_trait::async_trait;
|
||||
use atuin_common::utils;
|
||||
use fs_err as fs;
|
||||
use itertools::Itertools;
|
||||
use rand::{distributions::Alphanumeric, Rng};
|
||||
use sql_builder::{bind::Bind, esc, quote, SqlBuilder, SqlName};
|
||||
use rand::{Rng, distributions::Alphanumeric};
|
||||
use sql_builder::{SqlBuilder, SqlName, bind::Bind, esc, quote};
|
||||
use sqlx::{
|
||||
Result, Row,
|
||||
sqlite::{
|
||||
SqliteConnectOptions, SqliteJournalMode, SqlitePool, SqlitePoolOptions, SqliteRow,
|
||||
SqliteSynchronous,
|
||||
},
|
||||
Result, Row,
|
||||
};
|
||||
use time::OffsetDateTime;
|
||||
|
||||
@ -55,7 +55,9 @@ pub struct OptFilters {
|
||||
|
||||
pub fn current_context() -> Context {
|
||||
let Ok(session) = env::var("ATUIN_SESSION") else {
|
||||
eprintln!("ERROR: Failed to find $ATUIN_SESSION in the environment. Check that you have correctly set up your shell.");
|
||||
eprintln!(
|
||||
"ERROR: Failed to find $ATUIN_SESSION in the environment. Check that you have correctly set up your shell."
|
||||
);
|
||||
std::process::exit(1);
|
||||
};
|
||||
let hostname = get_host_user();
|
||||
@ -131,7 +133,9 @@ impl Sqlite {
|
||||
debug!("opening sqlite database at {:?}", path);
|
||||
|
||||
if utils::broken_symlink(path) {
|
||||
eprintln!("Atuin: Sqlite db path ({path:?}) is a broken symlink. Unable to read or create replacement.");
|
||||
eprintln!(
|
||||
"Atuin: Sqlite db path ({path:?}) is a broken symlink. Unable to read or create replacement."
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
|
@ -10,17 +10,17 @@
|
||||
|
||||
use std::{io::prelude::*, path::PathBuf};
|
||||
|
||||
use base64::prelude::{Engine, BASE64_STANDARD};
|
||||
use base64::prelude::{BASE64_STANDARD, Engine};
|
||||
pub use crypto_secretbox::Key;
|
||||
use crypto_secretbox::{
|
||||
aead::{Nonce, OsRng},
|
||||
AeadCore, AeadInPlace, KeyInit, XSalsa20Poly1305,
|
||||
aead::{Nonce, OsRng},
|
||||
};
|
||||
use eyre::{bail, ensure, eyre, Context, Result};
|
||||
use eyre::{Context, Result, bail, ensure, eyre};
|
||||
use fs_err as fs;
|
||||
use rmp::{decode::Bytes, Marker};
|
||||
use rmp::{Marker, decode::Bytes};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::{format_description::well_known::Rfc3339, macros::format_description, OffsetDateTime};
|
||||
use time::{OffsetDateTime, format_description::well_known::Rfc3339, macros::format_description};
|
||||
|
||||
use crate::{history::History, settings::Settings};
|
||||
|
||||
@ -265,9 +265,9 @@ fn error_report<E: std::fmt::Debug>(err: E) -> eyre::Report {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crypto_secretbox::{aead::OsRng, KeyInit, XSalsa20Poly1305};
|
||||
use crypto_secretbox::{KeyInit, XSalsa20Poly1305, aead::OsRng};
|
||||
use pretty_assertions::assert_eq;
|
||||
use time::{macros::datetime, OffsetDateTime};
|
||||
use time::{OffsetDateTime, macros::datetime};
|
||||
|
||||
use crate::history::History;
|
||||
|
||||
@ -392,7 +392,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn key_encodings() {
|
||||
use super::{decode_key, encode_key, Key};
|
||||
use super::{Key, decode_key, encode_key};
|
||||
|
||||
// a history of our key encodings.
|
||||
// v11.0.0 xCAbWypb0msJ2Kq+8j4GVEWUlDX7deKnrTRSIopuqXxc5Q==
|
||||
|
@ -1,13 +1,13 @@
|
||||
use core::fmt::Formatter;
|
||||
use rmp::decode::ValueReadError;
|
||||
use rmp::{decode::Bytes, Marker};
|
||||
use rmp::{Marker, decode::Bytes};
|
||||
use std::env;
|
||||
use std::fmt::Display;
|
||||
|
||||
use atuin_common::record::DecryptedData;
|
||||
use atuin_common::utils::uuid_v7;
|
||||
|
||||
use eyre::{bail, eyre, Result};
|
||||
use eyre::{Result, bail, eyre};
|
||||
|
||||
use crate::secrets::SECRET_PATTERNS_RE;
|
||||
use crate::settings::Settings;
|
||||
|
@ -1,16 +1,16 @@
|
||||
use std::{collections::HashSet, fmt::Write, time::Duration};
|
||||
|
||||
use eyre::{bail, eyre, Result};
|
||||
use eyre::{Result, bail, eyre};
|
||||
use indicatif::{ProgressBar, ProgressState, ProgressStyle};
|
||||
use rmp::decode::Bytes;
|
||||
|
||||
use crate::{
|
||||
database::{current_context, Database},
|
||||
database::{Database, current_context},
|
||||
record::{encryption::PASETO_V4, sqlite_store::SqliteStore, store::Store},
|
||||
};
|
||||
use atuin_common::record::{DecryptedData, Host, HostId, Record, RecordId, RecordIdx};
|
||||
|
||||
use super::{History, HistoryId, HISTORY_TAG, HISTORY_VERSION};
|
||||
use super::{HISTORY_TAG, HISTORY_VERSION, History, HistoryId};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HistoryStore {
|
||||
@ -246,10 +246,11 @@ impl HistoryStore {
|
||||
for id in ids {
|
||||
let record = self.store.get(*id).await;
|
||||
|
||||
let record = if let Ok(record) = record {
|
||||
record
|
||||
} else {
|
||||
let record = match record {
|
||||
Ok(record) => record,
|
||||
_ => {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
if record.tag != HISTORY_TAG {
|
||||
@ -342,7 +343,7 @@ mod tests {
|
||||
use atuin_common::record::DecryptedData;
|
||||
use time::macros::datetime;
|
||||
|
||||
use crate::history::{store::HistoryRecord, HISTORY_VERSION};
|
||||
use crate::history::{HISTORY_VERSION, store::HistoryRecord};
|
||||
|
||||
use super::History;
|
||||
|
||||
|
@ -2,11 +2,11 @@ use std::{path::PathBuf, str};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use directories::UserDirs;
|
||||
use eyre::{eyre, Result};
|
||||
use eyre::{Result, eyre};
|
||||
use itertools::Itertools;
|
||||
use time::{Duration, OffsetDateTime};
|
||||
|
||||
use super::{get_histpath, unix_byte_lines, Importer, Loader};
|
||||
use super::{Importer, Loader, get_histpath, unix_byte_lines};
|
||||
use crate::history::History;
|
||||
use crate::import::read_to_end;
|
||||
|
||||
@ -73,7 +73,9 @@ impl Importer for Bash {
|
||||
LineType::Empty => {} // do nothing
|
||||
LineType::Timestamp(t) => {
|
||||
if t < next_timestamp {
|
||||
warn!("Time reversal detected in Bash history! Commands may be ordered incorrectly.");
|
||||
warn!(
|
||||
"Time reversal detected in Bash history! Commands may be ordered incorrectly."
|
||||
);
|
||||
}
|
||||
next_timestamp = t;
|
||||
}
|
||||
@ -126,9 +128,9 @@ fn try_parse_line_as_timestamp(line: &str) -> Option<OffsetDateTime> {
|
||||
mod test {
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use itertools::{assert_equal, Itertools};
|
||||
use itertools::{Itertools, assert_equal};
|
||||
|
||||
use crate::import::{tests::TestLoader, Importer};
|
||||
use crate::import::{Importer, tests::TestLoader};
|
||||
|
||||
use super::Bash;
|
||||
|
||||
|
@ -5,10 +5,10 @@ use std::path::PathBuf;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use directories::BaseDirs;
|
||||
use eyre::{eyre, Result};
|
||||
use eyre::{Result, eyre};
|
||||
use time::OffsetDateTime;
|
||||
|
||||
use super::{unix_byte_lines, Importer, Loader};
|
||||
use super::{Importer, Loader, unix_byte_lines};
|
||||
use crate::history::History;
|
||||
use crate::import::read_to_end;
|
||||
|
||||
@ -110,7 +110,7 @@ impl Importer for Fish {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use crate::import::{tests::TestLoader, Importer};
|
||||
use crate::import::{Importer, tests::TestLoader};
|
||||
|
||||
use super::Fish;
|
||||
|
||||
@ -160,7 +160,7 @@ ERROR
|
||||
|
||||
// simple wrapper for fish history entry
|
||||
macro_rules! fishtory {
|
||||
($timestamp:expr, $command:expr) => {
|
||||
($timestamp:expr_2021, $command:expr_2021) => {
|
||||
let h = history.next().expect("missing entry in history");
|
||||
assert_eq!(h.command.as_str(), $command);
|
||||
assert_eq!(h.timestamp.unix_timestamp(), $timestamp);
|
||||
|
@ -3,7 +3,7 @@ use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use eyre::{bail, Result};
|
||||
use eyre::{Result, bail};
|
||||
use memchr::Memchr;
|
||||
|
||||
use crate::history::History;
|
||||
|
@ -5,10 +5,10 @@ use std::path::PathBuf;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use directories::BaseDirs;
|
||||
use eyre::{eyre, Result};
|
||||
use eyre::{Result, eyre};
|
||||
use time::OffsetDateTime;
|
||||
|
||||
use super::{unix_byte_lines, Importer, Loader};
|
||||
use super::{Importer, Loader, unix_byte_lines};
|
||||
use crate::history::History;
|
||||
use crate::import::read_to_end;
|
||||
|
||||
|
@ -5,8 +5,8 @@ use std::path::PathBuf;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use directories::BaseDirs;
|
||||
use eyre::{eyre, Result};
|
||||
use sqlx::{sqlite::SqlitePool, Pool};
|
||||
use eyre::{Result, eyre};
|
||||
use sqlx::{Pool, sqlite::SqlitePool};
|
||||
use time::{Duration, OffsetDateTime};
|
||||
|
||||
use super::Importer;
|
||||
|
@ -2,10 +2,10 @@ use std::{path::PathBuf, str};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use directories::UserDirs;
|
||||
use eyre::{eyre, Result};
|
||||
use time::{macros::format_description, OffsetDateTime, PrimitiveDateTime};
|
||||
use eyre::{Result, eyre};
|
||||
use time::{OffsetDateTime, PrimitiveDateTime, macros::format_description};
|
||||
|
||||
use super::{get_histpath, unix_byte_lines, Importer, Loader};
|
||||
use super::{Importer, Loader, get_histpath, unix_byte_lines};
|
||||
use crate::history::History;
|
||||
use crate::import::read_to_end;
|
||||
|
||||
@ -72,7 +72,7 @@ fn try_parse_line_as_timestamp(line: &str) -> Option<OffsetDateTime> {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use crate::import::{tests::TestLoader, Importer};
|
||||
use crate::import::{Importer, tests::TestLoader};
|
||||
|
||||
use super::Replxx;
|
||||
|
||||
@ -100,7 +100,7 @@ CREATE TABLE test( stamp DateTime('UTC'))ENGINE = MergeTreePARTITION BY toDat
|
||||
|
||||
// simple wrapper for replxx history entry
|
||||
macro_rules! history {
|
||||
($timestamp:expr, $command:expr) => {
|
||||
($timestamp:expr_2021, $command:expr_2021) => {
|
||||
let h = history.next().expect("missing entry in history");
|
||||
assert_eq!(h.command.as_str(), $command);
|
||||
assert_eq!(h.timestamp.unix_timestamp(), $timestamp);
|
||||
@ -114,6 +114,9 @@ CREATE TABLE test( stamp DateTime('UTC'))ENGINE = MergeTreePARTITION BY toDat
|
||||
history!(1707603396, "select * from numbers(10)");
|
||||
history!(1707603401, "select * from system.numbers");
|
||||
history!(1707603568, "select 1");
|
||||
history!(1708600533, "CREATE TABLE test\n( stamp DateTime('UTC'))\nENGINE = MergeTree\nPARTITION BY toDate(stamp)\norder by tuple() as select toDateTime('2020-01-01')+number*60 from numbers(80000);");
|
||||
history!(
|
||||
1708600533,
|
||||
"CREATE TABLE test\n( stamp DateTime('UTC'))\nENGINE = MergeTree\nPARTITION BY toDate(stamp)\norder by tuple() as select toDateTime('2020-01-01')+number*60 from numbers(80000);"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,13 @@ use std::path::PathBuf;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use directories::UserDirs;
|
||||
use eyre::{eyre, Result};
|
||||
use eyre::{Result, eyre};
|
||||
use serde::Deserialize;
|
||||
|
||||
use atuin_common::utils::uuid_v7;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
use super::{get_histpath, unix_byte_lines, Importer, Loader};
|
||||
use super::{Importer, Loader, get_histpath, unix_byte_lines};
|
||||
use crate::history::History;
|
||||
use crate::import::read_to_end;
|
||||
|
||||
|
@ -4,13 +4,13 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use directories::BaseDirs;
|
||||
use eyre::{eyre, Result};
|
||||
use eyre::{Result, eyre};
|
||||
use serde::Deserialize;
|
||||
use time::OffsetDateTime;
|
||||
use uuid::timestamp::{context::NoContext, Timestamp};
|
||||
use uuid::Uuid;
|
||||
use uuid::timestamp::{Timestamp, context::NoContext};
|
||||
|
||||
use super::{get_histpath, Importer, Loader};
|
||||
use super::{Importer, Loader, get_histpath};
|
||||
use crate::history::History;
|
||||
use crate::utils::get_host_user;
|
||||
|
||||
|
@ -3,14 +3,14 @@ use std::path::PathBuf;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use directories::BaseDirs;
|
||||
use eyre::{eyre, Result};
|
||||
use eyre::{Result, eyre};
|
||||
use futures::TryStreamExt;
|
||||
use sqlx::{sqlite::SqlitePool, FromRow, Row};
|
||||
use sqlx::{FromRow, Row, sqlite::SqlitePool};
|
||||
use time::OffsetDateTime;
|
||||
use uuid::timestamp::{context::NoContext, Timestamp};
|
||||
use uuid::Uuid;
|
||||
use uuid::timestamp::{Timestamp, context::NoContext};
|
||||
|
||||
use super::{get_histpath, Importer, Loader};
|
||||
use super::{Importer, Loader, get_histpath};
|
||||
use crate::history::History;
|
||||
use crate::utils::get_host_user;
|
||||
|
||||
|
@ -6,10 +6,10 @@ use std::path::PathBuf;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use directories::UserDirs;
|
||||
use eyre::{eyre, Result};
|
||||
use eyre::{Result, eyre};
|
||||
use time::OffsetDateTime;
|
||||
|
||||
use super::{get_histpath, unix_byte_lines, Importer, Loader};
|
||||
use super::{Importer, Loader, get_histpath, unix_byte_lines};
|
||||
use crate::history::History;
|
||||
use crate::import::read_to_end;
|
||||
|
||||
@ -38,7 +38,7 @@ fn default_histpath() -> Result<PathBuf> {
|
||||
None => {
|
||||
break Err(eyre!(
|
||||
"Could not find history file. Try setting and exporting $HISTFILE"
|
||||
))
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ use std::path::{Path, PathBuf};
|
||||
use async_trait::async_trait;
|
||||
use atuin_common::utils::uuid_v7;
|
||||
use directories::UserDirs;
|
||||
use eyre::{eyre, Result};
|
||||
use sqlx::{sqlite::SqlitePool, Pool};
|
||||
use eyre::{Result, eyre};
|
||||
use sqlx::{Pool, sqlite::SqlitePool};
|
||||
use time::PrimitiveDateTime;
|
||||
|
||||
use super::Importer;
|
||||
@ -178,10 +178,12 @@ mod test {
|
||||
use sqlx::sqlite::SqlitePoolOptions;
|
||||
use std::env;
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
#[allow(unsafe_code)]
|
||||
async fn test_env_vars() {
|
||||
let test_env_db = "nonstd-zsh-history.db";
|
||||
let key = "HISTDB_FILE";
|
||||
env::set_var(key, test_env_db);
|
||||
// TODO: Audit that the environment access only happens in single-threaded code.
|
||||
unsafe { env::set_var(key, test_env_db) };
|
||||
|
||||
// test the env got set
|
||||
assert_eq!(env::var(key).unwrap(), test_env_db.to_string());
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use atuin_common::record::{DecryptedData, Host, HostId};
|
||||
use eyre::{bail, ensure, eyre, Result};
|
||||
use eyre::{Result, bail, ensure, eyre};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::record::encryption::PASETO_V4;
|
||||
@ -200,7 +200,7 @@ mod tests {
|
||||
use crate::record::sqlite_store::SqliteStore;
|
||||
use crate::settings::test_local_timeout;
|
||||
|
||||
use super::{KvRecord, KvStore, KV_VERSION};
|
||||
use super::{KV_VERSION, KvRecord, KvStore};
|
||||
|
||||
#[test]
|
||||
fn encode_decode() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(unsafe_code)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
@ -1,13 +1,13 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use atuin_common::api::LoginRequest;
|
||||
use eyre::{bail, Context, Result};
|
||||
use eyre::{Context, Result, bail};
|
||||
use tokio::fs::File;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
use crate::{
|
||||
api_client,
|
||||
encryption::{decode_key, encode_key, load_key, Key},
|
||||
encryption::{Key, decode_key, encode_key, load_key},
|
||||
record::{sqlite_store::SqliteStore, store::Store},
|
||||
settings::Settings,
|
||||
};
|
||||
@ -23,7 +23,8 @@ pub async fn login(
|
||||
let key = match bip39::Mnemonic::from_phrase(&key, bip39::Language::English) {
|
||||
Ok(mnemonic) => encode_key(Key::from_slice(mnemonic.entropy()))?,
|
||||
Err(err) => {
|
||||
if let Some(err) = err.downcast_ref::<bip39::ErrorKind>() {
|
||||
match err.downcast_ref::<bip39::ErrorKind>() {
|
||||
Some(err) => {
|
||||
match err {
|
||||
// assume they copied in the base64 key
|
||||
bip39::ErrorKind::InvalidWord => key,
|
||||
@ -36,11 +37,13 @@ pub async fn login(
|
||||
bail!("key was not the correct length")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
_ => {
|
||||
// unknown error. assume they copied the base64 key
|
||||
key
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let key_path = settings.key_path.as_str();
|
||||
|
@ -1,8 +1,8 @@
|
||||
use atuin_common::record::{
|
||||
AdditionalData, DecryptedData, EncryptedData, Encryption, HostId, RecordId, RecordIdx,
|
||||
};
|
||||
use base64::{engine::general_purpose, Engine};
|
||||
use eyre::{ensure, Context, Result};
|
||||
use base64::{Engine, engine::general_purpose};
|
||||
use eyre::{Context, Result, ensure};
|
||||
use rusty_paserk::{Key, KeyId, Local, PieWrappedKey};
|
||||
use rusty_paseto::core::{
|
||||
ImplicitAssertion, Key as DataKey, Local as LocalPurpose, Paseto, PasetoNonce, Payload, V4,
|
||||
|
@ -6,12 +6,12 @@ use std::str::FromStr;
|
||||
use std::{path::Path, time::Duration};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use eyre::{eyre, Result};
|
||||
use eyre::{Result, eyre};
|
||||
use fs_err as fs;
|
||||
|
||||
use sqlx::{
|
||||
sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePool, SqlitePoolOptions, SqliteRow},
|
||||
Row,
|
||||
sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePool, SqlitePoolOptions, SqliteRow},
|
||||
};
|
||||
|
||||
use atuin_common::record::{
|
||||
@ -35,7 +35,9 @@ impl SqliteStore {
|
||||
debug!("opening sqlite database at {:?}", path);
|
||||
|
||||
if utils::broken_symlink(path) {
|
||||
eprintln!("Atuin: Sqlite db path ({path:?}) is a broken symlink. Unable to read or create replacement.");
|
||||
eprintln!(
|
||||
"Atuin: Sqlite db path ({path:?}) is a broken symlink. Unable to read or create replacement."
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ pub async fn operations(
|
||||
msg: String::from(
|
||||
"diff has nothing for local or remote - (host, tag) does not exist",
|
||||
),
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -38,7 +38,9 @@ pub static SECRET_PATTERNS: &[(&str, &str, TestValue)] = &[
|
||||
(
|
||||
"Atuin login",
|
||||
r"atuin\s+login",
|
||||
TestValue::Single("atuin login -u mycoolusername -p mycoolpassword -k \"lots of random words\""),
|
||||
TestValue::Single(
|
||||
"atuin login -u mycoolusername -p mycoolpassword -k \"lots of random words\"",
|
||||
),
|
||||
),
|
||||
(
|
||||
"GitHub PAT (old)",
|
||||
@ -51,7 +53,7 @@ pub static SECRET_PATTERNS: &[(&str, &str, TestValue)] = &[
|
||||
TestValue::Multiple(&[
|
||||
"gh1_1234567890abcdefghijk_1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklm",
|
||||
"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", // also legit, also expired
|
||||
])
|
||||
]),
|
||||
),
|
||||
(
|
||||
"GitHub OAuth Access Token",
|
||||
@ -71,7 +73,9 @@ pub static SECRET_PATTERNS: &[(&str, &str, TestValue)] = &[
|
||||
(
|
||||
"GitHub Refresh Token",
|
||||
"ghr_[A-Za-z0-9]{76}",
|
||||
TestValue::Single("ghr_1234567890abcdefghijklmnopqrstuvwx1234567890abcdefghijklmnopqrstuvwx1234567890abcdefghijklmnopqrstuvwx"), // not a real token
|
||||
TestValue::Single(
|
||||
"ghr_1234567890abcdefghijklmnopqrstuvwx1234567890abcdefghijklmnopqrstuvwx1234567890abcdefghijklmnopqrstuvwx",
|
||||
), // not a real token
|
||||
),
|
||||
(
|
||||
"GitHub App Installation Access Token v1",
|
||||
@ -96,10 +100,20 @@ pub static SECRET_PATTERNS: &[(&str, &str, TestValue)] = &[
|
||||
(
|
||||
"Slack webhook",
|
||||
"T[a-zA-Z0-9_]{8}/B[a-zA-Z0-9_]{8}/[a-zA-Z0-9_]{24}",
|
||||
TestValue::Single("https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX"),
|
||||
TestValue::Single(
|
||||
"https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
),
|
||||
),
|
||||
(
|
||||
"Stripe test key",
|
||||
"sk_test_[0-9a-zA-Z]{24}",
|
||||
TestValue::Single("sk_test_1234567890abcdefghijklmnop"),
|
||||
),
|
||||
(
|
||||
"Stripe live key",
|
||||
"sk_live_[0-9a-zA-Z]{24}",
|
||||
TestValue::Single("sk_live_1234567890abcdefghijklmnop"),
|
||||
),
|
||||
("Stripe test key", "sk_test_[0-9a-zA-Z]{24}", TestValue::Single("sk_test_1234567890abcdefghijklmnop")),
|
||||
("Stripe live key", "sk_live_[0-9a-zA-Z]{24}", TestValue::Single("sk_live_1234567890abcdefghijklmnop")),
|
||||
(
|
||||
"Netlify authentication token",
|
||||
"nf[pcoub]_[0-9a-zA-Z]{36}",
|
||||
@ -127,7 +141,7 @@ pub static SECRET_PATTERNS_RE: LazyLock<RegexSet> = LazyLock::new(|| {
|
||||
mod tests {
|
||||
use regex::Regex;
|
||||
|
||||
use crate::secrets::{TestValue, SECRET_PATTERNS};
|
||||
use crate::secrets::{SECRET_PATTERNS, TestValue};
|
||||
|
||||
#[test]
|
||||
fn test_secrets() {
|
||||
|
@ -6,19 +6,19 @@ use atuin_common::record::HostId;
|
||||
use atuin_common::utils;
|
||||
use clap::ValueEnum;
|
||||
use config::{
|
||||
builder::DefaultState, Config, ConfigBuilder, Environment, File as ConfigFile, FileFormat,
|
||||
Config, ConfigBuilder, Environment, File as ConfigFile, FileFormat, builder::DefaultState,
|
||||
};
|
||||
use eyre::{bail, eyre, Context, Error, Result};
|
||||
use fs_err::{create_dir_all, File};
|
||||
use eyre::{Context, Error, Result, bail, eyre};
|
||||
use fs_err::{File, create_dir_all};
|
||||
use humantime::parse_duration;
|
||||
use regex::RegexSet;
|
||||
use semver::Version;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::DeserializeFromStr;
|
||||
use time::{
|
||||
format_description::{well_known::Rfc3339, FormatItem},
|
||||
macros::format_description,
|
||||
OffsetDateTime, UtcOffset,
|
||||
format_description::{FormatItem, well_known::Rfc3339},
|
||||
macros::format_description,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
@ -141,8 +141,9 @@ impl fmt::Display for Timezone {
|
||||
}
|
||||
}
|
||||
/// format: <+|-><hour>[:<minute>[:<second>]]
|
||||
static OFFSET_FMT: &[FormatItem<'_>] =
|
||||
format_description!("[offset_hour sign:mandatory padding:none][optional [:[offset_minute padding:none][optional [:[offset_second padding:none]]]]]");
|
||||
static OFFSET_FMT: &[FormatItem<'_>] = format_description!(
|
||||
"[offset_hour sign:mandatory padding:none][optional [:[offset_minute padding:none][optional [:[offset_second padding:none]]]]]"
|
||||
);
|
||||
impl FromStr for Timezone {
|
||||
type Err = Error;
|
||||
|
||||
|
@ -109,15 +109,18 @@ async fn sync_download(
|
||||
for i in remote_status.deleted {
|
||||
// we will update the stored history to have this data
|
||||
// pretty much everything can be nullified
|
||||
if let Some(h) = db.load(i.as_str()).await? {
|
||||
match db.load(i.as_str()).await? {
|
||||
Some(h) => {
|
||||
db.delete(h).await?;
|
||||
} else {
|
||||
}
|
||||
_ => {
|
||||
info!(
|
||||
"could not delete history with id {}, not found locally",
|
||||
i.as_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok((local_count - initial_local, local_count))
|
||||
}
|
||||
|
@ -416,7 +416,7 @@ impl ThemeManager {
|
||||
"set theme debug on for more info".to_string()
|
||||
}
|
||||
),
|
||||
)))
|
||||
)));
|
||||
}
|
||||
};
|
||||
let colors: HashMap<Meaning, String> = theme_config.colors;
|
||||
@ -697,7 +697,8 @@ mod theme_tests {
|
||||
|
||||
testing_logger::validate(|captured_logs| {
|
||||
assert_eq!(captured_logs.len(), 1);
|
||||
assert_eq!(captured_logs[0].body,
|
||||
assert_eq!(
|
||||
captured_logs[0].body,
|
||||
"Could not load theme nonsolarized: Empty theme directory override and could not find theme elsewhere"
|
||||
);
|
||||
assert_eq!(captured_logs[0].level, log::Level::Warn)
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "atuin-common"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
description = "common library for atuin"
|
||||
|
||||
rust-version = { workspace = true }
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(unsafe_code)]
|
||||
|
||||
/// Defines a new UUID type wrapper
|
||||
macro_rules! new_uuid {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::{ffi::OsStr, path::Path, process::Command};
|
||||
|
||||
use serde::Serialize;
|
||||
use sysinfo::{get_current_pid, Process, System};
|
||||
use sysinfo::{Process, System, get_current_pid};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
|
@ -2,9 +2,9 @@ use std::borrow::Cow;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use eyre::{eyre, Result};
|
||||
use eyre::{Result, eyre};
|
||||
|
||||
use base64::prelude::{Engine, BASE64_URL_SAFE_NO_PAD};
|
||||
use base64::prelude::{BASE64_URL_SAFE_NO_PAD, Engine};
|
||||
use getrandom::getrandom;
|
||||
use uuid::Uuid;
|
||||
|
||||
@ -194,6 +194,7 @@ pub fn unquote(s: &str) -> Result<String> {
|
||||
|
||||
impl<T: AsRef<str>> Escapable for T {}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pretty_assertions::assert_ne;
|
||||
@ -214,36 +215,48 @@ mod tests {
|
||||
}
|
||||
|
||||
fn test_config_dir_xdg() {
|
||||
env::remove_var("HOME");
|
||||
env::set_var("XDG_CONFIG_HOME", "/home/user/custom_config");
|
||||
// TODO: Audit that the environment access only happens in single-threaded code.
|
||||
unsafe { env::remove_var("HOME") };
|
||||
// TODO: Audit that the environment access only happens in single-threaded code.
|
||||
unsafe { env::set_var("XDG_CONFIG_HOME", "/home/user/custom_config") };
|
||||
assert_eq!(
|
||||
config_dir(),
|
||||
PathBuf::from("/home/user/custom_config/atuin")
|
||||
);
|
||||
env::remove_var("XDG_CONFIG_HOME");
|
||||
// TODO: Audit that the environment access only happens in single-threaded code.
|
||||
unsafe { env::remove_var("XDG_CONFIG_HOME") };
|
||||
}
|
||||
|
||||
fn test_config_dir() {
|
||||
env::set_var("HOME", "/home/user");
|
||||
env::remove_var("XDG_CONFIG_HOME");
|
||||
// TODO: Audit that the environment access only happens in single-threaded code.
|
||||
unsafe { env::set_var("HOME", "/home/user") };
|
||||
// TODO: Audit that the environment access only happens in single-threaded code.
|
||||
unsafe { env::remove_var("XDG_CONFIG_HOME") };
|
||||
|
||||
assert_eq!(config_dir(), PathBuf::from("/home/user/.config/atuin"));
|
||||
|
||||
env::remove_var("HOME");
|
||||
// TODO: Audit that the environment access only happens in single-threaded code.
|
||||
unsafe { env::remove_var("HOME") };
|
||||
}
|
||||
|
||||
fn test_data_dir_xdg() {
|
||||
env::remove_var("HOME");
|
||||
env::set_var("XDG_DATA_HOME", "/home/user/custom_data");
|
||||
// TODO: Audit that the environment access only happens in single-threaded code.
|
||||
unsafe { env::remove_var("HOME") };
|
||||
// TODO: Audit that the environment access only happens in single-threaded code.
|
||||
unsafe { env::set_var("XDG_DATA_HOME", "/home/user/custom_data") };
|
||||
assert_eq!(data_dir(), PathBuf::from("/home/user/custom_data/atuin"));
|
||||
env::remove_var("XDG_DATA_HOME");
|
||||
// TODO: Audit that the environment access only happens in single-threaded code.
|
||||
unsafe { env::remove_var("XDG_DATA_HOME") };
|
||||
}
|
||||
|
||||
fn test_data_dir() {
|
||||
env::set_var("HOME", "/home/user");
|
||||
env::remove_var("XDG_DATA_HOME");
|
||||
// TODO: Audit that the environment access only happens in single-threaded code.
|
||||
unsafe { env::set_var("HOME", "/home/user") };
|
||||
// TODO: Audit that the environment access only happens in single-threaded code.
|
||||
unsafe { env::remove_var("XDG_DATA_HOME") };
|
||||
assert_eq!(data_dir(), PathBuf::from("/home/user/.local/share/atuin"));
|
||||
env::remove_var("HOME");
|
||||
// TODO: Audit that the environment access only happens in single-threaded code.
|
||||
unsafe { env::remove_var("HOME") };
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "atuin-daemon"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
version = { workspace = true }
|
||||
description = "The daemon crate for Atuin"
|
||||
|
||||
|
@ -12,7 +12,7 @@ use tokio::net::UnixStream;
|
||||
use atuin_client::history::History;
|
||||
|
||||
use crate::history::{
|
||||
history_client::HistoryClient as HistoryServiceClient, EndHistoryRequest, StartHistoryRequest,
|
||||
EndHistoryRequest, StartHistoryRequest, history_client::HistoryClient as HistoryServiceClient,
|
||||
};
|
||||
|
||||
pub struct HistoryClient {
|
||||
|
@ -7,13 +7,13 @@ use atuin_client::settings::Settings;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use time::OffsetDateTime;
|
||||
use tracing::{instrument, Level};
|
||||
use tracing::{Level, instrument};
|
||||
|
||||
use atuin_client::database::{Database, Sqlite as HistoryDatabase};
|
||||
use atuin_client::history::{History, HistoryId};
|
||||
use dashmap::DashMap;
|
||||
use eyre::Result;
|
||||
use tonic::{transport::Server, Request, Response, Status};
|
||||
use tonic::{Request, Response, Status, transport::Server};
|
||||
|
||||
use crate::history::history_server::{History as HistorySvc, HistoryServer};
|
||||
|
||||
@ -194,7 +194,9 @@ async fn start_server(settings: Settings, history: HistoryService) -> Result<()>
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::warn!("could not detect systemd socket path, ensure that it's at the configured path: {socket_path:?}, error: {err:?}");
|
||||
tracing::warn!(
|
||||
"could not detect systemd socket path, ensure that it's at the configured path: {socket_path:?}, error: {err:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
(UnixListener::from_std(listener)?, false)
|
||||
|
@ -10,7 +10,7 @@ use atuin_client::{
|
||||
settings::Settings,
|
||||
};
|
||||
|
||||
use atuin_dotfiles::store::{var::VarStore, AliasStore};
|
||||
use atuin_dotfiles::store::{AliasStore, var::VarStore};
|
||||
|
||||
pub async fn worker(
|
||||
settings: Settings,
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "atuin-dotfiles"
|
||||
description = "The dotfiles crate for Atuin"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
version = { workspace = true }
|
||||
|
||||
authors.workspace = true
|
||||
|
@ -1,4 +1,4 @@
|
||||
use eyre::{ensure, eyre, Result};
|
||||
use eyre::{Result, ensure, eyre};
|
||||
use rmp::{decode, encode};
|
||||
use serde::Serialize;
|
||||
|
||||
@ -158,7 +158,7 @@ pub async fn import_aliases(store: &AliasStore) -> Result<Vec<Alias>> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::shell::{parse_alias, Alias};
|
||||
use crate::shell::{Alias, parse_alias};
|
||||
|
||||
#[test]
|
||||
fn test_parse_simple_alias() {
|
||||
@ -177,7 +177,10 @@ mod tests {
|
||||
|
||||
let git_alias = super::parse_alias("gwip='git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign --message \"--wip-- [skip ci]\"'").expect("failed to parse alias");
|
||||
assert_eq!(git_alias.name, "gwip");
|
||||
assert_eq!(git_alias.value, "'git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign --message \"--wip-- [skip ci]\"'");
|
||||
assert_eq!(
|
||||
git_alias.value,
|
||||
"'git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign --message \"--wip-- [skip ci]\"'"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::store::{var::VarStore, AliasStore};
|
||||
use crate::store::{AliasStore, var::VarStore};
|
||||
|
||||
async fn cached_aliases(path: PathBuf, store: &AliasStore) -> String {
|
||||
match tokio::fs::read_to_string(path).await {
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Configuration for fish
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::store::{var::VarStore, AliasStore};
|
||||
use crate::store::{AliasStore, var::VarStore};
|
||||
|
||||
async fn cached_aliases(path: PathBuf, store: &AliasStore) -> String {
|
||||
match tokio::fs::read_to_string(path).await {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::store::{var::VarStore, AliasStore};
|
||||
use crate::store::{AliasStore, var::VarStore};
|
||||
|
||||
async fn cached_aliases(path: PathBuf, store: &AliasStore) -> String {
|
||||
match tokio::fs::read_to_string(path).await {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::store::{var::VarStore, AliasStore};
|
||||
use crate::store::{AliasStore, var::VarStore};
|
||||
|
||||
async fn cached_aliases(path: PathBuf, store: &AliasStore) -> String {
|
||||
match tokio::fs::read_to_string(path).await {
|
||||
|
@ -7,7 +7,7 @@ use atuin_client::record::sqlite_store::SqliteStore;
|
||||
// + stores, rather than one mega config store.
|
||||
use atuin_common::record::{DecryptedData, Host, HostId};
|
||||
use atuin_common::utils::unquote;
|
||||
use eyre::{bail, ensure, eyre, Result};
|
||||
use eyre::{Result, bail, ensure, eyre};
|
||||
|
||||
use atuin_client::record::encryption::PASETO_V4;
|
||||
use atuin_client::record::store::Store;
|
||||
@ -315,7 +315,7 @@ mod tests {
|
||||
|
||||
use crate::shell::Alias;
|
||||
|
||||
use super::{test_local_timeout, AliasRecord, AliasStore, CONFIG_SHELL_ALIAS_VERSION};
|
||||
use super::{AliasRecord, AliasStore, CONFIG_SHELL_ALIAS_VERSION, test_local_timeout};
|
||||
use crypto_secretbox::{KeyInit, XSalsa20Poly1305};
|
||||
|
||||
#[test]
|
||||
|
@ -6,7 +6,7 @@ use std::collections::BTreeMap;
|
||||
|
||||
use atuin_client::record::sqlite_store::SqliteStore;
|
||||
use atuin_common::record::{DecryptedData, Host, HostId};
|
||||
use eyre::{bail, ensure, eyre, Result};
|
||||
use eyre::{Result, bail, ensure, eyre};
|
||||
|
||||
use atuin_client::record::encryption::PASETO_V4;
|
||||
use atuin_client::record::store::Store;
|
||||
@ -294,7 +294,7 @@ mod tests {
|
||||
|
||||
use crate::{shell::Var, store::test_local_timeout};
|
||||
|
||||
use super::{VarRecord, VarStore, DOTFILES_VAR_VERSION};
|
||||
use super::{DOTFILES_VAR_VERSION, VarRecord, VarStore};
|
||||
use crypto_secretbox::{KeyInit, XSalsa20Poly1305};
|
||||
|
||||
#[test]
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "atuin-history"
|
||||
description = "The history crate for Atuin"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
version = { workspace = true }
|
||||
|
||||
authors.workspace = true
|
||||
|
@ -178,7 +178,9 @@ pub fn pretty_print(stats: Stats, ngram_size: usize, theme: &Theme) {
|
||||
.collect::<Vec<_>>()
|
||||
.join(" | ");
|
||||
|
||||
println!("{ResetColor}] {gray}{count:num_pad$}{ResetColor} {bold}{formatted_command}{ResetColor}");
|
||||
println!(
|
||||
"{ResetColor}] {gray}{count:num_pad$}{ResetColor} {bold}{formatted_command}{ResetColor}"
|
||||
);
|
||||
}
|
||||
println!("Total commands: {}", stats.total_commands);
|
||||
println!("Unique commands: {}", stats.unique_commands);
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "atuin-server-database"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
description = "server database library for atuin"
|
||||
|
||||
version = { workspace = true }
|
||||
|
@ -15,7 +15,7 @@ use self::{
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use atuin_common::record::{EncryptedData, HostId, Record, RecordIdx, RecordStatus};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
use time::{Date, Duration, Month, OffsetDateTime, Time, UtcOffset};
|
||||
use tracing::instrument;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "atuin-server-postgres"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
description = "server postgres database library for atuin"
|
||||
|
||||
version = { workspace = true }
|
||||
|
@ -10,8 +10,8 @@ use atuin_server_database::{Database, DbError, DbResult};
|
||||
use futures_util::TryStreamExt;
|
||||
use metrics::counter;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::postgres::PgPoolOptions;
|
||||
use sqlx::Row;
|
||||
use sqlx::postgres::PgPoolOptions;
|
||||
|
||||
use time::{OffsetDateTime, PrimitiveDateTime, UtcOffset};
|
||||
use tracing::{instrument, trace};
|
||||
|
@ -1,7 +1,7 @@
|
||||
use ::sqlx::{FromRow, Result};
|
||||
use atuin_common::record::{EncryptedData, Host, Record};
|
||||
use atuin_server_database::models::{History, Session, User};
|
||||
use sqlx::{postgres::PgRow, Row};
|
||||
use sqlx::{Row, postgres::PgRow};
|
||||
use time::PrimitiveDateTime;
|
||||
|
||||
pub struct DbUser(pub User);
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "atuin-server"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
description = "server library for atuin"
|
||||
|
||||
rust-version = { workspace = true }
|
||||
|
@ -1,4 +1,4 @@
|
||||
use axum::{http, response::IntoResponse, Json};
|
||||
use axum::{Json, http, response::IntoResponse};
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
use std::{collections::HashMap, convert::TryFrom};
|
||||
|
||||
use axum::{
|
||||
Json,
|
||||
extract::{Path, Query, State},
|
||||
http::{HeaderMap, StatusCode},
|
||||
Json,
|
||||
};
|
||||
use metrics::counter;
|
||||
use time::{Month, UtcOffset};
|
||||
@ -15,9 +15,9 @@ use crate::{
|
||||
utils::client_version_min,
|
||||
};
|
||||
use atuin_server_database::{
|
||||
Database,
|
||||
calendar::{TimePeriod, TimePeriodInfo},
|
||||
models::NewHistory,
|
||||
Database,
|
||||
};
|
||||
|
||||
use atuin_common::api::*;
|
||||
@ -223,7 +223,7 @@ pub async fn calendar<DB: Database>(
|
||||
"day" => TimePeriod::Day { year, month },
|
||||
_ => {
|
||||
return Err(ErrorResponse::reply("invalid focus: use year/month/day")
|
||||
.with_status(StatusCode::BAD_REQUEST))
|
||||
.with_status(StatusCode::BAD_REQUEST));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use atuin_common::api::{ErrorResponse, IndexResponse};
|
||||
use atuin_server_database::Database;
|
||||
use axum::{extract::State, http, response::IntoResponse, Json};
|
||||
use axum::{Json, extract::State, http, response::IntoResponse};
|
||||
|
||||
use crate::router::AppState;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use axum::{http::StatusCode, response::IntoResponse, Json};
|
||||
use axum::{Json, http::StatusCode, response::IntoResponse};
|
||||
use serde_json::json;
|
||||
use tracing::instrument;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use axum::{extract::State, http::StatusCode, Json};
|
||||
use axum::{Json, extract::State, http::StatusCode};
|
||||
use tracing::instrument;
|
||||
|
||||
use super::{ErrorResponse, ErrorResponseStatus, RespExt};
|
||||
@ -28,7 +28,7 @@ pub async fn status<DB: Database>(
|
||||
Ok(count) => count,
|
||||
Err(_) => {
|
||||
return Err(ErrorResponse::reply("failed to query history count")
|
||||
.with_status(StatusCode::INTERNAL_SERVER_ERROR))
|
||||
.with_status(StatusCode::INTERNAL_SERVER_ERROR));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -3,17 +3,17 @@ use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
|
||||
use argon2::{
|
||||
password_hash::SaltString, Algorithm, Argon2, Params, PasswordHash, PasswordHasher,
|
||||
PasswordVerifier, Version,
|
||||
Algorithm, Argon2, Params, PasswordHash, PasswordHasher, PasswordVerifier, Version,
|
||||
password_hash::SaltString,
|
||||
};
|
||||
use axum::{
|
||||
Json,
|
||||
extract::{Path, State},
|
||||
http::StatusCode,
|
||||
Json,
|
||||
};
|
||||
use metrics::counter;
|
||||
|
||||
use postmark::{reqwest::PostmarkClient, Query};
|
||||
use postmark::{Query, reqwest::PostmarkClient};
|
||||
|
||||
use rand::rngs::OsRng;
|
||||
use tracing::{debug, error, info, instrument};
|
||||
@ -21,8 +21,8 @@ use tracing::{debug, error, info, instrument};
|
||||
use super::{ErrorResponse, ErrorResponseStatus, RespExt};
|
||||
use crate::router::{AppState, UserAuth};
|
||||
use atuin_server_database::{
|
||||
models::{NewSession, NewUser},
|
||||
Database, DbError,
|
||||
models::{NewSession, NewUser},
|
||||
};
|
||||
|
||||
use reqwest::header::CONTENT_TYPE;
|
||||
@ -104,7 +104,7 @@ pub async fn register<DB: Database>(
|
||||
return Err(ErrorResponse::reply(
|
||||
"Only alphanumeric and hyphens (-) are allowed in usernames",
|
||||
)
|
||||
.with_status(StatusCode::BAD_REQUEST))
|
||||
.with_status(StatusCode::BAD_REQUEST));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -201,12 +201,13 @@ pub async fn send_verification<DB: Database>(
|
||||
}
|
||||
|
||||
// TODO: if we ever add another mail provider, can match on them all here.
|
||||
let postmark_token = if let Some(token) = settings.mail.postmark.token {
|
||||
token
|
||||
} else {
|
||||
let postmark_token = match settings.mail.postmark.token {
|
||||
Some(token) => token,
|
||||
_ => {
|
||||
error!("Failed to verify email: got None for postmark token");
|
||||
return Err(ErrorResponse::reply("mail not configured")
|
||||
.with_status(StatusCode::INTERNAL_SERVER_ERROR));
|
||||
}
|
||||
};
|
||||
|
||||
let db = &state.0.database;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use axum::{extract::Query, extract::State, http::StatusCode, Json};
|
||||
use axum::{Json, extract::Query, extract::State, http::StatusCode};
|
||||
use metrics::counter;
|
||||
use serde::Deserialize;
|
||||
use tracing::{error, instrument};
|
||||
|
@ -4,18 +4,18 @@ use std::future::Future;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use atuin_server_database::Database;
|
||||
use axum::{serve, Router};
|
||||
use axum_server::tls_rustls::RustlsConfig;
|
||||
use axum::{Router, serve};
|
||||
use axum_server::Handle;
|
||||
use eyre::{eyre, Context, Result};
|
||||
use axum_server::tls_rustls::RustlsConfig;
|
||||
use eyre::{Context, Result, eyre};
|
||||
|
||||
mod handlers;
|
||||
mod metrics;
|
||||
mod router;
|
||||
mod utils;
|
||||
|
||||
pub use settings::example_config;
|
||||
pub use settings::Settings;
|
||||
pub use settings::example_config;
|
||||
|
||||
pub mod settings;
|
||||
|
||||
|
@ -28,10 +28,9 @@ pub fn setup_metrics_recorder() -> PrometheusHandle {
|
||||
pub async fn track_metrics(req: Request, next: Next) -> impl IntoResponse {
|
||||
let start = Instant::now();
|
||||
|
||||
let path = if let Some(matched_path) = req.extensions().get::<MatchedPath>() {
|
||||
matched_path.as_str().to_owned()
|
||||
} else {
|
||||
req.uri().path().to_owned()
|
||||
let path = match req.extensions().get::<MatchedPath>() {
|
||||
Some(matched_path) => matched_path.as_str().to_owned(),
|
||||
_ => req.uri().path().to_owned(),
|
||||
};
|
||||
|
||||
let method = req.method().clone();
|
||||
|
@ -1,12 +1,12 @@
|
||||
use async_trait::async_trait;
|
||||
use atuin_common::api::{ErrorResponse, ATUIN_CARGO_VERSION, ATUIN_HEADER_VERSION};
|
||||
use atuin_common::api::{ATUIN_CARGO_VERSION, ATUIN_HEADER_VERSION, ErrorResponse};
|
||||
use axum::{
|
||||
Router,
|
||||
extract::{FromRequestParts, Request},
|
||||
http::{self, request::Parts},
|
||||
middleware::Next,
|
||||
response::{IntoResponse, Response},
|
||||
routing::{delete, get, patch, post},
|
||||
Router,
|
||||
};
|
||||
use eyre::Result;
|
||||
use tower::ServiceBuilder;
|
||||
@ -18,7 +18,7 @@ use crate::{
|
||||
metrics,
|
||||
settings::Settings,
|
||||
};
|
||||
use atuin_server_database::{models::User, Database, DbError};
|
||||
use atuin_server_database::{Database, DbError, models::User};
|
||||
|
||||
pub struct UserAuth(pub User);
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
use std::{io::prelude::*, path::PathBuf};
|
||||
|
||||
use config::{Config, Environment, File as ConfigFile, FileFormat};
|
||||
use eyre::{eyre, Result};
|
||||
use fs_err::{create_dir_all, File};
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use eyre::{Result, eyre};
|
||||
use fs_err::{File, create_dir_all};
|
||||
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
||||
|
||||
static EXAMPLE_CONFIG: &str = include_str!("../server.toml");
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "atuin"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
description = "atuin - magical shell history"
|
||||
readme = "./README.md"
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clap::Parser;
|
||||
use eyre::{bail, Result};
|
||||
use eyre::{Result, bail};
|
||||
|
||||
use atuin_client::{api_client, settings::Settings};
|
||||
use rpassword::prompt_password;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use atuin_client::{api_client, settings::Settings};
|
||||
use eyre::{bail, Result};
|
||||
use eyre::{Result, bail};
|
||||
use std::fs::remove_file;
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
use std::{io, path::PathBuf};
|
||||
|
||||
use clap::Parser;
|
||||
use eyre::{bail, Context, Result};
|
||||
use eyre::{Context, Result, bail};
|
||||
use tokio::{fs::File, io::AsyncWriteExt};
|
||||
|
||||
use atuin_client::{
|
||||
api_client,
|
||||
encryption::{decode_key, encode_key, load_key, Key},
|
||||
encryption::{Key, decode_key, encode_key, load_key},
|
||||
record::sqlite_store::SqliteStore,
|
||||
record::store::Store,
|
||||
settings::Settings,
|
||||
@ -56,7 +56,9 @@ impl Cmd {
|
||||
let key_path = PathBuf::from(key_path);
|
||||
|
||||
println!("IMPORTANT");
|
||||
println!("If you are already logged in on another machine, you must ensure that the key you use here is the same as the key you used there.");
|
||||
println!(
|
||||
"If you are already logged in on another machine, you must ensure that the key you use here is the same as the key you used there."
|
||||
);
|
||||
println!("You can find your key by running 'atuin key' on the other machine");
|
||||
println!("Do not share this key with anyone");
|
||||
println!("\nRead more here: https://docs.atuin.sh/guide/sync/#login \n");
|
||||
@ -75,7 +77,8 @@ impl Cmd {
|
||||
match bip39::Mnemonic::from_phrase(&key, bip39::Language::English) {
|
||||
Ok(mnemonic) => encode_key(Key::from_slice(mnemonic.entropy()))?,
|
||||
Err(err) => {
|
||||
if let Some(err) = err.downcast_ref::<bip39::ErrorKind>() {
|
||||
match err.downcast_ref::<bip39::ErrorKind>() {
|
||||
Some(err) => {
|
||||
match err {
|
||||
// assume they copied in the base64 key
|
||||
bip39::ErrorKind::InvalidWord => key,
|
||||
@ -88,12 +91,14 @@ impl Cmd {
|
||||
bail!("key was not the correct length")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
_ => {
|
||||
// unknown error. assume they copied the base64 key
|
||||
key
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// I've simplified this a little, but it could really do with a refactor
|
||||
@ -106,7 +111,9 @@ impl Cmd {
|
||||
bail!("the key in existing key file was invalid");
|
||||
}
|
||||
} else {
|
||||
panic!("No key provided. Please use 'atuin key' on your other machine, or recover your key from a backup.")
|
||||
panic!(
|
||||
"No key provided. Please use 'atuin key' on your other machine, or recover your key from a backup."
|
||||
)
|
||||
}
|
||||
} else if !key_path.exists() {
|
||||
if decode_key(key.clone()).is_err() {
|
||||
@ -184,6 +191,9 @@ mod tests {
|
||||
.into_phrase();
|
||||
let mnemonic = bip39::Mnemonic::from_phrase(&phrase, bip39::Language::English).unwrap();
|
||||
assert_eq!(mnemonic.entropy(), key.as_slice());
|
||||
assert_eq!(phrase, "adapt amused able anxiety mother adapt beef gaze amount else seat alcohol cage lottery avoid scare alcohol cactus school avoid coral adjust catch pink");
|
||||
assert_eq!(
|
||||
phrase,
|
||||
"adapt amused able anxiety mother adapt beef gaze amount else seat alcohol cage lottery avoid scare alcohol cactus school avoid coral adjust catch pink"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clap::Parser;
|
||||
use eyre::{bail, Result};
|
||||
use eyre::{Result, bail};
|
||||
use tokio::{fs::File, io::AsyncWriteExt};
|
||||
|
||||
use atuin_client::{api_client, settings::Settings};
|
||||
@ -51,8 +51,12 @@ pub async fn run(
|
||||
|
||||
let _key = atuin_client::encryption::load_key(settings)?;
|
||||
|
||||
println!("Registration successful! Please make a note of your key (run 'atuin key') and keep it safe.");
|
||||
println!("You will need it to log in on other devices, and we cannot help recover it if you lose it.");
|
||||
println!(
|
||||
"Registration successful! Please make a note of your key (run 'atuin key') and keep it safe."
|
||||
);
|
||||
println!(
|
||||
"You will need it to log in on other devices, and we cannot help recover it if you lose it."
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -35,11 +35,15 @@ pub async fn run(settings: &Settings, token: Option<String>) -> Result<()> {
|
||||
}
|
||||
|
||||
(false, false) => {
|
||||
println!("Your Atuin server does not have mail setup. This is not required, though your account cannot be verified. Speak to your admin.");
|
||||
println!(
|
||||
"Your Atuin server does not have mail setup. This is not required, though your account cannot be verified. Speak to your admin."
|
||||
);
|
||||
}
|
||||
|
||||
_ => {
|
||||
println!("Invalid email and verification status. This is a bug. Please open an issue: https://github.com/atuinsh/atuin");
|
||||
println!(
|
||||
"Invalid email and verification status. This is a bug. Please open an issue: https://github.com/atuinsh/atuin"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,13 +3,13 @@ use std::{env, path::PathBuf, str::FromStr};
|
||||
|
||||
use atuin_client::database::Sqlite;
|
||||
use atuin_client::settings::Settings;
|
||||
use atuin_common::shell::{shell_name, Shell};
|
||||
use atuin_common::shell::{Shell, shell_name};
|
||||
use atuin_common::utils;
|
||||
use colored::Colorize;
|
||||
use eyre::Result;
|
||||
use serde::Serialize;
|
||||
|
||||
use sysinfo::{get_current_pid, Disks, System};
|
||||
use sysinfo::{Disks, System, get_current_pid};
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct ShellInfo {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clap::Subcommand;
|
||||
use eyre::{eyre, Context, Result};
|
||||
use eyre::{Context, Result, eyre};
|
||||
|
||||
use atuin_client::{encryption, record::sqlite_store::SqliteStore, settings::Settings};
|
||||
|
||||
@ -92,7 +92,9 @@ impl Cmd {
|
||||
|
||||
pub async fn run(&self, settings: &Settings, store: SqliteStore) -> Result<()> {
|
||||
if !settings.dotfiles.enabled {
|
||||
eprintln!("Dotfiles are not enabled. Add\n\n[dotfiles]\nenabled = true\n\nto your configuration file to enable them.\n");
|
||||
eprintln!(
|
||||
"Dotfiles are not enabled. Add\n\n[dotfiles]\nenabled = true\n\nto your configuration file to enable them.\n"
|
||||
);
|
||||
eprintln!("The default configuration file is located at ~/.config/atuin/config.toml.");
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -73,7 +73,9 @@ impl Cmd {
|
||||
|
||||
pub async fn run(&self, settings: &Settings, store: SqliteStore) -> Result<()> {
|
||||
if !settings.dotfiles.enabled {
|
||||
eprintln!("Dotfiles are not enabled. Add\n\n[dotfiles]\nenabled = true\n\nto your configuration file to enable them.\n");
|
||||
eprintln!(
|
||||
"Dotfiles are not enabled. Add\n\n[dotfiles]\nenabled = true\n\nto your configuration file to enable them.\n"
|
||||
);
|
||||
eprintln!("The default configuration file is located at ~/.config/atuin/config.toml.");
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -11,9 +11,9 @@ use eyre::{Context, Result};
|
||||
use runtime_format::{FormatKey, FormatKeyError, ParseSegment, ParsedFmt};
|
||||
|
||||
use atuin_client::{
|
||||
database::{current_context, Database, Sqlite},
|
||||
database::{Database, Sqlite, current_context},
|
||||
encryption,
|
||||
history::{store::HistoryStore, History},
|
||||
history::{History, store::HistoryStore},
|
||||
record::sqlite_store::SqliteStore,
|
||||
settings::{
|
||||
FilterMode::{Directory, Global, Session},
|
||||
@ -25,7 +25,7 @@ use atuin_client::{
|
||||
use atuin_client::{record, sync};
|
||||
|
||||
use log::{debug, warn};
|
||||
use time::{macros::format_description, OffsetDateTime};
|
||||
use time::{OffsetDateTime, macros::format_description};
|
||||
|
||||
use super::search::format_duration_into;
|
||||
|
||||
@ -285,7 +285,9 @@ fn parse_fmt(format: &str) -> ParsedFmt {
|
||||
Ok(fmt) => fmt,
|
||||
Err(err) => {
|
||||
eprintln!("ERROR: History formatting failed with the following error: {err}");
|
||||
println!("If your formatting string contains curly braces (eg: {{var}}) you need to escape them this way: {{{{var}}.");
|
||||
println!(
|
||||
"If your formatting string contains curly braces (eg: {{var}}) you need to escape them this way: {{{{var}}."
|
||||
);
|
||||
std::process::exit(1)
|
||||
}
|
||||
}
|
||||
@ -550,11 +552,11 @@ impl Cmd {
|
||||
if settings.daemon.enabled {
|
||||
match self {
|
||||
Self::Start { command } => {
|
||||
return Self::handle_daemon_start(settings, &command).await
|
||||
return Self::handle_daemon_start(settings, &command).await;
|
||||
}
|
||||
|
||||
Self::End { id, exit, duration } => {
|
||||
return Self::handle_daemon_end(settings, &id, exit, duration).await
|
||||
return Self::handle_daemon_end(settings, &id, exit, duration).await;
|
||||
}
|
||||
|
||||
_ => {}
|
||||
|
@ -9,8 +9,8 @@ use atuin_client::{
|
||||
database::Database,
|
||||
history::History,
|
||||
import::{
|
||||
bash::Bash, fish::Fish, nu::Nu, nu_histdb::NuHistDb, replxx::Replxx, resh::Resh,
|
||||
xonsh::Xonsh, xonsh_sqlite::XonshSqlite, zsh::Zsh, zsh_histdb::ZshHistDb, Importer, Loader,
|
||||
Importer, Loader, bash::Bash, fish::Fish, nu::Nu, nu_histdb::NuHistDb, replxx::Replxx,
|
||||
resh::Resh, xonsh::Xonsh, xonsh_sqlite::XonshSqlite, zsh::Zsh, zsh_histdb::ZshHistDb,
|
||||
},
|
||||
};
|
||||
|
||||
@ -57,7 +57,9 @@ impl Cmd {
|
||||
match self {
|
||||
Self::Auto => {
|
||||
if cfg!(windows) {
|
||||
println!("This feature does not work on windows. Please run atuin import <SHELL>. To view a list of shells, run atuin import.");
|
||||
println!(
|
||||
"This feature does not work on windows. Please run atuin import <SHELL>. To view a list of shells, run atuin import."
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use atuin_client::{encryption, record::sqlite_store::SqliteStore, settings::Settings};
|
||||
use atuin_dotfiles::store::{var::VarStore, AliasStore};
|
||||
use atuin_dotfiles::store::{AliasStore, var::VarStore};
|
||||
use clap::{Parser, ValueEnum};
|
||||
use eyre::{Result, WrapErr};
|
||||
|
||||
@ -160,7 +160,9 @@ $env.config = (
|
||||
|
||||
pub async fn run(self, settings: &Settings) -> Result<()> {
|
||||
if !settings.paths_ok() {
|
||||
eprintln!("Atuin settings paths are broken. Disabling atuin shell hooks. Run `atuin doctor` to diagnose.");
|
||||
eprintln!(
|
||||
"Atuin settings paths are broken. Disabling atuin shell hooks. Run `atuin doctor` to diagnose."
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use atuin_dotfiles::store::{var::VarStore, AliasStore};
|
||||
use atuin_dotfiles::store::{AliasStore, var::VarStore};
|
||||
use eyre::Result;
|
||||
|
||||
pub fn init_static(disable_up_arrow: bool, disable_ctrl_r: bool) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use atuin_dotfiles::store::{var::VarStore, AliasStore};
|
||||
use atuin_dotfiles::store::{AliasStore, var::VarStore};
|
||||
use eyre::Result;
|
||||
|
||||
pub fn init_static(disable_up_arrow: bool, disable_ctrl_r: bool) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use atuin_dotfiles::store::{var::VarStore, AliasStore};
|
||||
use atuin_dotfiles::store::{AliasStore, var::VarStore};
|
||||
use eyre::Result;
|
||||
|
||||
pub fn init_static(disable_up_arrow: bool, disable_ctrl_r: bool) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use atuin_dotfiles::store::{var::VarStore, AliasStore};
|
||||
use atuin_dotfiles::store::{AliasStore, var::VarStore};
|
||||
use eyre::Result;
|
||||
|
||||
pub fn init_static(disable_up_arrow: bool, disable_ctrl_r: bool) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::io::{stderr, IsTerminal as _};
|
||||
use std::io::{IsTerminal as _, stderr};
|
||||
|
||||
use atuin_common::utils::{self, Escapable as _};
|
||||
use clap::Parser;
|
||||
@ -6,9 +6,9 @@ use eyre::Result;
|
||||
|
||||
use atuin_client::{
|
||||
database::Database,
|
||||
database::{current_context, OptFilters},
|
||||
database::{OptFilters, current_context},
|
||||
encryption,
|
||||
history::{store::HistoryStore, History},
|
||||
history::{History, store::HistoryStore},
|
||||
record::sqlite_store::SqliteStore,
|
||||
settings::{FilterMode, KeymapMode, SearchMode, Settings, Timezone},
|
||||
theme::Theme,
|
||||
@ -165,7 +165,9 @@ impl Cmd {
|
||||
}
|
||||
|
||||
if self.delete && query.is_empty() {
|
||||
eprintln!("Please specify a query to match the items you wish to delete. If you wish to delete all history, pass --delete-it-all");
|
||||
eprintln!(
|
||||
"Please specify a query to match the items you wish to delete. If you wish to delete all history, pass --delete-it-all"
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -184,11 +184,7 @@ impl Cursor {
|
||||
}
|
||||
|
||||
pub fn back(&mut self) -> Option<char> {
|
||||
if self.left() {
|
||||
self.remove()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
if self.left() { self.remove() } else { None }
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
|
@ -3,7 +3,7 @@ use std::path::Path;
|
||||
use async_trait::async_trait;
|
||||
use atuin_client::{database::Database, history::History, settings::FilterMode};
|
||||
use eyre::Result;
|
||||
use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher};
|
||||
use fuzzy_matcher::{FuzzyMatcher, skim::SkimMatcherV2};
|
||||
use itertools::Itertools;
|
||||
use time::OffsetDateTime;
|
||||
use tokio::task::yield_now;
|
||||
|
@ -6,12 +6,12 @@ use atuin_client::{
|
||||
settings::Settings,
|
||||
};
|
||||
use ratatui::{
|
||||
Frame,
|
||||
crossterm::event::{KeyCode, KeyEvent, KeyModifiers},
|
||||
layout::Rect,
|
||||
prelude::{Constraint, Direction, Layout},
|
||||
style::Style,
|
||||
widgets::{Bar, BarChart, BarGroup, Block, Borders, Padding, Paragraph, Row, Table},
|
||||
Frame,
|
||||
};
|
||||
|
||||
use super::duration::format_duration;
|
||||
@ -21,11 +21,7 @@ use super::interactive::{InputAction, State};
|
||||
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
fn u64_or_zero(num: i64) -> u64 {
|
||||
if num < 0 {
|
||||
0
|
||||
} else {
|
||||
num as u64
|
||||
}
|
||||
if num < 0 { 0 } else { num as u64 }
|
||||
}
|
||||
|
||||
pub fn draw_commands(
|
||||
|
@ -1,5 +1,5 @@
|
||||
use std::{
|
||||
io::{stdout, Write},
|
||||
io::{Write, stdout},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
@ -11,8 +11,8 @@ use time::OffsetDateTime;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use atuin_client::{
|
||||
database::{current_context, Database},
|
||||
history::{store::HistoryStore, History, HistoryStats},
|
||||
database::{Database, current_context},
|
||||
history::{History, HistoryStats, store::HistoryStore},
|
||||
settings::{
|
||||
CursorStyle, ExitMode, FilterMode, KeymapMode, PreviewStrategy, SearchMode, Settings,
|
||||
},
|
||||
@ -25,9 +25,10 @@ use super::{
|
||||
};
|
||||
|
||||
use crate::command::client::theme::{Meaning, Theme};
|
||||
use crate::{command::client::search::engines, VERSION};
|
||||
use crate::{VERSION, command::client::search::engines};
|
||||
|
||||
use ratatui::{
|
||||
Frame, Terminal, TerminalOptions, Viewport,
|
||||
backend::CrosstermBackend,
|
||||
crossterm::{
|
||||
cursor::SetCursorStyle,
|
||||
@ -42,8 +43,7 @@ use ratatui::{
|
||||
prelude::*,
|
||||
style::{Modifier, Style},
|
||||
text::{Line, Span, Text},
|
||||
widgets::{block::Title, Block, BorderType, Borders, Padding, Paragraph, Tabs},
|
||||
Frame, Terminal, TerminalOptions, Viewport,
|
||||
widgets::{Block, BorderType, Borders, Padding, Paragraph, Tabs, block::Title},
|
||||
};
|
||||
|
||||
const TAB_TITLES: [&str; 2] = ["Search", "Inspect"];
|
||||
@ -390,7 +390,7 @@ impl State {
|
||||
KeyCode::Char(c @ '1'..='9') if modfr => {
|
||||
return c.to_digit(10).map_or(InputAction::Continue, |c| {
|
||||
InputAction::Accept(self.results_state.selected() + c as usize)
|
||||
})
|
||||
});
|
||||
}
|
||||
KeyCode::Left if ctrl => self
|
||||
.search
|
||||
@ -763,7 +763,9 @@ impl State {
|
||||
|
||||
// HACK: I'm following up with abstracting this into the UI container, with a
|
||||
// sub-widget for search + for inspector
|
||||
let feedback = Paragraph::new("The inspector is new - please give feedback (good, or bad) at https://forum.atuin.sh");
|
||||
let feedback = Paragraph::new(
|
||||
"The inspector is new - please give feedback (good, or bad) at https://forum.atuin.sh",
|
||||
);
|
||||
f.render_widget(feedback, input_chunk);
|
||||
|
||||
return;
|
||||
|
@ -4,7 +4,7 @@ use interim::parse_date_string;
|
||||
use time::{Duration, OffsetDateTime, Time};
|
||||
|
||||
use atuin_client::{
|
||||
database::{current_context, Database},
|
||||
database::{Database, current_context},
|
||||
settings::Settings,
|
||||
theme::Theme,
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
use atuin_dotfiles::store::{var::VarStore, AliasStore};
|
||||
use atuin_dotfiles::store::{AliasStore, var::VarStore};
|
||||
use clap::Args;
|
||||
use eyre::{bail, Result};
|
||||
use eyre::{Result, bail};
|
||||
|
||||
use atuin_client::{
|
||||
database::Database, encryption, history::store::HistoryStore,
|
||||
|
@ -1,9 +1,9 @@
|
||||
use clap::Args;
|
||||
use eyre::{bail, Result};
|
||||
use eyre::{Result, bail};
|
||||
use tokio::{fs::File, io::AsyncWriteExt};
|
||||
|
||||
use atuin_client::{
|
||||
encryption::{decode_key, encode_key, generate_encoded_key, load_key, Key},
|
||||
encryption::{Key, decode_key, encode_key, generate_encoded_key, load_key},
|
||||
record::sqlite_store::SqliteStore,
|
||||
record::store::Store,
|
||||
settings::Settings,
|
||||
@ -23,7 +23,8 @@ impl Rekey {
|
||||
let key = match bip39::Mnemonic::from_phrase(&key, bip39::Language::English) {
|
||||
Ok(mnemonic) => encode_key(Key::from_slice(mnemonic.entropy()))?,
|
||||
Err(err) => {
|
||||
if let Some(err) = err.downcast_ref::<bip39::ErrorKind>() {
|
||||
match err.downcast_ref::<bip39::ErrorKind>() {
|
||||
Some(err) => {
|
||||
match err {
|
||||
// assume they copied in the base64 key
|
||||
bip39::ErrorKind::InvalidWord => key,
|
||||
@ -36,11 +37,13 @@ impl Rekey {
|
||||
bail!("key was not the correct length")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
_ => {
|
||||
// unknown error. assume they copied the base64 key
|
||||
key
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
key
|
||||
|
@ -5,7 +5,7 @@ use time::{Date, Duration, Month, OffsetDateTime, Time};
|
||||
|
||||
use atuin_client::{database::Database, settings::Settings, theme::Theme};
|
||||
|
||||
use atuin_history::stats::{compute, Stats};
|
||||
use atuin_history::stats::{Stats, compute};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct WrappedStats {
|
||||
@ -293,7 +293,9 @@ pub async fn run(
|
||||
|
||||
let history = db.range(start, end).await?;
|
||||
if history.is_empty() {
|
||||
println!("Your history for {year} is empty!\nMaybe 'atuin import' could help you import your previous history 🪄");
|
||||
println!(
|
||||
"Your history for {year} is empty!\nMaybe 'atuin import' could help you import your previous history 🪄"
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clap::{CommandFactory, Parser, ValueEnum};
|
||||
use clap_complete::{generate, generate_to, Generator, Shell};
|
||||
use clap_complete::{Generator, Shell, generate, generate_to};
|
||||
use clap_complete_nushell::Nushell;
|
||||
use eyre::Result;
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use atuin_server_postgres::Postgres;
|
||||
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
|
||||
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
|
||||
|
||||
use clap::Parser;
|
||||
use eyre::{Context, Result};
|
||||
|
||||
use atuin_server::{example_config, launch, launch_metrics_server, Settings};
|
||||
use atuin_server::{Settings, example_config, launch, launch_metrics_server};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(infer_subcommands = true)]
|
||||
|
@ -1,4 +1,4 @@
|
||||
use atuin_dotfiles::store::{var::VarStore, AliasStore};
|
||||
use atuin_dotfiles::store::{AliasStore, var::VarStore};
|
||||
use eyre::{Context, Result};
|
||||
|
||||
use atuin_client::{
|
||||
|
@ -2,12 +2,12 @@ use std::{env, time::Duration};
|
||||
|
||||
use atuin_client::api_client;
|
||||
use atuin_common::utils::uuid_v7;
|
||||
use atuin_server::{launch_with_tcp_listener, Settings as ServerSettings};
|
||||
use atuin_server::{Settings as ServerSettings, launch_with_tcp_listener};
|
||||
use atuin_server_postgres::{Postgres, PostgresSettings};
|
||||
use futures_util::TryFutureExt;
|
||||
use tokio::{net::TcpListener, sync::oneshot, task::JoinHandle};
|
||||
use tracing::{dispatcher, Dispatch};
|
||||
use tracing_subscriber::{layer::SubscriberExt, EnvFilter};
|
||||
use tracing::{Dispatch, dispatcher};
|
||||
use tracing_subscriber::{EnvFilter, layer::SubscriberExt};
|
||||
|
||||
pub async fn start_server(path: &str) -> (String, oneshot::Sender<()>, JoinHandle<()>) {
|
||||
let formatting_layer = tracing_tree::HierarchicalLayer::default()
|
||||
|
Reference in New Issue
Block a user