summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEllie Huxtable <e@elm.sh>2020-10-05 20:36:15 +0100
committerEllie Huxtable <e@elm.sh>2020-10-05 20:38:34 +0100
commit9917d6c1e2a743d5666247d8e87c9791721c213e (patch)
tree088df4af1041d53bd1faa38d5542200689be57a1
parent4783b77a6a5e9bb0156428bca1f8b765e1bb3357 (diff)
parent46285309fe7f0ccbc829555d402c6c446b69c1da (diff)
Fix merge
...I forgot to push. oops.
-rw-r--r--Cargo.lock120
-rw-r--r--Cargo.toml3
-rw-r--r--src/local/database.rs46
-rw-r--r--src/local/history.rs6
-rw-r--r--src/local/mod.rs2
-rw-r--r--src/main.rs157
6 files changed, 245 insertions, 89 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 6e8923b0..0cad5c25 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -128,6 +128,15 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -195,6 +204,15 @@ dependencies = [
]
[[package]]
+name = "heck"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
name = "hermit-abi"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -226,9 +244,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
-version = "0.2.78"
+version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa7087f49d294270db4e1928fc110c976cd4b9e5a16348e0a1df09afa99e6c98"
+checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743"
[[package]]
name = "libsqlite3-sys"
@@ -313,12 +331,54 @@ dependencies = [
]
[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
+name = "quote"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
name = "redox_syscall"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -394,12 +454,13 @@ name = "shync"
version = "0.1.1"
dependencies = [
"chrono",
- "clap",
+ "directories",
"eyre",
"log",
"pretty_env_logger",
"rusqlite",
"shellexpand",
+ "structopt",
]
[[package]]
@@ -415,6 +476,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
+name = "structopt"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a33f6461027d7f08a13715659b2948e1602c31a3756aeae9378bfe7518c72e82"
+dependencies = [
+ "clap",
+ "lazy_static",
+ "structopt-derive",
+]
+
+[[package]]
+name = "structopt-derive"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c92e775028122a4b3dd55d58f14fc5120289c69bee99df1d117ae30f84b225c9"
+dependencies = [
+ "heck",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c51d92969d209b54a98397e1b91c8ae82d8c87a7bb87df0b29aa2ad81454228"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
name = "termcolor"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -453,12 +549,24 @@ dependencies = [
]
[[package]]
+name = "unicode-segmentation"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
+
+[[package]]
name = "unicode-width"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]]
+name = "unicode-xid"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+
+[[package]]
name = "vcpkg"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -471,6 +579,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
+name = "version_check"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
+
+[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index c608ddeb..49850377 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,10 +11,11 @@ description = "shync - sync your shell history"
[dependencies]
log = "0.4"
pretty_env_logger = "0.4"
-clap = "2.33.3"
chrono = "0.4.19"
eyre = "0.6.1"
shellexpand = "2.0.0"
+structopt = "0.3.15"
+directories = "3.0.1"
[dependencies.rusqlite]
version = "0.24.0"
diff --git a/src/local/database.rs b/src/local/database.rs
index b84bf99c..b94a6445 100644
--- a/src/local/database.rs
+++ b/src/local/database.rs
@@ -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,
)?;
@@ -61,19 +62,22 @@ impl Database for SqliteDatabase {
self.conn.execute(
"insert into history (
- timestamp,
+ 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(())
}
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)?,
diff --git a/src/local/history.rs b/src/local/history.rs
index 61438b6d..e84d718c 100644
--- a/src/local/history.rs
+++ b/src/local/history.rs
@@ -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,
}
}
}
diff --git a/src/local/mod.rs b/src/local/mod.rs
index 8854aa8e..f587d016 100644
--- a/src/local/mod.rs
+++ b/src/local/mod.rs
@@ -1,2 +1,2 @@
-pub mod history;
pub mod database;
+pub mod history;
diff --git a/src/main.rs b/src/main.rs
index a9b08c00..2ec14a50 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,75 +1,112 @@
use std::env;
+use std::path::PathBuf;
-use clap::{Arg, App, SubCommand};
-use eyre::Result;
+use directories::ProjectDirs;
+use eyre::{eyre, Result};
+use structopt::StructOpt;
-#[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;
-fn main() -> Result<()> {
- pretty_env_logger::init();
+#[derive(StructOpt)]
+#[structopt(
+ author = "Ellie Huxtable <e@elm.sh>",
+ version = "0.1.0",
+ about = "Keep your shell history in sync"
+)]
+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")]
+ Import,
+
+ #[structopt(about = "start a shync server")]
+ Server,
+}
+
+impl Shync {
+ 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)?;
- let db = SqliteDatabase::new("~/.history.db")?;
-
- let matches = App::new("Shync")
- .version("0.1.0")
- .author("Ellie Huxtable <e@elm.sh>")
- .about("Keep your shell history in sync")
- .subcommand(
- SubCommand::with_name("history")
- .aliases(&["h", "hi", "his", "hist", "histo", "histor"])
- .about("manipulate shell history")
- .subcommand(
- SubCommand::with_name("add")
- .aliases(&["a", "ad"])
- .about("add a new command to the history")
- .arg(
- Arg::with_name("command")
- .multiple(true)
- .required(true)
- )
- )
- .subcommand(
- SubCommand::with_name("list")
- .aliases(&["l", "li", "lis"])
- .about("list all items in history")
- )
- )
- .subcommand(
- SubCommand::with_name("import")
- .about("import shell history from file")
- )
- .subcommand(
- SubCommand::with_name("server")
- .about("start a shync server")
- )
- .get_matches();
-
-
- if let Some(m) = matches.subcommand_matches("history") {
- if let Some(m) = m.subcommand_matches("add") {
- let words: Vec<&str> = m.values_of("command").unwrap().collect();
- let command = words.join(" ");
-
- let cwd = env::current_dir()?;
- let h = History::new(
- command.as_str(),
- cwd.display().to_string().as_str(),
- );
-
- debug!("adding history: {:?}", h);
- db.save(h)?;
- debug!("saved history to sqlite");
+ match self.shync {
+ ShyncCmd::History(history) => history.run(db),
+ _ => Ok(()),
}
- else if let Some(_m) = m.subcommand_matches("list") {
- db.list()?;
+ }
+}
+
+#[derive(StructOpt)]
+enum HistoryCmd {
+ #[structopt(
+ about="add a new command to the history",
+ aliases=&["a", "ad"],
+ )]
+ Add { command: Vec<String> },
+
+ #[structopt(
+ about="list all items in history",
+ aliases=&["l", "li", "lis"],
+ )]
+ List,
+}
+
+impl HistoryCmd {
+ fn run(self, db: SqliteDatabase) -> Result<()> {
+ match self {
+ HistoryCmd::Add { command: words } => {
+ let command = words.join(" ");
+ let cwd = env::current_dir()?.display().to_string();
+ let h = History::new(command, cwd);
+
+ debug!("adding history: {:?}", h);
+ db.save(h)?;
+ debug!("saved history to sqlite");
+ Ok(())
+ }
+
+ HistoryCmd::List => db.list(),
}
}
+}
+
+fn main() -> Result<()> {
+ pretty_env_logger::init();
- Ok(())
+ Shync::from_args().run()
}