use crate::{error::{MLE, MLError, ErrorType}, Modloader, config::Cfg, db::lists_get, get_current_list, List}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Input { pub command: Option, pub mod_options: Option, pub mod_id: Option, pub mod_version: Option, pub set_version: bool, pub all_lists: bool, pub clean: bool, pub direct_download: bool, pub delete_old: bool, pub list: Option, pub list_options: Option, pub list_id: Option, pub list_mcversion: Option, pub modloader: Option, pub directory: Option, pub io_options: Option, pub file: Option, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum Cmd { Mod, List, Update, Download, Io, Version, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum ModOptions { Add, Remove } #[derive(Debug, Clone, PartialEq, Eq)] pub enum ListOptions { Add, Remove, Change, Version, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum IoOptions { Export, Import } impl Input { fn from(config: Cfg, input: Vec) -> MLE { let input_string = input.join(" "); let mut args: Vec<&str> = input_string.split('-').collect(); args.reverse(); args.pop(); args.reverse(); let mut command: Option = None; let mut mod_options: Option = None; let mut mod_id: Option = None; let mut mod_version: Option = None; let mut set_version = false; let mut all_lists = false; let mut clean = false; let mut direct_download = true; let mut delete_old = false; let mut list: Option = None; let mut list_options: Option = None; let mut list_id: Option = None; let mut list_mcversion: Option = None; let mut modloader: Option = None; let mut directory: Option = None; let mut io_options: Option = None; let mut file: Option = None; for arg in args { let arg_split: Vec<&str> = arg.trim().split(" ").collect(); match arg_split[0] { "v" | "version" => { command = Some(Cmd::Version); }, "d" | "download" => { command = Some(Cmd::Download); }, "u" | "update" => { command = Some(Cmd::Update); }, "ma" => { command = Some(Cmd::Mod); mod_options = Some(ModOptions::Add); if arg_split.len() == 2 { mod_id = Some(String::from(arg_split[1])); } }, "mv" => { command = Some(Cmd::Mod); mod_options = Some(ModOptions::Add); if arg_split.len() == 2 { mod_version = Some(String::from(arg_split[1])); }; }, "mr" => { command = Some(Cmd::Mod); mod_options = Some(ModOptions::Remove); if arg_split.len() == 2 { mod_id = Some(String::from(arg_split[1])); } }, "set_version" => { set_version = true; }, "all_lists" => { all_lists = true; }, "clean" => { clean = true; }, "no-download" => { direct_download = false; }, "delete_old" => { delete_old = true; }, "l" => { if arg_split.len() == 2 { list = Some(lists_get(config.clone(), String::from(arg_split[1]))?); } else { return Err(MLError::new(ErrorType::ArgumentError, "Please specify a list via it's id")); } } "la" => { command = Some(Cmd::List); list_options = Some(ListOptions::Add); list_id = Some(String::from(arg_split[1])); }, "lr" => { command = Some(Cmd::List); list_options = Some(ListOptions::Remove); }, "lc" => { command = Some(Cmd::List); list_options = Some(ListOptions::Change); }, "lv" => { command = Some(Cmd::List); list_options = Some(ListOptions::Version); if arg_split.len() == 2 { list_mcversion = Some(String::from(arg_split[1])); } else { return Err(MLError::new(ErrorType::ArgumentError, "Please specify a minecraft version")); } }, "mcv" => { if arg_split.len() == 2 { list_mcversion = Some(String::from(arg_split[1])); } else { return Err(MLError::new(ErrorType::ArgumentError, "Please specify a minecraft version")); } }, "ml" => { modloader = Some(Modloader::from(arg_split[1])?); }, "dir" => { directory = Some(String::from(arg_split[1])); }, "export" => { command = Some(Cmd::Io); io_options = Some(IoOptions::Export); }, "import" => { command = Some(Cmd::Io); io_options = Some(IoOptions::Import); }, "f" => { file = Some(String::from(arg_split[1])); }, _ => return Err(MLError::new(ErrorType::ArgumentError, format!("Unknown Argument ({})", arg_split[0]).as_str())), } } Ok(Self { command, mod_options, mod_id, mod_version, set_version, all_lists, clean, direct_download, delete_old, list, list_options, list_id, list_mcversion, modloader, directory, io_options, file }) } } pub async fn get_input(config: Cfg, args: Vec) -> MLE { let input = Input::from(config.clone(), args)?; if input.command.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "No command specified")); }; match input.clone().command.unwrap() { Cmd::Mod => check_mod(input, config), Cmd::List => check_list(input, config), _ => Ok(input), } } //Move checks to commands? translate to variables there? fn check_mod(mut input: Input, config: Cfg) -> MLE { if input.mod_options.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "No mod option")); }; match input.clone().mod_options.unwrap() { //Check for MV if no mod-id on both ModOptions::Add => { if input.mod_id.is_none() && input.mod_version.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "No mod id/slug or version id")); }; if input.list_id.is_none() { input.list = Some(get_current_list(config.clone())?); }; Ok(input) }, ModOptions::Remove => { if input.mod_id.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "MODS_NO_MODID")); }; Ok(input) }, } } fn check_list(mut input: Input, config: Cfg) -> MLE { if input.list_options.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "NO_LIST_ARGUMENT")); }; match input.clone().list_options.unwrap() { ListOptions::Add => { if input.list_id.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "no list id specified")); }; if input.list_mcversion.is_none() { println!("No Minecraft Version specified, defaulting to latest release"); //TODO Get latest version input.list_mcversion = Some(String::from("1.19.3")); }; if input.modloader.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "no modloader specified")); }; if input.directory.is_none() { input.directory = Some(format!("./downloads/{}", input.clone().list_id.expect("earlier if failed"))) }; Ok(input) }, ListOptions::Remove => { if input.list.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "NO_LIST_SPECIFIED")); }; Ok(input) }, ListOptions::Change => { //TODO check if no change if input.list.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "NO_LIST_SPECIFIED")); }; Ok(input) }, ListOptions::Version => { if input.list.is_none() { println!("No list specified, using default"); input.list = Some(get_current_list(config)?); }; Ok(input) } } } #[test] fn input_from() { let config = Cfg::init("modlist.toml").unwrap(); assert_eq!( Input::from(config.clone(), vec![String::from("-la test -lv 1.19.3")]).unwrap(), Input { command: Some(Cmd::List), mod_options: None, mod_id: None, mod_version: None, set_version: false, all_lists: false, clean: false, direct_download: false, delete_old: false, list: None, list_options: Some(ListOptions::Add), list_id: Some(String::from("test")), list_mcversion: Some(String::from("1.19.3")), modloader: None, directory: None, io_options: None, file: None } ); } #[tokio::test] async fn get_input_test() { let config = Cfg::init("modlist.toml").unwrap(); assert_eq!( get_input(config.clone(), vec![String::from("-ma test")]).await.unwrap(), Input { command: Some(Cmd::Mod), mod_options: Some(ModOptions::Add), mod_id: Some(String::from("test")), mod_version: None, set_version: false, all_lists: false, clean: false, direct_download: false, delete_old: false, list: Some(lists_get(config.clone(), String::from("one")).unwrap()), list_options: None, list_id: None, list_mcversion: None, modloader: None, directory: None, io_options: None, file: None } ) }