mirror of
https://github.com/atuinsh/atuin.git
synced 2024-11-25 17:54:55 +01:00
feat: Add xonsh history import (#1678)
* add importers for xonsh JSON files and SQLite db * rustfmt xonsh importers * remove env-dependent tests from xonsh importers * pass xonsh_data_dir into path resolver instead of looking up in env * review: run format * review: fix clippy errors --------- Co-authored-by: Ellie Huxtable <ellie@elliehuxtable.com>
This commit is contained in:
parent
8ef5f67f8b
commit
87e19df9c5
@ -13,6 +13,8 @@ pub mod fish;
|
||||
pub mod nu;
|
||||
pub mod nu_histdb;
|
||||
pub mod resh;
|
||||
pub mod xonsh;
|
||||
pub mod xonsh_sqlite;
|
||||
pub mod zsh;
|
||||
pub mod zsh_histdb;
|
||||
|
||||
|
238
atuin-client/src/import/xonsh.rs
Normal file
238
atuin-client/src/import/xonsh.rs
Normal file
@ -0,0 +1,238 @@
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use directories::BaseDirs;
|
||||
use eyre::{eyre, Result};
|
||||
use serde::Deserialize;
|
||||
use time::OffsetDateTime;
|
||||
use uuid::timestamp::{context::NoContext, Timestamp};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::{Importer, Loader};
|
||||
use crate::history::History;
|
||||
|
||||
// Note: both HistoryFile and HistoryData have other keys present in the JSON, we don't
|
||||
// care about them so we leave them unspecified so as to avoid deserializing unnecessarily.
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct HistoryFile {
|
||||
data: HistoryData,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct HistoryData {
|
||||
sessionid: String,
|
||||
cmds: Vec<HistoryCmd>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct HistoryCmd {
|
||||
cwd: String,
|
||||
inp: String,
|
||||
rtn: Option<i64>,
|
||||
ts: (f64, f64),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Xonsh {
|
||||
// history is stored as a bunch of json files, one per session
|
||||
sessions: Vec<HistoryData>,
|
||||
hostname: String,
|
||||
}
|
||||
|
||||
fn get_hist_dir(xonsh_data_dir: Option<String>) -> Result<PathBuf> {
|
||||
// if running within xonsh, this will be available
|
||||
if let Some(d) = xonsh_data_dir {
|
||||
let mut path = PathBuf::from(d);
|
||||
path.push("history_json");
|
||||
return Ok(path);
|
||||
}
|
||||
|
||||
// otherwise, fall back to default
|
||||
let base = BaseDirs::new().ok_or_else(|| eyre!("Could not determine home directory"))?;
|
||||
|
||||
let hist_dir = base.data_dir().join("xonsh/history_json");
|
||||
if hist_dir.exists() || cfg!(test) {
|
||||
Ok(hist_dir)
|
||||
} else {
|
||||
Err(eyre!("Could not find xonsh history files"))
|
||||
}
|
||||
}
|
||||
|
||||
fn get_hostname() -> String {
|
||||
format!(
|
||||
"{}:{}",
|
||||
env::var("ATUIN_HOST_NAME").unwrap_or_else(|_| whoami::hostname()),
|
||||
env::var("ATUIN_HOST_USER").unwrap_or_else(|_| whoami::username()),
|
||||
)
|
||||
}
|
||||
|
||||
fn load_sessions(hist_dir: &Path) -> Result<Vec<HistoryData>> {
|
||||
let mut sessions = vec![];
|
||||
for entry in fs::read_dir(hist_dir)? {
|
||||
let p = entry?.path();
|
||||
let ext = p.extension().and_then(|e| e.to_str());
|
||||
if p.is_file() && ext == Some("json") {
|
||||
if let Some(data) = load_session(&p)? {
|
||||
sessions.push(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(sessions)
|
||||
}
|
||||
|
||||
fn load_session(path: &Path) -> Result<Option<HistoryData>> {
|
||||
let file = File::open(path)?;
|
||||
// empty files are not valid json, so we can't deserialize them
|
||||
if file.metadata()?.len() == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut hist_file: HistoryFile = serde_json::from_reader(file)?;
|
||||
|
||||
// if there are commands in this session, replace the existing UUIDv4
|
||||
// with a UUIDv7 generated from the timestamp of the first command
|
||||
if let Some(cmd) = hist_file.data.cmds.first() {
|
||||
let seconds = cmd.ts.0.trunc() as u64;
|
||||
let nanos = (cmd.ts.0.fract() * 1_000_000_000_f64) as u32;
|
||||
let ts = Timestamp::from_unix(NoContext, seconds, nanos);
|
||||
hist_file.data.sessionid = Uuid::new_v7(ts).to_string();
|
||||
}
|
||||
Ok(Some(hist_file.data))
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Importer for Xonsh {
|
||||
const NAME: &'static str = "xonsh";
|
||||
|
||||
async fn new() -> Result<Self> {
|
||||
let hist_dir = get_hist_dir(env::var("XONSH_DATA_DIR").ok())?;
|
||||
let sessions = load_sessions(&hist_dir)?;
|
||||
let hostname = get_hostname();
|
||||
Ok(Xonsh { sessions, hostname })
|
||||
}
|
||||
|
||||
async fn entries(&mut self) -> Result<usize> {
|
||||
let total = self.sessions.iter().map(|s| s.cmds.len()).sum();
|
||||
Ok(total)
|
||||
}
|
||||
|
||||
async fn load(self, loader: &mut impl Loader) -> Result<()> {
|
||||
for session in self.sessions {
|
||||
for cmd in session.cmds {
|
||||
let (start, end) = cmd.ts;
|
||||
let ts_nanos = (start * 1_000_000_000_f64) as i128;
|
||||
let timestamp = OffsetDateTime::from_unix_timestamp_nanos(ts_nanos)?;
|
||||
|
||||
let duration = (end - start) * 1_000_000_000_f64;
|
||||
|
||||
match cmd.rtn {
|
||||
Some(exit) => {
|
||||
let entry = History::import()
|
||||
.timestamp(timestamp)
|
||||
.duration(duration.trunc() as i64)
|
||||
.exit(exit)
|
||||
.command(cmd.inp.trim())
|
||||
.cwd(cmd.cwd)
|
||||
.session(session.sessionid.clone())
|
||||
.hostname(self.hostname.clone());
|
||||
loader.push(entry.build().into()).await?;
|
||||
}
|
||||
None => {
|
||||
let entry = History::import()
|
||||
.timestamp(timestamp)
|
||||
.duration(duration.trunc() as i64)
|
||||
.command(cmd.inp.trim())
|
||||
.cwd(cmd.cwd)
|
||||
.session(session.sessionid.clone())
|
||||
.hostname(self.hostname.clone());
|
||||
loader.push(entry.build().into()).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use time::macros::datetime;
|
||||
|
||||
use super::*;
|
||||
|
||||
use crate::history::History;
|
||||
use crate::import::tests::TestLoader;
|
||||
|
||||
#[test]
|
||||
fn test_hist_dir_xonsh() {
|
||||
let hist_dir = get_hist_dir(Some("/home/user/xonsh_data".to_string())).unwrap();
|
||||
assert_eq!(
|
||||
hist_dir,
|
||||
PathBuf::from("/home/user/xonsh_data/history_json")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_import() {
|
||||
let dir = PathBuf::from("tests/data/xonsh");
|
||||
let sessions = load_sessions(&dir).unwrap();
|
||||
let hostname = "box:user".to_string();
|
||||
let xonsh = Xonsh { sessions, hostname };
|
||||
|
||||
let mut loader = TestLoader::default();
|
||||
xonsh.load(&mut loader).await.unwrap();
|
||||
// order in buf will depend on filenames, so sort by timestamp for consistency
|
||||
loader.buf.sort_by_key(|h| h.timestamp);
|
||||
for (actual, expected) in loader.buf.iter().zip(expected_hist_entries().iter()) {
|
||||
assert_eq!(actual.timestamp, expected.timestamp);
|
||||
assert_eq!(actual.command, expected.command);
|
||||
assert_eq!(actual.cwd, expected.cwd);
|
||||
assert_eq!(actual.exit, expected.exit);
|
||||
assert_eq!(actual.duration, expected.duration);
|
||||
assert_eq!(actual.hostname, expected.hostname);
|
||||
}
|
||||
}
|
||||
|
||||
fn expected_hist_entries() -> [History; 4] {
|
||||
[
|
||||
History::import()
|
||||
.timestamp(datetime!(2024-02-6 04:17:59.478272256 +00:00:00))
|
||||
.command("echo hello world!".to_string())
|
||||
.cwd("/home/user/Documents/code/atuin".to_string())
|
||||
.exit(0)
|
||||
.duration(4651069)
|
||||
.hostname("box:user".to_string())
|
||||
.build()
|
||||
.into(),
|
||||
History::import()
|
||||
.timestamp(datetime!(2024-02-06 04:18:01.70632832 +00:00:00))
|
||||
.command("ls -l".to_string())
|
||||
.cwd("/home/user/Documents/code/atuin".to_string())
|
||||
.exit(0)
|
||||
.duration(21288633)
|
||||
.hostname("box:user".to_string())
|
||||
.build()
|
||||
.into(),
|
||||
History::import()
|
||||
.timestamp(datetime!(2024-02-06 17:41:31.142515968 +00:00:00))
|
||||
.command("false".to_string())
|
||||
.cwd("/home/user/Documents/code/atuin/atuin-client".to_string())
|
||||
.exit(1)
|
||||
.duration(10269403)
|
||||
.hostname("box:user".to_string())
|
||||
.build()
|
||||
.into(),
|
||||
History::import()
|
||||
.timestamp(datetime!(2024-02-06 17:41:32.271584 +00:00:00))
|
||||
.command("exit".to_string())
|
||||
.cwd("/home/user/Documents/code/atuin/atuin-client".to_string())
|
||||
.exit(0)
|
||||
.duration(4259347)
|
||||
.hostname("box:user".to_string())
|
||||
.build()
|
||||
.into(),
|
||||
]
|
||||
}
|
||||
}
|
222
atuin-client/src/import/xonsh_sqlite.rs
Normal file
222
atuin-client/src/import/xonsh_sqlite.rs
Normal file
@ -0,0 +1,222 @@
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use directories::BaseDirs;
|
||||
use eyre::{eyre, Result};
|
||||
use futures::TryStreamExt;
|
||||
use sqlx::{sqlite::SqlitePool, FromRow, Row};
|
||||
use time::OffsetDateTime;
|
||||
use uuid::timestamp::{context::NoContext, Timestamp};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::{Importer, Loader};
|
||||
use crate::history::History;
|
||||
|
||||
#[derive(Debug, FromRow)]
|
||||
struct HistDbEntry {
|
||||
inp: String,
|
||||
rtn: Option<i64>,
|
||||
tsb: f64,
|
||||
tse: f64,
|
||||
cwd: String,
|
||||
session_start: f64,
|
||||
}
|
||||
|
||||
impl HistDbEntry {
|
||||
fn into_hist_with_hostname(self, hostname: String) -> History {
|
||||
let ts_nanos = (self.tsb * 1_000_000_000_f64) as i128;
|
||||
let timestamp = OffsetDateTime::from_unix_timestamp_nanos(ts_nanos).unwrap();
|
||||
|
||||
let session_ts_seconds = self.session_start.trunc() as u64;
|
||||
let session_ts_nanos = (self.session_start.fract() * 1_000_000_000_f64) as u32;
|
||||
let session_ts = Timestamp::from_unix(NoContext, session_ts_seconds, session_ts_nanos);
|
||||
let session_id = Uuid::new_v7(session_ts).to_string();
|
||||
let duration = (self.tse - self.tsb) * 1_000_000_000_f64;
|
||||
|
||||
if let Some(exit) = self.rtn {
|
||||
let imported = History::import()
|
||||
.timestamp(timestamp)
|
||||
.duration(duration.trunc() as i64)
|
||||
.exit(exit)
|
||||
.command(self.inp)
|
||||
.cwd(self.cwd)
|
||||
.session(session_id)
|
||||
.hostname(hostname);
|
||||
imported.build().into()
|
||||
} else {
|
||||
let imported = History::import()
|
||||
.timestamp(timestamp)
|
||||
.duration(duration.trunc() as i64)
|
||||
.command(self.inp)
|
||||
.cwd(self.cwd)
|
||||
.session(session_id)
|
||||
.hostname(hostname);
|
||||
imported.build().into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_db_path(xonsh_data_dir: Option<String>) -> Result<PathBuf> {
|
||||
// if running within xonsh, this will be available
|
||||
if let Some(d) = xonsh_data_dir {
|
||||
let mut path = PathBuf::from(d);
|
||||
path.push("xonsh-history.sqlite");
|
||||
return Ok(path);
|
||||
}
|
||||
|
||||
// otherwise, fall back to default
|
||||
let base = BaseDirs::new().ok_or_else(|| eyre!("Could not determine home directory"))?;
|
||||
|
||||
let hist_file = base.data_dir().join("xonsh/xonsh-history.sqlite");
|
||||
if hist_file.exists() || cfg!(test) {
|
||||
Ok(hist_file)
|
||||
} else {
|
||||
Err(eyre!(
|
||||
"Could not find xonsh history db at: {}",
|
||||
hist_file.to_string_lossy()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn get_hostname() -> String {
|
||||
format!(
|
||||
"{}:{}",
|
||||
env::var("ATUIN_HOST_NAME").unwrap_or_else(|_| whoami::hostname()),
|
||||
env::var("ATUIN_HOST_USER").unwrap_or_else(|_| whoami::username()),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XonshSqlite {
|
||||
pool: SqlitePool,
|
||||
hostname: String,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Importer for XonshSqlite {
|
||||
const NAME: &'static str = "xonsh_sqlite";
|
||||
|
||||
async fn new() -> Result<Self> {
|
||||
let db_path = get_db_path(env::var("XONSH_DATA_DIR").ok())?;
|
||||
let connection_str = db_path.to_str().ok_or_else(|| {
|
||||
eyre!(
|
||||
"Invalid path for SQLite database: {}",
|
||||
db_path.to_string_lossy()
|
||||
)
|
||||
})?;
|
||||
|
||||
let pool = SqlitePool::connect(connection_str).await?;
|
||||
let hostname = get_hostname();
|
||||
Ok(XonshSqlite { pool, hostname })
|
||||
}
|
||||
|
||||
async fn entries(&mut self) -> Result<usize> {
|
||||
let query = "SELECT COUNT(*) FROM xonsh_history";
|
||||
let row = sqlx::query(query).fetch_one(&self.pool).await?;
|
||||
let count: u32 = row.get(0);
|
||||
Ok(count as usize)
|
||||
}
|
||||
|
||||
async fn load(self, loader: &mut impl Loader) -> Result<()> {
|
||||
let query = r#"
|
||||
SELECT inp, rtn, tsb, tse, cwd,
|
||||
MIN(tsb) OVER (PARTITION BY sessionid) AS session_start
|
||||
FROM xonsh_history
|
||||
ORDER BY rowid
|
||||
"#;
|
||||
|
||||
let mut entries = sqlx::query_as::<_, HistDbEntry>(query).fetch(&self.pool);
|
||||
|
||||
let mut count = 0;
|
||||
while let Some(entry) = entries.try_next().await? {
|
||||
let hist = entry.into_hist_with_hostname(self.hostname.clone());
|
||||
loader.push(hist).await?;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
println!("Loaded: {count}");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use time::macros::datetime;
|
||||
|
||||
use super::*;
|
||||
|
||||
use crate::history::History;
|
||||
use crate::import::tests::TestLoader;
|
||||
|
||||
#[test]
|
||||
fn test_db_path_xonsh() {
|
||||
let db_path = get_db_path(Some("/home/user/xonsh_data".to_string())).unwrap();
|
||||
assert_eq!(
|
||||
db_path,
|
||||
PathBuf::from("/home/user/xonsh_data/xonsh-history.sqlite")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_import() {
|
||||
let connection_str = "tests/data/xonsh-history.sqlite";
|
||||
let xonsh_sqlite = XonshSqlite {
|
||||
pool: SqlitePool::connect(connection_str).await.unwrap(),
|
||||
hostname: "box:user".to_string(),
|
||||
};
|
||||
|
||||
let mut loader = TestLoader::default();
|
||||
xonsh_sqlite.load(&mut loader).await.unwrap();
|
||||
|
||||
for (actual, expected) in loader.buf.iter().zip(expected_hist_entries().iter()) {
|
||||
assert_eq!(actual.timestamp, expected.timestamp);
|
||||
assert_eq!(actual.command, expected.command);
|
||||
assert_eq!(actual.cwd, expected.cwd);
|
||||
assert_eq!(actual.exit, expected.exit);
|
||||
assert_eq!(actual.duration, expected.duration);
|
||||
assert_eq!(actual.hostname, expected.hostname);
|
||||
}
|
||||
}
|
||||
|
||||
fn expected_hist_entries() -> [History; 4] {
|
||||
[
|
||||
History::import()
|
||||
.timestamp(datetime!(2024-02-6 17:56:21.130956288 +00:00:00))
|
||||
.command("echo hello world!".to_string())
|
||||
.cwd("/home/user/Documents/code/atuin".to_string())
|
||||
.exit(0)
|
||||
.duration(2628564)
|
||||
.hostname("box:user".to_string())
|
||||
.build()
|
||||
.into(),
|
||||
History::import()
|
||||
.timestamp(datetime!(2024-02-06 17:56:28.190406144 +00:00:00))
|
||||
.command("ls -l".to_string())
|
||||
.cwd("/home/user/Documents/code/atuin".to_string())
|
||||
.exit(0)
|
||||
.duration(9371519)
|
||||
.hostname("box:user".to_string())
|
||||
.build()
|
||||
.into(),
|
||||
History::import()
|
||||
.timestamp(datetime!(2024-02-06 17:56:46.989020928 +00:00:00))
|
||||
.command("false".to_string())
|
||||
.cwd("/home/user/Documents/code/atuin".to_string())
|
||||
.exit(1)
|
||||
.duration(17337560)
|
||||
.hostname("box:user".to_string())
|
||||
.build()
|
||||
.into(),
|
||||
History::import()
|
||||
.timestamp(datetime!(2024-02-06 17:56:48.218384128 +00:00:00))
|
||||
.command("exit".to_string())
|
||||
.cwd("/home/user/Documents/code/atuin".to_string())
|
||||
.exit(0)
|
||||
.duration(4599094)
|
||||
.hostname("box:user".to_string())
|
||||
.build()
|
||||
.into(),
|
||||
]
|
||||
}
|
||||
}
|
BIN
atuin-client/tests/data/xonsh-history.sqlite
Normal file
BIN
atuin-client/tests/data/xonsh-history.sqlite
Normal file
Binary file not shown.
@ -0,0 +1,12 @@
|
||||
{"locs": [ 69, 3371, 3451, 3978],
|
||||
"index": {"offsets":{"__total__":0,"cmds":[{"__total__":10,"cwd":18,"inp":78,"rtn":96,"ts":[106,125,105]},{"__total__":149,"cwd":157,"inp":217,"rtn":234,"ts":[244,263,243]},9],"env":{"ATUIN_SESSION":314,"BASH_COMPLETIONS":370,"COLORTERM":433,"DBUS_SESSION_BUS_ADDRESS":474,"DESKTOP_SESSION":529,"DISPLAY":550,"GDMSESSION":570,"GIO_LAUNCHED_DESKTOP_FILE":609,"GIO_LAUNCHED_DESKTOP_FILE_PID":704,"GJS_DEBUG_OUTPUT":734,"GJS_DEBUG_TOPICS":764,"GNOME_DESKTOP_SESSION_ID":811,"GNOME_SETUP_DISPLAY":856,"GNOME_SHELL_SESSION_MODE":890,"GTK_MODULES":915,"HOME":942,"IM_CONFIG_PHASE":976,"INVOCATION_ID":998,"JOURNAL_STREAM":1052,"LANG":1071,"LOGNAME":1097,"MANAGERPID":1118,"MOZ_ENABLE_WAYLAND":1148,"PATH":1161,"PWD":1736,"PYENV_DIR":1802,"PYENV_HOOK_PATH":1874,"PYENV_ROOT":2048,"PYENV_SHELL":2086,"PYENV_VERSION":2111,"QT_ACCESSIBILITY":2141,"QT_IM_MODULE":2162,"SESSION_MANAGER":2189,"SHELL":2279,"SHLVL":2303,"SSH_AGENT_LAUNCHER":2330,"SSH_AUTH_SOCK":2364,"SSL_CERT_DIR":2415,"SSL_CERT_FILE":2458,"SYSTEMD_EXEC_PID":2525,"TERM":2541,"TERM_PROGRAM":2575,"TERM_PROGRAM_VERSION":2610,"THREAD_SUBPROCS":2657,"USER":2670,"USERNAME":2689,"WAYLAND_DISPLAY":2715,"WEZTERM_CONFIG_DIR":2750,"WEZTERM_CONFIG_FILE":2806,"WEZTERM_EXECUTABLE":2874,"WEZTERM_EXECUTABLE_DIR":2927,"WEZTERM_PANE":2957,"WEZTERM_UNIX_SOCKET":2986,"XAUTHORITY":3047,"XDG_CONFIG_DIRS":3116,"XDG_CURRENT_DESKTOP":3176,"XDG_DATA_DIRS":3209,"XDG_MENU_PREFIX":3316,"XDG_RUNTIME_DIR":3345,"XDG_SESSION_CLASS":3387,"XDG_SESSION_DESKTOP":3418,"XDG_SESSION_TYPE":3448,"XMODIFIERS":3473,"XONSHRC":3496,"XONSHRC_DIR":3594,"XONSH_CAPTURE_ALWAYS":3674,"XONSH_CONFIG_DIR":3698,"XONSH_DATA_DIR":3747,"XONSH_INTERACTIVE":3805,"XONSH_LOGIN":3825,"XONSH_VERSION":3847,"__total__":296},"locked":3869,"sessionid":3889,"ts":[3936,3956,3935]},"sizes":{"__total__":3978,"cmds":[{"__total__":137,"cwd":51,"inp":9,"rtn":1,"ts":[17,18,40]},{"__total__":136,"cwd":51,"inp":8,"rtn":1,"ts":[17,18,40]},278],"env":{"ATUIN_SESSION":34,"BASH_COMPLETIONS":48,"COLORTERM":11,"DBUS_SESSION_BUS_ADDRESS":34,"DESKTOP_SESSION":8,"DISPLAY":4,"GDMSESSION":8,"GIO_LAUNCHED_DESKTOP_FILE":60,"GIO_LAUNCHED_DESKTOP_FILE_PID":8,"GJS_DEBUG_OUTPUT":8,"GJS_DEBUG_TOPICS":17,"GNOME_DESKTOP_SESSION_ID":20,"GNOME_SETUP_DISPLAY":4,"GNOME_SHELL_SESSION_MODE":8,"GTK_MODULES":17,"HOME":13,"IM_CONFIG_PHASE":3,"INVOCATION_ID":34,"JOURNAL_STREAM":9,"LANG":13,"LOGNAME":5,"MANAGERPID":6,"MOZ_ENABLE_WAYLAND":3,"PATH":566,"PWD":51,"PYENV_DIR":51,"PYENV_HOOK_PATH":158,"PYENV_ROOT":21,"PYENV_SHELL":6,"PYENV_VERSION":8,"QT_ACCESSIBILITY":3,"QT_IM_MODULE":6,"SESSION_MANAGER":79,"SHELL":13,"SHLVL":3,"SSH_AGENT_LAUNCHER":15,"SSH_AUTH_SOCK":33,"SSL_CERT_DIR":24,"SSL_CERT_FILE":45,"SYSTEMD_EXEC_PID":6,"TERM":16,"TERM_PROGRAM":9,"TERM_PROGRAM_VERSION":26,"THREAD_SUBPROCS":3,"USER":5,"USERNAME":5,"WAYLAND_DISPLAY":11,"WEZTERM_CONFIG_DIR":31,"WEZTERM_CONFIG_FILE":44,"WEZTERM_EXECUTABLE":25,"WEZTERM_EXECUTABLE_DIR":12,"WEZTERM_PANE":4,"WEZTERM_UNIX_SOCKET":45,"XAUTHORITY":48,"XDG_CONFIG_DIRS":35,"XDG_CURRENT_DESKTOP":14,"XDG_DATA_DIRS":86,"XDG_MENU_PREFIX":8,"XDG_RUNTIME_DIR":19,"XDG_SESSION_CLASS":6,"XDG_SESSION_DESKTOP":8,"XDG_SESSION_TYPE":9,"XMODIFIERS":10,"XONSHRC":81,"XONSHRC_DIR":54,"XONSH_CAPTURE_ALWAYS":2,"XONSH_CONFIG_DIR":29,"XONSH_DATA_DIR":35,"XONSH_INTERACTIVE":3,"XONSH_LOGIN":3,"XONSH_VERSION":8,"__total__":3561},"locked":5,"sessionid":38,"ts":[18,18,41]}},
|
||||
"data": {"cmds": [{"cwd": "\/home\/user\/Documents\/code\/atuin\/atuin-client", "inp": "false\n", "rtn": 1, "ts": [1707241291.142516, 1707241291.1527853]
|
||||
}
|
||||
, {"cwd": "\/home\/user\/Documents\/code\/atuin\/atuin-client", "inp": "exit\n", "rtn": 0, "ts": [1707241292.271584, 1707241292.2758434]
|
||||
}
|
||||
]
|
||||
, "env": {"ATUIN_SESSION": "018d7f82ad167dc4888ca0bf294d2bfd", "BASH_COMPLETIONS": "\/usr\/share\/bash-completion\/bash_completion", "COLORTERM": "truecolor", "DBUS_SESSION_BUS_ADDRESS": "unix:path=\/run\/user\/1000\/bus", "DESKTOP_SESSION": "ubuntu", "DISPLAY": ":0", "GDMSESSION": "ubuntu", "GIO_LAUNCHED_DESKTOP_FILE": "\/usr\/share\/applications\/org.wezfurlong.wezterm.desktop", "GIO_LAUNCHED_DESKTOP_FILE_PID": "196859", "GJS_DEBUG_OUTPUT": "stderr", "GJS_DEBUG_TOPICS": "JS ERROR;JS LOG", "GNOME_DESKTOP_SESSION_ID": "this-is-deprecated", "GNOME_SETUP_DISPLAY": ":1", "GNOME_SHELL_SESSION_MODE": "ubuntu", "GTK_MODULES": "gail:atk-bridge", "HOME": "\/home\/user", "IM_CONFIG_PHASE": "1", "INVOCATION_ID": "4f121e7ad56c41a6b84aa3cbe1ad61fa", "JOURNAL_STREAM": "8:37187", "LANG": "en_US.UTF-8", "LOGNAME": "user", "MANAGERPID": "2118", "MOZ_ENABLE_WAYLAND": "1", "PATH": "\/home\/user\/.pyenv\/versions\/3.12.0\/bin:\/home\/user\/.pyenv\/libexec:\/home\/user\/.pyenv\/plugins\/python-build\/bin:\/home\/user\/.pyenv\/plugins\/pyenv-virtualenv\/bin:\/home\/user\/.pyenv\/plugins\/pyenv-update\/bin:\/home\/user\/.pyenv\/plugins\/pyenv-doctor\/bin:\/home\/user\/.cargo\/bin:\/home\/user\/.pyenv\/shims:\/home\/user\/.pyenv\/bin:\/home\/user\/bin:\/home\/user\/bin:\/usr\/local\/sbin:\/usr\/local\/bin:\/usr\/sbin:\/usr\/bin:\/sbin:\/bin:\/usr\/games:\/usr\/local\/games:\/snap\/bin:\/snap\/bin:\/home\/user\/.local\/share\/JetBrains\/Toolbox\/scripts", "PWD": "\/home\/user\/Documents\/code\/atuin\/atuin-client", "PYENV_DIR": "\/home\/user\/Documents\/code\/atuin\/atuin-client", "PYENV_HOOK_PATH": "\/home\/user\/.pyenv\/pyenv.d:\/usr\/local\/etc\/pyenv.d:\/etc\/pyenv.d:\/usr\/lib\/pyenv\/hooks:\/home\/user\/.pyenv\/plugins\/pyenv-virtualenv\/etc\/pyenv.d", "PYENV_ROOT": "\/home\/user\/.pyenv", "PYENV_SHELL": "bash", "PYENV_VERSION": "3.12.0", "QT_ACCESSIBILITY": "1", "QT_IM_MODULE": "ibus", "SESSION_MANAGER": "local\/box:@\/tmp\/.ICE-unix\/2452,unix\/box:\/tmp\/.ICE-unix\/2452", "SHELL": "\/bin\/bash", "SHLVL": "1", "SSH_AGENT_LAUNCHER": "gnome-keyring", "SSH_AUTH_SOCK": "\/run\/user\/1000\/keyring\/ssh", "SSL_CERT_DIR": "\/usr\/lib\/ssl\/certs", "SSL_CERT_FILE": "\/usr\/lib\/ssl\/certs\/ca-certificates.crt", "SYSTEMD_EXEC_PID": "2470", "TERM": "xterm-256color", "TERM_PROGRAM": "WezTerm", "TERM_PROGRAM_VERSION": "20240127-113634-bbcac864", "THREAD_SUBPROCS": "1", "USER": "user", "USERNAME": "user", "WAYLAND_DISPLAY": "wayland-0", "WEZTERM_CONFIG_DIR": "\/home\/user\/.config\/wezterm", "WEZTERM_CONFIG_FILE": "\/home\/user\/.config\/wezterm\/wezterm.lua", "WEZTERM_EXECUTABLE": "\/usr\/bin\/wezterm-gui", "WEZTERM_EXECUTABLE_DIR": "\/usr\/bin", "WEZTERM_PANE": "41", "WEZTERM_UNIX_SOCKET": "\/run\/user\/1000\/wezterm\/gui-sock-196859", "XAUTHORITY": "\/run\/user\/1000\/.mutter-Xwaylandauth.T986H2", "XDG_CONFIG_DIRS": "\/etc\/xdg\/xdg-ubuntu:\/etc\/xdg", "XDG_CURRENT_DESKTOP": "ubuntu:GNOME", "XDG_DATA_DIRS": "\/usr\/share\/ubuntu:\/usr\/local\/share\/:\/usr\/share\/:\/var\/lib\/snapd\/desktop", "XDG_MENU_PREFIX": "gnome-", "XDG_RUNTIME_DIR": "\/run\/user\/1000", "XDG_SESSION_CLASS": "user", "XDG_SESSION_DESKTOP": "ubuntu", "XDG_SESSION_TYPE": "wayland", "XMODIFIERS": "@im=ibus", "XONSHRC": "\/etc\/xonsh\/xonshrc:\/home\/user\/.config\/xonsh\/rc.xsh:\/home\/user\/.xonshrc", "XONSHRC_DIR": "\/etc\/xonsh\/rc.d:\/home\/user\/.config\/xonsh\/rc.d", "XONSH_CAPTURE_ALWAYS": "", "XONSH_CONFIG_DIR": "\/home\/user\/.config\/xonsh", "XONSH_DATA_DIR": "\/home\/user\/.local\/share\/xonsh", "XONSH_INTERACTIVE": "1", "XONSH_LOGIN": "1", "XONSH_VERSION": "0.14.2"}
|
||||
, "locked": false, "sessionid": "82eafbf5-9f43-489a-80d2-61c7dc6ef542", "ts": [1707241286.9361255, 1707241292.3081477]
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
{"locs": [ 69, 3372, 3452, 3936],
|
||||
"index": {"offsets":{"__total__":0,"cmds":[{"__total__":10,"cwd":18,"inp":64,"rtn":94,"ts":[104,124,103]},{"__total__":148,"cwd":156,"inp":202,"rtn":220,"ts":[230,250,229]},9],"env":{"ATUIN_SESSION":300,"BASH_COMPLETIONS":356,"COLORTERM":419,"DBUS_SESSION_BUS_ADDRESS":460,"DESKTOP_SESSION":515,"DISPLAY":536,"GDMSESSION":556,"GIO_LAUNCHED_DESKTOP_FILE":595,"GIO_LAUNCHED_DESKTOP_FILE_PID":690,"GJS_DEBUG_OUTPUT":720,"GJS_DEBUG_TOPICS":750,"GNOME_DESKTOP_SESSION_ID":797,"GNOME_SETUP_DISPLAY":842,"GNOME_SHELL_SESSION_MODE":876,"GTK_MODULES":901,"HOME":928,"IM_CONFIG_PHASE":962,"INVOCATION_ID":984,"JOURNAL_STREAM":1038,"LANG":1057,"LOGNAME":1083,"MANAGERPID":1104,"MOZ_ENABLE_WAYLAND":1134,"PATH":1147,"PWD":1722,"PYENV_DIR":1774,"PYENV_HOOK_PATH":1832,"PYENV_ROOT":2006,"PYENV_SHELL":2044,"PYENV_VERSION":2069,"QT_ACCESSIBILITY":2099,"QT_IM_MODULE":2120,"SESSION_MANAGER":2147,"SHELL":2237,"SHLVL":2261,"SSH_AGENT_LAUNCHER":2288,"SSH_AUTH_SOCK":2322,"SSL_CERT_DIR":2373,"SSL_CERT_FILE":2416,"SYSTEMD_EXEC_PID":2483,"TERM":2499,"TERM_PROGRAM":2533,"TERM_PROGRAM_VERSION":2568,"THREAD_SUBPROCS":2615,"USER":2628,"USERNAME":2647,"WAYLAND_DISPLAY":2673,"WEZTERM_CONFIG_DIR":2708,"WEZTERM_CONFIG_FILE":2764,"WEZTERM_EXECUTABLE":2832,"WEZTERM_EXECUTABLE_DIR":2885,"WEZTERM_PANE":2915,"WEZTERM_UNIX_SOCKET":2944,"XAUTHORITY":3005,"XDG_CONFIG_DIRS":3074,"XDG_CURRENT_DESKTOP":3134,"XDG_DATA_DIRS":3167,"XDG_MENU_PREFIX":3274,"XDG_RUNTIME_DIR":3303,"XDG_SESSION_CLASS":3345,"XDG_SESSION_DESKTOP":3376,"XDG_SESSION_TYPE":3406,"XMODIFIERS":3431,"XONSHRC":3454,"XONSHRC_DIR":3552,"XONSH_CAPTURE_ALWAYS":3632,"XONSH_CONFIG_DIR":3656,"XONSH_DATA_DIR":3705,"XONSH_INTERACTIVE":3763,"XONSH_LOGIN":3783,"XONSH_VERSION":3805,"__total__":282},"locked":3827,"sessionid":3847,"ts":[3894,3914,3893]},"sizes":{"__total__":3936,"cmds":[{"__total__":136,"cwd":37,"inp":21,"rtn":1,"ts":[18,18,41]},{"__total__":123,"cwd":37,"inp":9,"rtn":1,"ts":[18,17,40]},264],"env":{"ATUIN_SESSION":34,"BASH_COMPLETIONS":48,"COLORTERM":11,"DBUS_SESSION_BUS_ADDRESS":34,"DESKTOP_SESSION":8,"DISPLAY":4,"GDMSESSION":8,"GIO_LAUNCHED_DESKTOP_FILE":60,"GIO_LAUNCHED_DESKTOP_FILE_PID":8,"GJS_DEBUG_OUTPUT":8,"GJS_DEBUG_TOPICS":17,"GNOME_DESKTOP_SESSION_ID":20,"GNOME_SETUP_DISPLAY":4,"GNOME_SHELL_SESSION_MODE":8,"GTK_MODULES":17,"HOME":13,"IM_CONFIG_PHASE":3,"INVOCATION_ID":34,"JOURNAL_STREAM":9,"LANG":13,"LOGNAME":5,"MANAGERPID":6,"MOZ_ENABLE_WAYLAND":3,"PATH":566,"PWD":37,"PYENV_DIR":37,"PYENV_HOOK_PATH":158,"PYENV_ROOT":21,"PYENV_SHELL":6,"PYENV_VERSION":8,"QT_ACCESSIBILITY":3,"QT_IM_MODULE":6,"SESSION_MANAGER":79,"SHELL":13,"SHLVL":3,"SSH_AGENT_LAUNCHER":15,"SSH_AUTH_SOCK":33,"SSL_CERT_DIR":24,"SSL_CERT_FILE":45,"SYSTEMD_EXEC_PID":6,"TERM":16,"TERM_PROGRAM":9,"TERM_PROGRAM_VERSION":26,"THREAD_SUBPROCS":3,"USER":5,"USERNAME":5,"WAYLAND_DISPLAY":11,"WEZTERM_CONFIG_DIR":31,"WEZTERM_CONFIG_FILE":44,"WEZTERM_EXECUTABLE":25,"WEZTERM_EXECUTABLE_DIR":12,"WEZTERM_PANE":4,"WEZTERM_UNIX_SOCKET":45,"XAUTHORITY":48,"XDG_CONFIG_DIRS":35,"XDG_CURRENT_DESKTOP":14,"XDG_DATA_DIRS":86,"XDG_MENU_PREFIX":8,"XDG_RUNTIME_DIR":19,"XDG_SESSION_CLASS":6,"XDG_SESSION_DESKTOP":8,"XDG_SESSION_TYPE":9,"XMODIFIERS":10,"XONSHRC":81,"XONSHRC_DIR":54,"XONSH_CAPTURE_ALWAYS":2,"XONSH_CONFIG_DIR":29,"XONSH_DATA_DIR":35,"XONSH_INTERACTIVE":3,"XONSH_LOGIN":3,"XONSH_VERSION":8,"__total__":3533},"locked":5,"sessionid":38,"ts":[18,18,41]}},
|
||||
"data": {"cmds": [{"cwd": "\/home\/user\/Documents\/code\/atuin", "inp": "echo hello world!\n", "rtn": 0, "ts": [1707193079.4782722, 1707193079.4829233]
|
||||
}
|
||||
, {"cwd": "\/home\/user\/Documents\/code\/atuin", "inp": "ls -l\n", "rtn": 0, "ts": [1707193081.7063284, 1707193081.727617]
|
||||
}
|
||||
]
|
||||
, "env": {"ATUIN_SESSION": "018d7ca2e953742e9826012f30115040", "BASH_COMPLETIONS": "\/usr\/share\/bash-completion\/bash_completion", "COLORTERM": "truecolor", "DBUS_SESSION_BUS_ADDRESS": "unix:path=\/run\/user\/1000\/bus", "DESKTOP_SESSION": "ubuntu", "DISPLAY": ":0", "GDMSESSION": "ubuntu", "GIO_LAUNCHED_DESKTOP_FILE": "\/usr\/share\/applications\/org.wezfurlong.wezterm.desktop", "GIO_LAUNCHED_DESKTOP_FILE_PID": "196859", "GJS_DEBUG_OUTPUT": "stderr", "GJS_DEBUG_TOPICS": "JS ERROR;JS LOG", "GNOME_DESKTOP_SESSION_ID": "this-is-deprecated", "GNOME_SETUP_DISPLAY": ":1", "GNOME_SHELL_SESSION_MODE": "ubuntu", "GTK_MODULES": "gail:atk-bridge", "HOME": "\/home\/user", "IM_CONFIG_PHASE": "1", "INVOCATION_ID": "4f121e7ad56c41a6b84aa3cbe1ad61fa", "JOURNAL_STREAM": "8:37187", "LANG": "en_US.UTF-8", "LOGNAME": "user", "MANAGERPID": "2118", "MOZ_ENABLE_WAYLAND": "1", "PATH": "\/home\/user\/.pyenv\/versions\/3.12.0\/bin:\/home\/user\/.pyenv\/libexec:\/home\/user\/.pyenv\/plugins\/python-build\/bin:\/home\/user\/.pyenv\/plugins\/pyenv-virtualenv\/bin:\/home\/user\/.pyenv\/plugins\/pyenv-update\/bin:\/home\/user\/.pyenv\/plugins\/pyenv-doctor\/bin:\/home\/user\/.cargo\/bin:\/home\/user\/.pyenv\/shims:\/home\/user\/.pyenv\/bin:\/home\/user\/bin:\/home\/user\/bin:\/usr\/local\/sbin:\/usr\/local\/bin:\/usr\/sbin:\/usr\/bin:\/sbin:\/bin:\/usr\/games:\/usr\/local\/games:\/snap\/bin:\/snap\/bin:\/home\/user\/.local\/share\/JetBrains\/Toolbox\/scripts", "PWD": "\/home\/user\/Documents\/code\/atuin", "PYENV_DIR": "\/home\/user\/Documents\/code\/atuin", "PYENV_HOOK_PATH": "\/home\/user\/.pyenv\/pyenv.d:\/usr\/local\/etc\/pyenv.d:\/etc\/pyenv.d:\/usr\/lib\/pyenv\/hooks:\/home\/user\/.pyenv\/plugins\/pyenv-virtualenv\/etc\/pyenv.d", "PYENV_ROOT": "\/home\/user\/.pyenv", "PYENV_SHELL": "bash", "PYENV_VERSION": "3.12.0", "QT_ACCESSIBILITY": "1", "QT_IM_MODULE": "ibus", "SESSION_MANAGER": "local\/box:@\/tmp\/.ICE-unix\/2452,unix\/box:\/tmp\/.ICE-unix\/2452", "SHELL": "\/bin\/bash", "SHLVL": "1", "SSH_AGENT_LAUNCHER": "gnome-keyring", "SSH_AUTH_SOCK": "\/run\/user\/1000\/keyring\/ssh", "SSL_CERT_DIR": "\/usr\/lib\/ssl\/certs", "SSL_CERT_FILE": "\/usr\/lib\/ssl\/certs\/ca-certificates.crt", "SYSTEMD_EXEC_PID": "2470", "TERM": "xterm-256color", "TERM_PROGRAM": "WezTerm", "TERM_PROGRAM_VERSION": "20240127-113634-bbcac864", "THREAD_SUBPROCS": "1", "USER": "user", "USERNAME": "user", "WAYLAND_DISPLAY": "wayland-0", "WEZTERM_CONFIG_DIR": "\/home\/user\/.config\/wezterm", "WEZTERM_CONFIG_FILE": "\/home\/user\/.config\/wezterm\/wezterm.lua", "WEZTERM_EXECUTABLE": "\/usr\/bin\/wezterm-gui", "WEZTERM_EXECUTABLE_DIR": "\/usr\/bin", "WEZTERM_PANE": "38", "WEZTERM_UNIX_SOCKET": "\/run\/user\/1000\/wezterm\/gui-sock-196859", "XAUTHORITY": "\/run\/user\/1000\/.mutter-Xwaylandauth.T986H2", "XDG_CONFIG_DIRS": "\/etc\/xdg\/xdg-ubuntu:\/etc\/xdg", "XDG_CURRENT_DESKTOP": "ubuntu:GNOME", "XDG_DATA_DIRS": "\/usr\/share\/ubuntu:\/usr\/local\/share\/:\/usr\/share\/:\/var\/lib\/snapd\/desktop", "XDG_MENU_PREFIX": "gnome-", "XDG_RUNTIME_DIR": "\/run\/user\/1000", "XDG_SESSION_CLASS": "user", "XDG_SESSION_DESKTOP": "ubuntu", "XDG_SESSION_TYPE": "wayland", "XMODIFIERS": "@im=ibus", "XONSHRC": "\/etc\/xonsh\/xonshrc:\/home\/user\/.config\/xonsh\/rc.xsh:\/home\/user\/.xonshrc", "XONSHRC_DIR": "\/etc\/xonsh\/rc.d:\/home\/user\/.config\/xonsh\/rc.d", "XONSH_CAPTURE_ALWAYS": "", "XONSH_CONFIG_DIR": "\/home\/user\/.config\/xonsh", "XONSH_DATA_DIR": "\/home\/user\/.local\/share\/xonsh", "XONSH_INTERACTIVE": "1", "XONSH_LOGIN": "1", "XONSH_VERSION": "0.14.2"}
|
||||
, "locked": false, "sessionid": "de16af90-9148-4461-8df3-5b5659c6420d", "ts": [1707193067.8615997, 1707193089.2513068]
|
||||
}
|
||||
|
||||
}
|
@ -9,8 +9,8 @@ use atuin_client::{
|
||||
database::Database,
|
||||
history::History,
|
||||
import::{
|
||||
bash::Bash, fish::Fish, nu::Nu, nu_histdb::NuHistDb, resh::Resh, zsh::Zsh,
|
||||
zsh_histdb::ZshHistDb, Importer, Loader,
|
||||
bash::Bash, fish::Fish, nu::Nu, nu_histdb::NuHistDb, resh::Resh, xonsh::Xonsh,
|
||||
xonsh_sqlite::XonshSqlite, zsh::Zsh, zsh_histdb::ZshHistDb, Importer, Loader,
|
||||
},
|
||||
};
|
||||
|
||||
@ -34,6 +34,10 @@ pub enum Cmd {
|
||||
Nu,
|
||||
/// Import history from the nu history file
|
||||
NuHistDb,
|
||||
/// Import history from xonsh json files
|
||||
Xonsh,
|
||||
/// Import history from xonsh sqlite db
|
||||
XonshSqlite,
|
||||
}
|
||||
|
||||
const BATCH_SIZE: usize = 100;
|
||||
@ -97,6 +101,8 @@ impl Cmd {
|
||||
Self::Fish => import::<Fish, DB>(db).await,
|
||||
Self::Nu => import::<Nu, DB>(db).await,
|
||||
Self::NuHistDb => import::<NuHistDb, DB>(db).await,
|
||||
Self::Xonsh => import::<Xonsh, DB>(db).await,
|
||||
Self::XonshSqlite => import::<XonshSqlite, DB>(db).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user