use clap::builder::PossibleValue;
use clap::Parser;
use std::error::Error;
use std::path::PathBuf;
use tackler_api::txn_ts;
use tackler_api::txn_ts::GroupBy;
use tackler_core::config;
use tackler_core::kernel::settings::{FileInput, FsInput, GitInput, InputSettings};
use tackler_core::kernel::Settings;
use tackler_core::parser::GitInputSelector;
#[derive(Parser)]
#[command(author, version=env!("VERSION"), about, long_about = None)]
pub(crate) struct Cli {
#[arg(long = "config", value_name = "config file path")]
pub(crate) conf_path: PathBuf,
#[arg(long = "strict.mode", value_name = "true|false")]
pub(crate) strict_mode: Option<bool>,
#[arg(long = "audit.mode", value_name = "true|false")]
pub(crate) audit_mode: Option<bool>,
#[arg(
long = "output.dir",
value_name = "output directory for reports",
requires("output_name")
)]
pub(crate) output_directory: Option<PathBuf>,
#[arg(
long = "output.prefix",
value_name = "prefix of name for report files",
requires("output_directory")
)]
pub(crate) output_name: Option<String>,
#[arg(long="input.file",
value_name = "txn file path",
conflicts_with_all([
"input_storage",
"input_fs_dir",
"input_fs_ext",
"input_git_repo",
"input_git_ref",
"input_git_dir"])
)]
pub(crate) input_filename: Option<PathBuf>,
#[arg(long="input.storage",
value_name = "storage type",
value_parser([
PossibleValue::new(config::StorageType::STORAGE_FS),
PossibleValue::new(config::StorageType::STORAGE_GIT),
])
)]
pub(crate) input_storage: Option<String>,
#[arg(long="input.fs.dir",
value_name = "txn dir path",
requires("input_fs_ext"),
conflicts_with_all([
"input_git_repo",
"input_git_ref",
"input_git_dir"])
)]
pub(crate) input_fs_dir: Option<PathBuf>,
#[arg(
long = "input.fs.ext",
value_name = "txn file suffix",
requires("input_fs_dir")
)]
pub(crate) input_fs_ext: Option<String>,
#[arg(
long = "input.git.repository",
value_name = "git repository path",
requires("input_git_ref"),
requires("input_git_dir")
)]
pub(crate) input_git_repo: Option<PathBuf>,
#[arg(long = "input.git.ref", value_name = "git ref")]
pub(crate) input_git_ref: Option<String>,
#[arg(
long = "input.git.dir",
value_name = "git-path prefix",
requires("input_git_repo"),
requires("input_git_ref")
)]
pub(crate) input_git_dir: Option<String>,
#[arg(long = "accounts", value_name = "regex", num_args(1..))]
pub(crate) accounts: Option<Vec<String>>,
#[arg(long = "reports", value_name = "type", num_args(1..),
value_parser([
PossibleValue::new("register"),
PossibleValue::new("balance"),
PossibleValue::new("balance-group"),
])
)]
pub(crate) reports: Option<Vec<String>>,
#[arg(long = "group-by", value_name = "group-by", num_args(1),
value_parser([
PossibleValue::new(txn_ts::GroupBy::YEAR),
PossibleValue::new(txn_ts::GroupBy::MONTH),
PossibleValue::new(txn_ts::GroupBy::DATE),
PossibleValue::new(txn_ts::GroupBy::ISO_WEEK),
PossibleValue::new(txn_ts::GroupBy::ISO_WEEK_DATE),
])
)]
pub(crate) group_by: Option<GroupBy>,
#[arg(long = "exports", value_name = "type", num_args(1..),
value_parser([
PossibleValue::new("identity"),
PossibleValue::new("equity"),
])
)]
pub(crate) exports: Option<Vec<String>>,
#[arg(long = "api-filter-def", value_name = "filter def in json")]
pub(crate) api_filter_def: Option<String>,
}
impl Cli {
pub fn get_input_type(&self, settings: &Settings) -> Result<InputSettings, Box<dyn Error>> {
if let Some(filename) = &self.input_filename {
let i = FileInput {
path: filename.clone(),
};
Ok(InputSettings::File(i))
} else if self.input_fs_dir.is_some() {
let i = FsInput {
dir: self.input_fs_dir.clone().unwrap(),
suffix: self.input_fs_ext.clone().unwrap(),
};
Ok(InputSettings::Fs(i))
} else if self.input_git_repo.is_some() {
let i = GitInput {
repo: self.input_git_repo.clone().unwrap(),
git_ref: GitInputSelector::Reference(
self.input_git_ref.clone().unwrap(),
),
dir: self.input_git_dir.clone().unwrap().clone(),
ext: String::from("txn"),
};
Ok(InputSettings::Git(i))
} else if self.input_git_ref.is_some() && self.input_git_repo.is_none() {
let input_git_ref = self.input_git_ref.clone().unwrap();
match settings.get_input_settings(
Some(&config::StorageType::STORAGE_GIT.to_string()),
Some(self.conf_path.as_path()),
)? {
InputSettings::Git(git) => Ok(InputSettings::Git(GitInput {
git_ref: GitInputSelector::Reference(input_git_ref),
..git
})),
_ => {
let msg = "CLI Arg handling: Internal logic error";
Err(msg.into())
}
}
} else {
settings.get_input_settings(self.input_storage.as_ref(), Some(self.conf_path.as_path()))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn verify_cli() {
use clap::CommandFactory;
Cli::command().debug_assert()
}
}