tidy some stuff (#6)

This commit is contained in:
Conrad Ludgate 2021-02-14 17:18:02 +00:00 committed by GitHub
parent 8af0034ae0
commit 72c5ea7914
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 119 additions and 143 deletions

View file

@ -34,7 +34,7 @@ pub enum Cmd {
}, },
} }
fn print_list(h: &Vec<History>) { fn print_list(h: &[History]) {
for i in h { for i in h {
println!("{}", i.command); println!("{}", i.command);
} }
@ -60,7 +60,7 @@ impl Cmd {
// print the ID // print the ID
// we use this as the key for calling end // we use this as the key for calling end
println!("{}", h.id); println!("{}", h.id);
db.save(h)?; db.save(&h)?;
Ok(()) Ok(())
} }
@ -69,7 +69,7 @@ impl Cmd {
h.exit = *exit; h.exit = *exit;
h.duration = chrono::Utc::now().timestamp_nanos() - h.timestamp; h.duration = chrono::Utc::now().timestamp_nanos() - h.timestamp;
db.update(h)?; db.update(&h)?;
Ok(()) Ok(())
} }

View file

@ -1,3 +1,23 @@
pub mod history; use structopt::StructOpt;
pub mod import;
pub mod server; mod history;
mod import;
mod server;
#[derive(StructOpt)]
pub enum AtuinCmd {
#[structopt(
about="manipulate shell history",
aliases=&["h", "hi", "his", "hist", "histo", "histor"],
)]
History(history::Cmd),
#[structopt(about = "import shell history from file")]
Import(import::Cmd),
#[structopt(about = "start an atuin server")]
Server(server::Cmd),
#[structopt(about = "generates a UUID")]
Uuid,
}

View file

