Merge pull request #2 from conradludgate/main

feat: use directories project data dir
This commit is contained in:
Ellie Huxtable 2020-10-05 19:25:34 +01:00 committed by GitHub
commit 46285309fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 90 additions and 55 deletions

10
Cargo.lock generated
View file

@ -121,6 +121,15 @@ dependencies = [
"lazy_static", "lazy_static",
] ]
[[package]]
name = "directories"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8fed639d60b58d0f53498ab13d26f621fd77569cc6edb031f4cc36a2ad9da0f"
dependencies = [
"dirs-sys",
]
[[package]] [[package]]
name = "dirs" name = "dirs"
version = "2.0.2" version = "2.0.2"
@ -438,6 +447,7 @@ name = "shync"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"chrono", "chrono",
"directories",
"eyre", "eyre",
"log", "log",
"pretty_env_logger", "pretty_env_logger",

View file

@ -14,3 +14,4 @@ eyre = "0.6.1"
shellexpand = "2.0.0" shellexpand = "2.0.0"
rusqlite = "0.24.0" rusqlite = "0.24.0"
structopt = "0.3.15" structopt = "0.3.15"
directories = "3.0.1"

View file

@ -1,12 +1,11 @@
use std::path::Path; use std::path::Path;
use eyre::Result; use eyre::Result;
use shellexpand;
use rusqlite::{params, Connection};
use rusqlite::NO_PARAMS; use rusqlite::NO_PARAMS;
use rusqlite::{params, Connection};
use super::history::History; use crate::History;
pub trait Database { pub trait Database {
fn save(&self, h: History) -> Result<()>; fn save(&self, h: History) -> Result<()>;
@ -19,23 +18,25 @@ pub struct SqliteDatabase {
conn: Connection, conn: Connection,
} }
impl SqliteDatabase{ impl SqliteDatabase {
pub fn new(path: &str) -> Result<SqliteDatabase> { pub fn new(path: impl AsRef<Path>) -> Result<SqliteDatabase> {
let path = shellexpand::full(path)?;
let path = path.as_ref(); let path = path.as_ref();
debug!("opening sqlite database at {:?}", path); debug!("opening sqlite database at {:?}", path);
let create = !Path::new(path).exists(); let create = !path.exists();
if create {
if let Some(dir) = path.parent() {
std::fs::create_dir_all(dir)?;
}
}
let conn = Connection::open(path)?; let conn = Connection::open(path)?;
if create { if create {
Self::setup_db(&conn)?; Self::setup_db(&conn)?;
} }
Ok(SqliteDatabase{ Ok(SqliteDatabase { conn })
conn: conn,
})
} }
fn setup_db(conn: &Connection) -> Result<()> { fn setup_db(conn: &Connection) -> Result<()> {
@ -65,7 +66,8 @@ impl Database for SqliteDatabase {
command, command,
cwd cwd
) values (?1, ?2, ?3)", ) values (?1, ?2, ?3)",
params![h.timestamp, h.command, h.cwd])?; params![h.timestamp, h.command, h.cwd],
)?;
Ok(()) Ok(())
} }
@ -73,7 +75,9 @@ impl Database for SqliteDatabase {
fn list(&self) -> Result<()> { fn list(&self) -> Result<()> {
debug!("listing history"); debug!("listing history");
let mut stmt = self.conn.prepare("SELECT timestamp, command, cwd FROM history")?; let mut stmt = self
.conn
.prepare("SELECT timestamp, command, cwd FROM history")?;
let history_iter = stmt.query_map(params![], |row| { let history_iter = stmt.query_map(params![], |row| {
Ok(History { Ok(History {
timestamp: row.get(0)?, timestamp: row.get(0)?,

View file

@ -8,11 +8,11 @@ pub struct History {
} }
impl History { impl History {
pub fn new(command: &str, cwd: &str) -> History { pub fn new(command: String, cwd: String) -> History {
History { History {
timestamp: chrono::Utc::now().timestamp_millis(), timestamp: chrono::Utc::now().timestamp_millis(),
command: command.to_string(), command,
cwd: cwd.to_string(), cwd,
} }
} }
} }

View file

@ -1,2 +1,2 @@
pub mod history;
pub mod database; pub mod database;
pub mod history;

View file

@ -1,45 +1,72 @@
use std::env; use std::env;
use std::path::PathBuf;
use directories::ProjectDirs;
use eyre::{eyre, Result};
use structopt::StructOpt; use structopt::StructOpt;
use eyre::Result;
#[macro_use] extern crate log; #[macro_use]
extern crate log;
use pretty_env_logger; use pretty_env_logger;
mod local; mod local;
use local::history::History;
use local::database::{Database, SqliteDatabase}; use local::database::{Database, SqliteDatabase};
use local::history::History;
#[derive(StructOpt)] #[derive(StructOpt)]
#[structopt( #[structopt(
author="Ellie Huxtable <e@elm.sh>", author = "Ellie Huxtable <e@elm.sh>",
version="0.1.0", version = "0.1.0",
about="Keep your shell history in sync" about = "Keep your shell history in sync"
)] )]
enum Shync { struct Shync {
#[structopt(long, parse(from_os_str), help = "db file path")]
db: Option<PathBuf>,
#[structopt(subcommand)]
shync: ShyncCmd,
}
#[derive(StructOpt)]
enum ShyncCmd {
#[structopt( #[structopt(
about="manipulate shell history", about="manipulate shell history",
aliases=&["h", "hi", "his", "hist", "histo", "histor"], aliases=&["h", "hi", "his", "hist", "histo", "histor"],
)] )]
History(HistoryCmd), History(HistoryCmd),
#[structopt( #[structopt(about = "import shell history from file")]
about="import shell history from file",
)]
Import, Import,
#[structopt( #[structopt(about = "start a shync server")]
about="start a shync server",
)]
Server, Server,
} }
impl Shync { impl Shync {
fn run(self, db: SqliteDatabase) -> Result<()> { fn run(self) -> Result<()> {
match self { let db_path = match self.db {
Shync::History(history) => history.run(db), Some(db_path) => {
_ => Ok(()) let path = db_path
.to_str()
.ok_or(eyre!("path {:?} was not valid UTF-8", db_path))?;
let path = shellexpand::full(path)?;
PathBuf::from(path.as_ref())
}
None => {
let project_dirs = ProjectDirs::from("bike", "ellie", "shync").ok_or(eyre!(
"could not determine db file location\nspecify one using the --db flag"
))?;
let root = project_dirs.data_dir();
root.join("history.db")
}
};
let db = SqliteDatabase::new(db_path)?;
match self.shync {
ShyncCmd::History(history) => history.run(db),
_ => Ok(()),
} }
} }
} }
@ -50,9 +77,7 @@ enum HistoryCmd {
about="add a new command to the history", about="add a new command to the history",
aliases=&["a", "ad"], aliases=&["a", "ad"],
)] )]
Add { Add { command: Vec<String> },
command: Vec<String>,
},
#[structopt( #[structopt(
about="list all items in history", about="list all items in history",
@ -64,14 +89,10 @@ enum HistoryCmd {
impl HistoryCmd { impl HistoryCmd {
fn run(self, db: SqliteDatabase) -> Result<()> { fn run(self, db: SqliteDatabase) -> Result<()> {
match self { match self {
HistoryCmd::Add{command: words} => { HistoryCmd::Add { command: words } => {
let command = words.join(" "); let command = words.join(" ");
let cwd = env::current_dir()?.display().to_string();
let cwd = env::current_dir()?; let h = History::new(command, cwd);
let h = History::new(
command.as_str(),
cwd.display().to_string().as_str(),
);
debug!("adding history: {:?}", h); debug!("adding history: {:?}", h);
db.save(h)?; db.save(h)?;
@ -79,7 +100,7 @@ impl HistoryCmd {
Ok(()) Ok(())
} }
HistoryCmd::List => db.list() HistoryCmd::List => db.list(),
} }
} }
} }
@ -87,6 +108,5 @@ impl HistoryCmd {
fn main() -> Result<()> { fn main() -> Result<()> {
pretty_env_logger::init(); pretty_env_logger::init();
let db = SqliteDatabase::new("~/.history.db")?; Shync::from_args().run()
Shync::from_args().run(db)
} }