improved file lookup, load by extension

This commit is contained in:
əlemi 2022-03-28 01:52:05 +02:00
parent 6023fcb296
commit 9af29da716
No known key found for this signature in database
GPG key ID: BBCBFE5D7244634E
3 changed files with 60 additions and 29 deletions

View file

@ -10,15 +10,15 @@ use git_version::git_version;
use notify_rust::Notification;
use regex::Regex;
use remote::RemoteSync;
use storage::{AuthStorage, Memo, MemoStorage, SQLiteStorage, StateStorage, JsonStorage};
use utils::{find_by_regex, parse_human_duration, HumanDisplay};
use storage::{AuthStorage, Memo, MemoError, MemoStorage, SQLiteStorage, StateStorage, JsonStorage, SUPPORTED_FORMATS};
use utils::{find_by_regex, find_db_file, parse_human_duration, HumanDisplay};
use std::path::PathBuf;
const GIT_VERSION: &str = git_version!();
const PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
const VERSION: &str = concatcp!(PKG_VERSION, "-", GIT_VERSION);
#[derive(Parser)]
#[derive(Parser, Clone)]
#[clap(author, about, long_about = None)]
#[clap(version = VERSION)]
#[clap(disable_colored_help = true)]
@ -27,19 +27,19 @@ const VERSION: &str = concatcp!(PKG_VERSION, "-", GIT_VERSION);
struct Cli {
#[clap(subcommand)]
command: Option<Commands>,
//#[clap(short, long, help = "name of db file")]
//name: Option<String>,
#[clap(short, long, help = "show memos in a notification")]
notify: bool,
#[clap(long, help = "show completed tasks")]
old: bool,
#[clap(short, long, help = "synchronize memo db")]
sync: bool,
#[clap(long, help = "name of db file, without extension")]
name: Option<String>,
#[clap(short, long, help = "specify location for database file")]
path: Option<String>,
}
#[derive(Subcommand)]
#[derive(Subcommand, Clone)]
enum Commands {
/// create a new memo
#[clap(trailing_var_arg = true)]
@ -69,34 +69,41 @@ enum Commands {
fn main() {
let args = Cli::parse();
let args2 = args.clone(); // TODO args is already partially moved so I can't pass it all to run_commands()
//might want to move the pathfinding to its own function
let mut db_path: PathBuf;
let filename = "memostorage.db"; //TODO: make this configurable
let filename = args.name.unwrap_or("memostorage".to_string());
if let Some(db) = args.path { //if we are given a starting path from command line, set it to that
if let Some(db) = args.path { // if we are given a specific path, just use that
db_path = PathBuf::from(db);
} else { //else use the current path, also should not browse up if path is specified
db_path = std::env::current_dir().unwrap();
db_path.push(filename); //check if file exists in current folder
while !db_path.exists() && !db_path.parent().is_none() {
db_path.pop().pop(); //browse parent folders until the given filename (or root) is found
db_path.push(filename); //we want to know about the db file, not the folder itself
}
if (!db_path.exists()) { //fallback to default
} else if let Some(path) = find_db_file(filename.as_str(), SUPPORTED_FORMATS) { // search up from cwd
db_path = path;
} else { // default path
//TODO: a less "nix-centered" default fallback, possibly configurable
//protip: cfg!(windows)/cfg!(unix)/cfg!(target_os = "macos") will give us the info we need
db_path = dirs::home_dir().unwrap();
db_path.push(".local/share/"); //default fallback path
}
db_path.push(format!("{}.{}", filename, "db")); // TODO hardcoded default sqlite
}
//TODO: permissions check, this will panic if it finds an existing db it can't write to
let mut storage = SQLiteStorage::new(db_path.to_str().unwrap(), true).unwrap();
if let Some(ext) = db_path.extension() {
match ext.to_str().unwrap() {
"json" => run_commands(JsonStorage::new(db_path).unwrap(), args2).unwrap(),
"db" => run_commands(SQLiteStorage::new(db_path, true).unwrap(), args2).unwrap(),
_ => println!("[!] unsupported database"),
}
} else {
println!("[!] no extension on db file");
}
}
fn run_commands<T>(mut storage: T, args: Cli) -> Result<(), MemoError>
where T : MemoStorage + AuthStorage + StateStorage + RemoteSync
{
if args.sync {
if storage.get_key().is_err() {
let key = rpassword::prompt_password("[$] new passphrase: ").unwrap();
@ -116,7 +123,7 @@ fn main() {
}
}
match args.command {
match &args.command {
Some(Commands::New { body, due }) => {
let mut due_date: Option<DateTime<Utc>> = None;
if let Some(d) = due {
@ -135,7 +142,7 @@ fn main() {
if let Some(re) = rex.ok() {
for memo in storage.all(false).unwrap() {
if re.is_match(memo.body.as_str()) {
if many {
if *many {
storage.del(&memo.id).unwrap();
println!("[-] done task : {}", memo.body);
} else if found {
@ -164,7 +171,7 @@ fn main() {
.unwrap();
if let Some(b) = body {
m.body = b;
m.body = b.to_owned();
}
if let Some(d) = due {
if d == "null" || d == "none" {
@ -211,7 +218,8 @@ fn main() {
.summary(format!("memo-cli | {}", timing).as_str())
.body(builder.as_str())
//.icon("") //soon...
.show();
.show()
.unwrap();
} else {
println!("{} | {}", "memo-cli".bold(), timing);
print!("{}", builder);
@ -239,4 +247,6 @@ fn main() {
);
}
}
Ok(())
}

View file

@ -5,12 +5,13 @@ pub use sqlite::SQLiteStorage;
pub use json::JsonStorage;
use chrono::{DateTime, Utc};
use std::error::Error;
use std::collections::LinkedList;
use std::fmt;
use uuid::Uuid;
use serde::{Serialize, Deserialize};
pub const SUPPORTED_FORMATS : &'static [&'static str] = &["db", "json"];
#[derive(Clone, Serialize, Deserialize)]
pub struct Memo {
pub id: Uuid,

View file

@ -3,6 +3,7 @@ use chrono::{Duration, Utc};
use regex::{Error, Regex};
use colored::Colorize;
use std::collections::LinkedList;
use std::path::PathBuf;
pub trait HumanDisplay {
fn human(&self) -> String;
@ -108,6 +109,25 @@ pub fn find_by_regex(re: Regex, memos: LinkedList<Memo>) -> Option<Memo> {
return out;
}
pub fn find_db_file(fname: &str, extensions: &[&str]) -> Option<PathBuf> {
let mut cwd = std::env::current_dir().unwrap(); // TODO handle not being able to get cwd?
let home_dir = dirs::home_dir().unwrap_or(PathBuf::new());
loop {
for ext in extensions {
cwd.push(format!("{}.{}", fname, ext));
if cwd.exists() { return Some(cwd); }
cwd.pop();
}
if cwd.parent().is_none() { break; }
if cwd == home_dir { break; }
cwd.pop();
}
return None;
}
// TODO is it possible to make this a method?
/* pub fn vec_to_str<T: std::fmt::Display>(arr: &Vec<T>) -> String {
let mut out = String::default();