@ -3,18 +3,18 @@ use std::path::Path;
use eyre::{eyre, Result}; use eyre::{eyre, Result};
use rusqlite::NO_PARAMS;
use rusqlite::{params, Connection}; use rusqlite::{params, Connection};
use rusqlite::{Transaction, NO_PARAMS};
use crate::History; use super::history::History;
pub trait Database { pub trait Database {
fn save(&mut self, h: History) -> Result<()>; fn save(&mut self, h: &History) -> Result<()>;
fn save_bulk(&mut self, h: &[History]) -> Result<()>; fn save_bulk(&mut self, h: &[History]) -> Result<()>;
fn load(&self, id: &str) -> Result<History>; fn load(&self, id: &str) -> Result<History>;
fn list(&self) -> Result<Vec<History>>; fn list(&self) -> Result<Vec<History>>;
fn since(&self, date: chrono::DateTime<Utc>) -> Result<Vec<History>>; fn since(&self, date: chrono::DateTime<Utc>) -> Result<Vec<History>>;
fn update(&self, h: History) -> Result<()>; fn update(&self, h: &History) -> Result<()>;
} }
// Intended for use on a developer machine and not a sync server. // Intended for use on a developer machine and not a sync server.
@ -65,22 +65,8 @@ impl Sqlite {
Ok(()) Ok(())
} }
}
impl Database for Sqlite { fn save_raw(tx: &Transaction, h: &History) -> Result<()> {
fn save(&mut self, h: History) -> Result<()> {
debug!("saving history to sqlite");
let v = vec![h];
self.save_bulk(&v)
}
fn save_bulk(&mut self, h: &[History]) -> Result<()> {
debug!("saving history to sqlite");
let tx = self.conn.transaction()?;
for i in h {
tx.execute( tx.execute(
"insert or ignore into history ( "insert or ignore into history (
id, id,
@ -93,18 +79,39 @@ impl Database for Sqlite {
hostname hostname
) values (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)", ) values (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)",
params![ params![
i.id, h.id,
i.timestamp, h.timestamp,
i.duration, h.duration,
i.exit, h.exit,
i.command, h.command,
i.cwd, h.cwd,
i.session, h.session,
i.hostname h.hostname
], ],
)?; )?;
Ok(())
}
} }
impl Database for Sqlite {
fn save(&mut self, h: &History) -> Result<()> {
debug!("saving history to sqlite");
let tx = self.conn.transaction()?;
Self::save_raw(&tx, h)?;
tx.commit()?;
Ok(())
}
fn save_bulk(&mut self, h: &[History]) -> Result<()> {
debug!("saving history to sqlite");
let tx = self.conn.transaction()?;
for i in h {
Self::save_raw(&tx, i)?
}
tx.commit()?; tx.commit()?;
Ok(()) Ok(())
@ -119,16 +126,7 @@ impl Database for Sqlite {
)?; )?;
let mut iter = stmt.query_map(params![id], |row| { let mut iter = stmt.query_map(params![id], |row| {
Ok(History { history_from_sqlite_row(Some(id.to_string()), row)
id: String::from(id),
timestamp: row.get(1)?,
duration: row.get(2)?,
exit: row.get(3)?,
command: row.get(4)?,
cwd: row.get(5)?,
session: row.get(6)?,
hostname: row.get(7)?,
})
})?; })?;
let history = iter.next().unwrap(); let history = iter.next().unwrap();
@ -139,7 +137,7 @@ impl Database for Sqlite {
} }
} }
fn update(&self, h: History) -> Result<()> { fn update(&self, h: &History) -> Result<()> {
debug!("updating sqlite history"); debug!("updating sqlite history");
self.conn.execute( self.conn.execute(
@ -159,32 +157,37 @@ impl Database for Sqlite {
.conn .conn
.prepare("SELECT * FROM history order by timestamp asc")?; .prepare("SELECT * FROM history order by timestamp asc")?;
let history_iter = stmt.query_map(params![], |row| { let history_iter = stmt.query_map(params![], |row| history_from_sqlite_row(None, row))?;
Ok(History {
id: row.get(0)?,
timestamp: row.get(1)?,
duration: row.get(2)?,
exit: row.get(3)?,
command: row.get(4)?,
cwd: row.get(5)?,
session: row.get(6)?,
hostname: row.get(7)?,
})
})?;
Ok(history_iter.filter_map(|x| x.ok()).collect()) Ok(history_iter.filter_map(Result::ok).collect())
} }
fn since(&self, date: chrono::DateTime<Utc>) -> Result<Vec<History>> { fn since(&self, date: chrono::DateTime<Utc>) -> Result<Vec<History>> {
debug!("listing history"); debug!("listing history since {:?}", date);
let mut stmt = self.conn.prepare( let mut stmt = self.conn.prepare(
"SELECT distinct command FROM history where timestamp > ?1 order by timestamp asc", "SELECT distinct command FROM history where timestamp > ?1 order by timestamp asc",
)?; )?;
let history_iter = stmt.query_map(params![date.timestamp_nanos()], |row| { let history_iter = stmt.query_map(params![date.timestamp_nanos()], |row| {
history_from_sqlite_row(None, row)
})?;
Ok(history_iter.filter_map(Result::ok).collect())
}
}
fn history_from_sqlite_row(
id: Option<String>,
row: &rusqlite::Row,
) -> Result<History, rusqlite::Error> {
let id = match id {
Some(id) => id,
None => row.get(0)?,
};
Ok(History { Ok(History {
id: row.get(0)?, id,
timestamp: row.get(1)?, timestamp: row.get(1)?,
duration: row.get(2)?, duration: row.get(2)?,
exit: row.get(3)?, exit: row.get(3)?,
@ -193,8 +196,4 @@ impl Database for Sqlite {
session: row.get(6)?, session: row.get(6)?,
hostname: row.get(7)?, hostname: row.get(7)?,
}) })
})?;
Ok(history_iter.filter_map(|x| x.ok()).collect())
}
} }

View file

@ -24,17 +24,11 @@ impl History {
session: Option<String>, session: Option<String>,
hostname: Option<String>, hostname: Option<String>,
) -> Self { ) -> Self {
// get the current session or just generate a random string let session = session.unwrap_or_else(|| {
let env_session = env::var("ATUIN_SESSION").unwrap_or_else(|_| Uuid::new_v4().to_simple().to_string())
env::var("ATUIN_SESSION").unwrap_or_else(|_| Uuid::new_v4().to_simple().to_string()); });
let hostname =
// best attempt at getting the current hostname, or just unknown hostname.unwrap_or_else(|| hostname::get().unwrap().to_str().unwrap().to_string());
let os_hostname = hostname::get().unwrap();
let os_hostname = os_hostname.to_str().unwrap();
let os_hostname = String::from(os_hostname);
let session = session.unwrap_or(env_session);
let hostname = hostname.unwrap_or(os_hostname);
Self { Self {
id: Uuid::new_v4().to_simple().to_string(), id: Uuid::new_v4().to_simple().to_string(),

View file

@ -1,8 +1,8 @@
// import old shell history! // import old shell history!
// automatically hoover up all that we can find // automatically hoover up all that we can find
use std::fs::File; use std::io::{BufRead, BufReader, Seek, SeekFrom};
use std::io::{BufRead, BufReader}; use std::{fs::File, path::Path};
use eyre::{eyre, Result}; use eyre::{eyre, Result};
@ -16,19 +16,18 @@ pub struct Zsh {
} }
// this could probably be sped up // this could probably be sped up
fn count_lines(path: &str) -> Result<usize> { fn count_lines(buf: &mut BufReader<File>) -> Result<usize> {
let file = File::open(path)?; let lines = buf.lines().count();
let buf = BufReader::new(file); buf.seek(SeekFrom::Start(0))?;
Ok(buf.lines().count()) Ok(lines)
} }
impl Zsh { impl Zsh {
pub fn new(path: &str) -> Result<Self> { pub fn new(path: impl AsRef<Path>) -> Result<Self> {
let loc = count_lines(path)?;
let file = File::open(path)?; let file = File::open(path)?;
let buf = BufReader::new(file); let mut buf = BufReader::new(file);
let loc = count_lines(&mut buf)?;
Ok(Self { Ok(Self {
file: buf, file: buf,
@ -37,43 +36,25 @@ impl Zsh {
} }
} }
fn trim_newline(s: &str) -> String {
let mut s = String::from(s);
if s.ends_with('\n') {
s.pop();
if s.ends_with('\r') {
s.pop();
}
}
s
}
fn parse_extended(line: &str) -> History { fn parse_extended(line: &str) -> History {
let line = line.replacen(": ", "", 2); let line = line.replacen(": ", "", 2);
let mut split = line.splitn(2, ':'); let (time, duration) = line.split_once(':').unwrap();
let (duration, command) = duration.split_once(';').unwrap();
let time = split.next().unwrap_or("-1"); let time = time.parse::<i64>().map_or_else(
let time = time |_| chrono::Utc::now().timestamp_nanos(),
.parse::<i64>() |t| t * 1_000_000_000,
.unwrap_or_else(|_| chrono::Utc::now().timestamp_nanos()); );
let duration_command = split.next().unwrap(); // might be 0;the command let duration = duration.parse::<i64>().map_or(-1, |t| t * 1_000_000_000);
let mut split = duration_command.split(';');
let duration = split.next().unwrap_or("-1"); // should just be the 0
let duration = duration.parse::<i64>().unwrap_or(-1);
let command = split.next().unwrap();
// use nanos, because why the hell not? we won't display them. // use nanos, because why the hell not? we won't display them.
History::new( History::new(
time * 1_000_000_000, time,
trim_newline(command), command.trim_end().to_string(),
String::from("unknown"), String::from("unknown"),
-1, -1,
duration * 1_000_000_000, duration,
None, None,
None, None,
) )
@ -101,7 +82,7 @@ impl Iterator for Zsh {
} else { } else {
Some(Ok(History::new( Some(Ok(History::new(
chrono::Utc::now().timestamp_nanos(), // what else? :/ chrono::Utc::now().timestamp_nanos(), // what else? :/
trim_newline(line.as_str()), line.trim_end().to_string(),
String::from("unknown"), String::from("unknown"),
-1, -1,
-1, -1,

View file

@ -1,3 +1,4 @@
#![feature(str_split_once)]
#![feature(proc_macro_hygiene)] #![feature(proc_macro_hygiene)]
#![feature(decl_macro)] #![feature(decl_macro)]
#![warn(clippy::pedantic, clippy::nursery)] #![warn(clippy::pedantic, clippy::nursery)]
@ -15,9 +16,8 @@ extern crate log;
#[macro_use] #[macro_use]
extern crate rocket; extern crate rocket;
use command::{history, import, server}; use command::AtuinCmd;
use local::database::Sqlite; use local::database::Sqlite;
use local::history::History;
mod command; mod command;
mod local; mod local;
@ -37,24 +37,6 @@ struct Atuin {
atuin: AtuinCmd, atuin: AtuinCmd,
} }
#[derive(StructOpt)]
enum AtuinCmd {
#[structopt(
about="manipulate shell history",
aliases=&["h", "hi", "his", "hist", "histo", "histor"],
)]
History(history::Cmd),
#[structopt(about = "import shell history from file")]
Import(import::Cmd),
#[structopt(about = "start an atuin server")]
Server(server::Cmd),
#[structopt(about = "generates a UUID")]
Uuid,
}
impl Atuin { impl Atuin {
fn run(self) -> Result<()> { fn run(self) -> Result<()> {
let db_path = if let Some(db_path) = self.db { let db_path = if let Some(db_path) = self.db {