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

View file

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

View file

@ -1,12 +1,11 @@
use std::path::Path;
use eyre::Result;
use shellexpand;
use rusqlite::{params, Connection};
use rusqlite::NO_PARAMS;
use rusqlite::{params, Connection};
use super::history::History;
use crate::History;
pub trait Database {
fn save(&self, h: History) -> Result<()>;
@ -19,23 +18,25 @@ pub struct SqliteDatabase {
conn: Connection,
}
impl SqliteDatabase{
pub fn new(path: &str) -> Result<SqliteDatabase> {
let path = shellexpand::full(path)?;
impl SqliteDatabase {
pub fn new(path: impl AsRef<Path>) -> Result<SqliteDatabase> {
let path = path.as_ref();
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)?;
if create {
Self::setup_db(&conn)?;
}
Ok(SqliteDatabase{
conn: conn,
})
Ok(SqliteDatabase { conn })
}
fn setup_db(conn: &Connection) -> Result<()> {
@ -43,11 +44,11 @@ impl SqliteDatabase{
conn.execute(
"create table if not exists history (
id integer primary key,
timestamp integer not null,
command text not null,
cwd text not null
)",
id integer primary key,
timestamp integer not null,
command text not null,
cwd text not null
)",
NO_PARAMS,
)?;
@ -64,8 +65,9 @@ impl Database for SqliteDatabase {
timestamp,
command,
cwd
) values (?1, ?2, ?3)",
params![h.timestamp, h.command, h.cwd])?;
) values (?1, ?2, ?3)",
params![h.timestamp, h.command, h.cwd],
)?;
Ok(())
}
@ -73,7 +75,9 @@ impl Database for SqliteDatabase {
fn list(&self) -> Result<()> {
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| {
Ok(History {
timestamp: row.get(0)?,

View file

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

View file

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

View file

@ -1,45 +1,72 @@
use std::env;
use std::path::PathBuf;
use directories::ProjectDirs;
use eyre::{eyre, Result};
use structopt::StructOpt;
use eyre::Result;
#[macro_use] extern crate log;
#[macro_use]
extern crate log;
use pretty_env_logger;
mod local;
use local::history::History;
use local::database::{Database, SqliteDatabase};
use local::history::History;
#[derive(StructOpt)]
#[structopt(
author="Ellie Huxtable <e@elm.sh>",
version="0.1.0",
about="Keep your shell history in sync"
author = "Ellie Huxtable <e@elm.sh>",
version = "0.1.0",
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(
about="manipulate shell history",
aliases=&["h", "hi", "his", "hist", "histo", "histor"],
)]
History(HistoryCmd),
#[structopt(
about="import shell history from file",
)]
#[structopt(about = "import shell history from file")]
Import,
#[structopt(
about="start a shync server",
)]
#[structopt(about = "start a shync server")]
Server,
}
impl Shync {
fn run(self, db: SqliteDatabase) -> Result<()> {
match self {
Shync::History(history) => history.run(db),
_ => Ok(())
fn run(self) -> Result<()> {
let db_path = match self.db {
Some(db_path) => {
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",
aliases=&["a", "ad"],
)]
Add {
command: Vec<String>,
},
Add { command: Vec<String> },
#[structopt(
about="list all items in history",
@ -64,14 +89,10 @@ enum HistoryCmd {
impl HistoryCmd {
fn run(self, db: SqliteDatabase) -> Result<()> {
match self {
HistoryCmd::Add{command: words} => {
HistoryCmd::Add { command: words } => {
let command = words.join(" ");
let cwd = env::current_dir()?;
let h = History::new(
command.as_str(),
cwd.display().to_string().as_str(),
);
let cwd = env::current_dir()?.display().to_string();
let h = History::new(command, cwd);
debug!("adding history: {:?}", h);
db.save(h)?;
@ -79,7 +100,7 @@ impl HistoryCmd {
Ok(())
}
HistoryCmd::List => db.list()
HistoryCmd::List => db.list(),
}
}
}
@ -87,6 +108,5 @@ impl HistoryCmd {
fn main() -> Result<()> {
pretty_env_logger::init();
let db = SqliteDatabase::new("~/.history.db")?;
Shync::from_args().run(db)
Shync::from_args().run()
}