From 8567dd04b03313a111dd29b8cad6c3f50bf36fdf Mon Sep 17 00:00:00 2001 From: scoobybejesus Date: Sun, 6 Oct 2019 14:04:38 -0400 Subject: [PATCH] Added CLI arg for indicating input file date separator character. Also cleaned up Cli struct. Takes care of one item from #48. --- src/core_functions.rs | 8 ++++++-- src/csv_import_accts_txns.rs | 10 +++++++--- src/main.rs | 34 +++++++++++++++++++++++++--------- src/skip_wizard.rs | 12 ++++++++++-- src/wizard.rs | 9 ++++++++- 5 files changed, 56 insertions(+), 17 deletions(-) diff --git a/src/core_functions.rs b/src/core_functions.rs index 7790d77..e258e25 100644 --- a/src/core_functions.rs +++ b/src/core_functions.rs @@ -52,6 +52,7 @@ pub struct ImportProcessParameters { pub enable_like_kind_treatment: bool, pub costing_method: InventoryCostingMethod, pub lk_cutoff_date_string: String, + pub date_separator: String, } pub(crate) fn import_and_process_final( @@ -62,7 +63,7 @@ pub(crate) fn import_and_process_final( HashMap, HashMap, HashMap, - Option + Option, ), Box> { let mut transactions_map: HashMap = HashMap::new(); @@ -76,7 +77,8 @@ pub(crate) fn import_and_process_final( &mut transactions_map, &mut action_records_map, &mut raw_account_map, - &mut account_map + &mut account_map, + &settings.date_separator, ) { Ok(()) => { println!("Successfully imported csv file."); } Err(err) => { @@ -93,6 +95,7 @@ pub(crate) fn import_and_process_final( action_records: &mut HashMap, raw_acct_map: &mut HashMap, acct_map: &mut HashMap, + date_separator: &str, ) -> Result<(), Box> { let file = File::open(import_file_path)?; println!("CSV ledger file opened successfully.\n"); @@ -107,6 +110,7 @@ pub(crate) fn import_and_process_final( &mut rdr, transactions_map, action_records, + date_separator, )?; Ok(()) diff --git a/src/csv_import_accts_txns.rs b/src/csv_import_accts_txns.rs index 5d57f46..4fcee9b 100644 --- a/src/csv_import_accts_txns.rs +++ b/src/csv_import_accts_txns.rs @@ -111,6 +111,7 @@ pub(crate) fn import_transactions( rdr: &mut csv::Reader, txns_map: &mut HashMap, action_records: &mut HashMap, + sep: &str, ) -> Result<(), Box> { let mut this_tx_number = 0; @@ -199,9 +200,12 @@ pub(crate) fn import_transactions( None => {} } - let tx_date = NaiveDate::parse_from_str(this_tx_date, "%m/%d/%y") - .unwrap_or(NaiveDate::parse_from_str(this_tx_date, "%m/%d/%Y") - .expect("%m/%d/%y (or %Y) format required for ledger import") + let format_yy: &str = &("%m".to_owned() + sep + &"%d" + sep + "%y"); + let format_yyyy: &str = &("%m".to_owned() + sep + &"%d" + sep + "%Y"); + + let tx_date = NaiveDate::parse_from_str(this_tx_date, format_yy) + .unwrap_or(NaiveDate::parse_from_str(this_tx_date, format_yyyy) + .expect("\nFailed to parse date in input file. Check date separator character. Also %m/%d/%y (or %Y) format is required.\n") ); let transaction = Transaction { diff --git a/src/main.rs b/src/main.rs index 960daf6..21a373d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,6 +33,9 @@ mod skip_wizard; #[structopt(name = "cryptools")] pub(crate) struct Cli { + #[structopt(flatten)] + flags: Flags, + /// File to be imported. (Currently, the only supported date format is %m/%d/%y.) #[structopt(name = "file", parse(from_os_str))] file_to_import: Option, @@ -41,16 +44,18 @@ pub(crate) struct Cli { #[structopt(name = "output directory", short, long = "output", default_value = ".", parse(from_os_str))] output_dir_path: PathBuf, - /// This will prevent the program from writing the CSV to file. This will be ignored if -a is not set (the wizard will always ask to output). - #[structopt(name = "suppress reports", short, long = "suppress")] - suppress_reports: bool, + /// Choose "h" or "s" for hyphen or slash (i.e., "-" or "/") to indicate the separator character used + /// in the input file txDate column (i.e. 2017/12/31 or 2017-12-31). + #[structopt(name = "date separator character", short, long = "date-separator", default_value = "h", parse(from_os_str))] + date_separator: OsString, /// Cutoff date through which like-kind exchange treatment should be applied. /// Please use %y-%m-%d (or %Y-%m-%d) format for like-kind cutoff date entry. - #[structopt(name = "like-kind cutoff date", short, long = "cutoff", parse(from_os_str))] - cutoff_date: Option, + #[structopt(name = "like-kind cutoff date", short, long = "lk-cutoff", parse(from_os_str))] + lk_cutoff_date: Option, - /// Inventory costing method (in terms of lot selection, i.e., LIFO, FIFO, etc.). There are currently four options (1 through 4). + /// Inventory costing method (in terms of lot selection, i.e., LIFO, FIFO, etc.). + /// There are currently four options (1 through 4). #[structopt(name = "method", short, long, default_value = "1", parse(from_os_str), long_help = r" 1. LIFO according to the order the lot was created. 2. LIFO according to the basis date of the lot. @@ -59,13 +64,24 @@ pub(crate) struct Cli { ")] inv_costing_method: OsString, - /// Home currency (currency in which all resulting reports are denominated). (Only available as a command line setting.) + /// Home currency (currency in which all resulting reports are denominated). + /// (Only available as a command line setting.) #[structopt(name = "home currency", short = "c", long = "currency", default_value = "USD", parse(from_os_str))] home_currency: OsString, +} - /// User is instructing the program to skip the data entry wizard. When set, program will error without required command-line args. +#[derive(StructOpt, Debug)] +pub(crate) struct Flags { + + /// User is instructing the program to skip the data entry wizard. + /// When set, program will error without required command-line args. #[structopt(name = "accept args", short, long = "accept")] accept_args: bool, + + /// This will prevent the program from writing reports to files. + /// This will be ignored if -a is not set (the wizard will always ask to output). + #[structopt(name = "suppress reports", short, long = "suppress")] + suppress_reports: bool, } @@ -92,7 +108,7 @@ fn main() -> Result<(), Box> { let like_kind_settings; let should_export; - if !args.accept_args { + if !args.flags.accept_args { let ( account_map1, diff --git a/src/skip_wizard.rs b/src/skip_wizard.rs index 5b9626a..7ea9eb5 100644 --- a/src/skip_wizard.rs +++ b/src/skip_wizard.rs @@ -3,6 +3,7 @@ use std::error::Error; use std::collections::{HashMap}; +use std::process; use crate::cli_user_choices; use crate::core_functions::{self, LikeKindSettings, ImportProcessParameters}; @@ -19,6 +20,12 @@ pub(crate) fn skip_wizard(args: super::Cli) -> Result<( bool ), Box> { + let date_separator = match args.date_separator.into_string().unwrap().as_str() { + "h" => {"-"} + "s" => {"/"} + _ => { println!("\nFATAL: The date-separator arg requires either an 'h' or an 's'.\n"); process::exit(1) } + }; + let input_file_path; if let Some(file) = args.file_to_import { @@ -37,7 +44,7 @@ pub(crate) fn skip_wizard(args: super::Cli) -> Result<( let like_kind_election; let like_kind_cutoff_date_string: String; - if let Some(date) = args.cutoff_date { + if let Some(date) = args.lk_cutoff_date { like_kind_election = true; like_kind_cutoff_date_string = date.into_string().unwrap(); } else { @@ -51,6 +58,7 @@ pub(crate) fn skip_wizard(args: super::Cli) -> Result<( costing_method: costing_method_choice, enable_like_kind_treatment: like_kind_election, lk_cutoff_date_string: like_kind_cutoff_date_string, + date_separator: date_separator.to_string(), }; let ( @@ -61,7 +69,7 @@ pub(crate) fn skip_wizard(args: super::Cli) -> Result<( like_kind_settings1 ) = core_functions::import_and_process_final(input_file_path, &settings)?; - let should_export = !args.suppress_reports; + let should_export = !args.flags.suppress_reports; Ok((account_map1, raw_acct_map1, action_records_map1, transactions_map1, like_kind_settings1, settings, should_export)) } \ No newline at end of file diff --git a/src/wizard.rs b/src/wizard.rs index bb73a8a..a2374ee 100644 --- a/src/wizard.rs +++ b/src/wizard.rs @@ -24,6 +24,12 @@ pub(crate) fn wizard(args: super::Cli) -> Result<( shall_we_proceed()?; + let date_separator = match args.date_separator.into_string().unwrap().as_str() { + "h" => {"-"} + "s" => {"/"} + _ => { println!("\nFATAL: The date-separator arg requires either an 'h' or an 's'.\n"); process::exit(1) } + }; + let input_file_path; if let Some(file) = args.file_to_import { @@ -40,7 +46,7 @@ pub(crate) fn wizard(args: super::Cli) -> Result<( let lk_cutoff_date_opt_string; - if let Some(lk_cutoff) = args.cutoff_date { + if let Some(lk_cutoff) = args.lk_cutoff_date { lk_cutoff_date_opt_string = Some(lk_cutoff.into_string().unwrap()) } else { lk_cutoff_date_opt_string = None @@ -54,6 +60,7 @@ pub(crate) fn wizard(args: super::Cli) -> Result<( costing_method: costing_method_choice, enable_like_kind_treatment: like_kind_election, lk_cutoff_date_string: like_kind_cutoff_date, + date_separator: date_separator.to_string(), }; let (