Fix merge
...I forgot to push. oops.
This commit is contained in:
commit
9917d6c1e2
6 changed files with 247 additions and 91 deletions
120
Cargo.lock
generated
120
Cargo.lock
generated
|
@ -127,6 +127,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"
|
||||||
|
@ -194,6 +203,15 @@ dependencies = [
|
||||||
"wasi 0.9.0+wasi-snapshot-preview1",
|
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-segmentation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.1.16"
|
version = "0.1.16"
|
||||||
|
@ -226,9 +244,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.78"
|
version = "0.2.79"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aa7087f49d294270db4e1928fc110c976cd4b9e5a16348e0a1df09afa99e6c98"
|
checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsqlite3-sys"
|
name = "libsqlite3-sys"
|
||||||
|
@ -312,12 +330,54 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[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]]
|
[[package]]
|
||||||
name = "quick-error"
|
name = "quick-error"
|
||||||
version = "1.2.3"
|
version = "1.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
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]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.1.57"
|
version = "0.1.57"
|
||||||
|
@ -394,12 +454,13 @@ name = "shync"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"directories",
|
||||||
"eyre",
|
"eyre",
|
||||||
"log",
|
"log",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
"shellexpand",
|
"shellexpand",
|
||||||
|
"structopt",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -414,6 +475,41 @@ version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
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]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -452,12 +548,24 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
version = "0.2.10"
|
version = "0.2.10"
|
||||||
|
@ -470,6 +578,12 @@ version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.9.0+wasi-snapshot-preview1"
|
version = "0.9.0+wasi-snapshot-preview1"
|
||||||
|
|
|
@ -11,10 +11,11 @@ description = "shync - sync your shell history"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pretty_env_logger = "0.4"
|
pretty_env_logger = "0.4"
|
||||||
clap = "2.33.3"
|
|
||||||
chrono = "0.4.19"
|
chrono = "0.4.19"
|
||||||
eyre = "0.6.1"
|
eyre = "0.6.1"
|
||||||
shellexpand = "2.0.0"
|
shellexpand = "2.0.0"
|
||||||
|
structopt = "0.3.15"
|
||||||
|
directories = "3.0.1"
|
||||||
|
|
||||||
[dependencies.rusqlite]
|
[dependencies.rusqlite]
|
||||||
version = "0.24.0"
|
version = "0.24.0"
|
||||||
|
|
|
@ -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)?,
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
pub mod history;
|
|
||||||
pub mod database;
|
pub mod database;
|
||||||
|
pub mod history;
|
||||||
|
|
145
src/main.rs
145
src/main.rs
|
@ -1,75 +1,112 @@
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use clap::{Arg, App, SubCommand};
|
use directories::ProjectDirs;
|
||||||
use eyre::Result;
|
use eyre::{eyre, Result};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
#[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;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
#[derive(StructOpt)]
|
||||||
pretty_env_logger::init();
|
#[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>,
|
||||||
|
|
||||||
let db = SqliteDatabase::new("~/.history.db")?;
|
#[structopt(subcommand)]
|
||||||
|
shync: ShyncCmd,
|
||||||
|
}
|
||||||
|
|
||||||
let matches = App::new("Shync")
|
#[derive(StructOpt)]
|
||||||
.version("0.1.0")
|
enum ShyncCmd {
|
||||||
.author("Ellie Huxtable <e@elm.sh>")
|
#[structopt(
|
||||||
.about("Keep your shell history in sync")
|
about="manipulate shell history",
|
||||||
.subcommand(
|
aliases=&["h", "hi", "his", "hist", "histo", "histor"],
|
||||||
SubCommand::with_name("history")
|
)]
|
||||||
.aliases(&["h", "hi", "his", "hist", "histo", "histor"])
|
History(HistoryCmd),
|
||||||
.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();
|
|
||||||
|
|
||||||
|
#[structopt(about = "import shell history from file")]
|
||||||
|
Import,
|
||||||
|
|
||||||
if let Some(m) = matches.subcommand_matches("history") {
|
#[structopt(about = "start a shync server")]
|
||||||
if let Some(m) = m.subcommand_matches("add") {
|
Server,
|
||||||
let words: Vec<&str> = m.values_of("command").unwrap().collect();
|
}
|
||||||
|
|
||||||
|
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)?;
|
||||||
|
|
||||||
|
match self.shync {
|
||||||
|
ShyncCmd::History(history) => history.run(db),
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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 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)?;
|
||||||
debug!("saved history to sqlite");
|
debug!("saved history to sqlite");
|
||||||
}
|
Ok(())
|
||||||
else if let Some(_m) = m.subcommand_matches("list") {
|
|
||||||
db.list()?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
HistoryCmd::List => db.list(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
pretty_env_logger::init();
|
||||||
|
|
||||||
|
Shync::from_args().run()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue