From 613e1196b5e89d320283c4cea44a5d450616a932 Mon Sep 17 00:00:00 2001 From: Sam Tay Date: Mon, 8 Jun 2020 13:56:51 -0700 Subject: Implement --set-api-key --- TODO.md | 3 --- roadmap.md | 2 +- src/cli.rs | 31 +++++++++++++++++-------------- src/config.rs | 29 +++++++++++++++++------------ src/main.rs | 15 +++++---------- 5 files changed, 40 insertions(+), 40 deletions(-) diff --git a/TODO.md b/TODO.md index c993fe7..2d06bce 100644 --- a/TODO.md +++ b/TODO.md @@ -1,8 +1,5 @@ # TODO -### v0.1.1 -1. Touch up CLI and all that, finish all TODOs in cli.rs - ### v0.2.0 0. Termimad interface for viewing questions and answers 0. use [par_iter](https://github.com/rayon-rs/rayon) for parsing markdown and manual removers, etc. diff --git a/roadmap.md b/roadmap.md index 094bd2c..17da35a 100644 --- a/roadmap.md +++ b/roadmap.md @@ -8,7 +8,7 @@ ### v0.1.1 [x] Add xdga config -[ ] Finishing touches on cli opts like --set-api-key, etc. +[x] Finishing touches on cli opts like --set-api-key, etc. ### v0.2.0 [ ] Add --no-lucky option diff --git a/src/cli.rs b/src/cli.rs index 2bc4553..1f67edd 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -4,16 +4,12 @@ use crate::config; use crate::config::Config; use crate::error::Result; -// TODO maybe consts for these keywords? - -// TODO --set-api-key KEY -// TODO --update-sites -// TODO --install-filter-key --force // TODO --sites plural // TODO --add-site (in addition to defaults) pub struct Opts { pub list_sites: bool, pub update_sites: bool, + pub set_api_key: Option, pub query: Option, pub config: Config, } @@ -36,11 +32,18 @@ pub fn get_opts() -> Result { .long("update-sites") .help("Update cache of StackExchange sites"), ) + .arg( + Arg::with_name("set-api-key") + .long("set-api-key") + .number_of_values(1) + .takes_value(true) + .help("Set StackExchange API key"), + ) .arg( Arg::with_name("site") .long("site") .short("s") - .multiple(true) + .multiple(false) // TODO sites plural .number_of_values(1) .takes_value(true) .default_value(&config.site) @@ -67,27 +70,27 @@ pub fn get_opts() -> Result { Arg::with_name("query") .multiple(true) .index(1) - .required_unless_one(&["list-sites", "update-sites"]), + .required_unless_one(&["list-sites", "update-sites", "set-api-key"]), ) .get_matches(); Ok(Opts { list_sites: matches.is_present("list-sites"), update_sites: matches.is_present("update-sites"), + set_api_key: matches.value_of("set-api-key").map(String::from), query: matches .values_of("query") .map(|q| q.collect::>().join(" ")), config: Config { // these unwraps are safe via clap default values & validators limit: matches.value_of("limit").unwrap().parse::().unwrap(), - site: matches.value_of("site").unwrap().to_string(), - // TODO if set_api_key passed, pass it here too - ..config + site: matches.value_of("site").unwrap().to_string(), // TODO values_of + api_key: matches + .value_of("set-api-key") + .map(String::from) + .or(config.api_key), }, }) } -#[cfg(test)] -mod tests { - // TODO how can I test this now that it depends on user dir? -} +// TODO how can I test this App given https://users.rust-lang.org/t/help-with-idiomatic-rust-and-ownership-semantics/43880 diff --git a/src/config.rs b/src/config.rs index cb77086..0f09699 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,6 +2,7 @@ use directories::ProjectDirs; use serde::{Deserialize, Serialize}; use std::fs; use std::fs::File; +use std::path::PathBuf; use crate::error::{Error, Result}; @@ -27,18 +28,27 @@ pub fn user_config() -> Result { let project = project_dir()?; let dir = project.config_dir(); fs::create_dir_all(&dir).map_err(|_| Error::create_dir(&dir.to_path_buf()))?; - let filename = dir.join("config.yml"); + let filename = config_file_name()?; match File::open(&filename) { Err(_) => { - let file = File::create(&filename).map_err(|_| Error::create_file(&filename))?; let def = Config::default(); - serde_yaml::to_writer(file, &def).map_err(|_| Error::write_file(&filename))?; + write_config(&def)?; Ok(def) } Ok(file) => serde_yaml::from_reader(file).map_err(|_| Error::malformed(&filename)), } } +fn write_config(config: &Config) -> Result<()> { + let filename = config_file_name()?; + let file = File::create(&filename).map_err(|_| Error::create_file(&filename))?; + serde_yaml::to_writer(file, config).map_err(|_| Error::write_file(&filename)) +} + +fn config_file_name() -> Result { + Ok(project_dir()?.config_dir().join("config.yml")) +} + /// Get project directory pub fn project_dir() -> Result { ProjectDirs::from("io", "Sam Tay", "so").ok_or_else(|| { @@ -49,13 +59,8 @@ pub fn project_dir() -> Result { }) } -#[cfg(test)] -mod tests { - // TODO test malformed filter string - // TODO test malformed api key - // for both, detect situation and print helpful error message - #[test] - fn test_merge_configs() { - assert!(true) - } +pub fn set_api_key(key: String) -> Result<()> { + let mut cfg = user_config()?; + cfg.api_key = Some(key); + write_config(&cfg) } diff --git a/src/main.rs b/src/main.rs index 8ce16cc..57d561c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,10 @@ fn main() { let site = &config.site; let mut ls = LocalStorage::new()?; + if let Some(key) = opts.set_api_key { + config::set_api_key(key)?; + } + if opts.update_sites { ls.update_sites()?; } @@ -88,7 +92,7 @@ fn main() { this shouldn't be possible!", ) })?; - // TODO eventually do this in the right place, e.g. abstract out md parser & do within threads + // TODO eventually do this in the right place, e.g. abstract out md parser, write benches, & do within threads let md = ans.body.replace("", "**[").replace("", "]**"); skin.print_text(&md); } @@ -104,12 +108,3 @@ fn main() { println!("panic! {}", e.error); }); } - -#[cfg(test)] -mod tests { - - #[test] - fn test_main() { - //TODO - } -} -- cgit v1.2.3