From 30c1ffcecb541d9b27982df6af26948514cbadaa Mon Sep 17 00:00:00 2001 From: fxqnlr Date: Sun, 15 Jan 2023 16:58:45 +0100 Subject: started implementation of new input system --- src/main.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/main.rs') diff --git a/src/main.rs b/src/main.rs index 59d41c5..39e46e8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,17 @@ +use std::env; + use modlist::{config::Cfg, input::get_input}; #[tokio::main] async fn main() { let config = Cfg::init("modlist.toml").unwrap(); - match get_input(config).await { + let mut args: Vec = env::args().collect(); + args.reverse(); + args.pop(); + args.reverse(); + + match get_input(config, args).await { Ok(..) => (), Err(e) => { println!("{}", e); -- cgit v1.2.3 From f7a6d2e9c67c1fdf8fc17fa0461a201fd2720537 Mon Sep 17 00:00:00 2001 From: fxqnlr Date: Thu, 19 Jan 2023 18:37:42 +0100 Subject: input mostly inplemented, mods missing --- src/apis/modrinth.rs | 6 +-- src/commands/download.rs | 11 +++-- src/commands/io.rs | 30 ++++++------- src/commands/list.rs | 73 +++++++++--------------------- src/commands/mod.rs | 12 ++--- src/commands/update.rs | 18 +++++--- src/db.rs | 13 +++--- src/error.rs | 12 ++++- src/files.rs | 6 +-- src/input.rs | 115 +++++++++++++++++++++++++++-------------------- src/lib.rs | 6 +-- src/main.rs | 47 +++++++++++++++++-- 12 files changed, 194 insertions(+), 155 deletions(-) (limited to 'src/main.rs') diff --git a/src/apis/modrinth.rs b/src/apis/modrinth.rs index 78073e6..9890cf2 100644 --- a/src/apis/modrinth.rs +++ b/src/apis/modrinth.rs @@ -3,7 +3,7 @@ use chrono::{DateTime, FixedOffset}; use reqwest::Client; use serde::Deserialize; -use crate::{Modloader, List}; +use crate::{Modloader, List, error::{MLE, MLError, ErrorType}}; #[derive(Debug, Deserialize, Clone)] pub struct Project { @@ -177,9 +177,9 @@ pub async fn get_raw_versions(api: String, versions: Vec) -> Vec) -> Result> { +pub fn extract_current_version(versions: Vec) -> MLE { match versions.len() { - 0 => Err(Box::new(Error::new(ErrorKind::NotFound, "NO_VERSIONS_AVAILABLE"))), + 0 => Err(MLError::new(ErrorType::ModError, "NO_VERSIONS_AVAILABLE")), 1.. => { let mut times: Vec<(String, DateTime)> = vec![]; for ver in versions { diff --git a/src/commands/download.rs b/src/commands/download.rs index b958bf3..0f63876 100644 --- a/src/commands/download.rs +++ b/src/commands/download.rs @@ -1,7 +1,7 @@ -use crate::{files::{get_downloaded_versions, download_versions, delete_version, disable_version}, db::{userlist_get_all_current_versions_with_mods, lists_get_all_ids, lists_get}, modrinth::get_raw_versions}; +use crate::{files::{get_downloaded_versions, download_versions, delete_version, disable_version}, db::{userlist_get_all_current_versions_with_mods, lists_get_all_ids, lists_get}, modrinth::get_raw_versions, error::{MLE, ErrorType, MLError}}; use crate::{List, get_current_list, config::Cfg, input::Input}; -pub async fn download(config: Cfg, input: Input) -> Result<(), Box> { +pub async fn download(config: Cfg, input: Input) -> MLE<()> { let mut liststack: Vec = vec![]; if input.all_lists { @@ -18,7 +18,10 @@ pub async fn download(config: Cfg, input: Input) -> Result<(), Box Ok(i), + Err(e) => Err(MLError::new(ErrorType::DBError, e.to_string().as_str())), + }?; let mut to_download: Vec = vec![]; //(mod_id, version_id) @@ -33,7 +36,7 @@ pub async fn download(config: Cfg, input: Input) -> Result<(), Box Result> { + pub fn from(config: Cfg, list_id: String, download: bool) -> MLE { let list = lists_get(config.clone(), String::from(&list_id))?; @@ -32,26 +32,22 @@ impl ExportList { } } -pub async fn io(config: Cfg, input: Input) -> Result<(), Box> { +pub async fn io(config: Cfg, input: Input) -> MLE<()> { - match input.subcommand.clone().ok_or("INVALID_INPUT")? { - Subcmd::Export => { export(config, input)? }, - Subcmd::Import => { import(config, input.args).await? }, - _ => { }, + match input.clone().io_options.unwrap() { + IoOptions::Export => { export(config, input)? }, + IoOptions::Import => { import(config, input).await? }, } Ok(()) } -fn export(config: Cfg, input: Input) -> Result<(), Box> { +fn export(config: Cfg, input: Input) -> MLE<()> { let mut list_ids: Vec = vec![]; if input.all_lists { list_ids = lists_get_all_ids(config.clone())?; } else { - let args = input.args.ok_or("NO_ARGS")?; - for arg in args { - list_ids.push(lists_get(config.clone(), arg)?.id); - } + list_ids.push(lists_get(config.clone(), input.list.unwrap().id)?.id); } let mut lists: Vec = vec![]; for list_id in list_ids { @@ -68,10 +64,10 @@ fn export(config: Cfg, input: Input) -> Result<(), Box> { Ok(()) } -async fn import(config: Cfg, args: Option>) -> Result<(), Box> { +async fn import(config: Cfg, input: Input) -> MLE<()> { - let filestr: String = match args { - Some(args) => String::from(&args[0]), + let filestr: String = match input.file { + Some(args) => String::from(args), None => String::from(devdir(dirs::home_dir().unwrap().join("mlexport.toml").into_os_string().into_string().unwrap().as_str())), }; @@ -83,14 +79,14 @@ async fn import(config: Cfg, args: Option>) -> Result<(), Box = exportlist.mods.split("|").collect(); let mut mod_ids = vec![]; for mod_id in mods { mod_ids.push(String::from(mod_id)); }; - mod_add(config.clone(), mod_ids, list.clone(), false).await?; + //mod_add(config.clone(), mod_ids, list.clone(), false).await?; } Ok(()) } diff --git a/src/commands/list.rs b/src/commands/list.rs index 2fec1c7..bc58787 100644 --- a/src/commands/list.rs +++ b/src/commands/list.rs @@ -1,6 +1,4 @@ -use std::io::{Error, ErrorKind}; - -use crate::{db::{lists_insert, lists_remove, config_change_current_list, lists_get_all_ids, config_get_current_list, lists_get, lists_version}, Modloader, config::Cfg, input::{Input, ListOptions}, /*cmd_update,*/ error::{MLE, ErrorType, MLError}, /*modrinth::MCVersionType*/}; +use crate::{db::{lists_insert, lists_remove, config_change_current_list, config_get_current_list, lists_get}, Modloader, config::Cfg, input::{Input, ListOptions}, /*cmd_update,*/ error::MLE, /*modrinth::MCVersionType*/}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct List { @@ -9,78 +7,49 @@ pub struct List { pub modloader: Modloader, pub download_folder: String, } -/* -pub async fn list(config: Cfg, input: Input) -> Result<(), Box> { - match input.list_options.ok_or("")? { +pub async fn list(config: Cfg, input: Input) -> MLE<()> { + + match input.clone().list_options.unwrap() { ListOptions::Add => { - match add(config, input.args.ok_or("")?) { - Ok(..) => Ok(()), - Err(e) => Err(Box::new(e)) - } + add(config, input) }, ListOptions::Change => { - change(config, input.args) + change(config, input) }, ListOptions::Remove => { - match remove(config, input.args.ok_or("")?) { - Ok(..) => Ok(()), - Err(e) => Err(Box::new(e)) - } + remove(config, input) }, + /* Subcmd::Version => { match version(config, Some(input.args.ok_or("NO_VERSION")?), Some(MCVersionType::Release)).await { Ok(..) => Ok(()), Err(e) => Err(Box::new(e)) } - } - _ => { - Err(Box::new(Error::new(ErrorKind::InvalidInput, "WRONG_SUBCOMMAND"))) - } + }*/ } } -*/ + pub fn get_current_list(config: Cfg) -> MLE { let id = config_get_current_list(config.clone())?; lists_get(config, id) } -fn add(config: Cfg, args: Vec) -> MLE<()> { - match args.len() { - 1 | 2 | 3 => Err(MLError::new(ErrorType::ArgumentCountError, "TOO_FEW_ARGUMENTS")), - 4 => { - let id = String::from(&args[0]); - let mc_version = String::from(&args[1]); - let mod_loader = Modloader::from(&args[2])?; - let download_folder = String::from(&args[3]); - lists_insert(config, id, mc_version, mod_loader, download_folder) - }, - 5.. => Err(MLError::new(ErrorType::ArgumentCountError, "TOO_MANY_ARGUMENTS")), - _ => panic!("list arguments should never be zero or lower"), - } +fn add(config: Cfg, input: Input) -> MLE<()> { + let id = input.list_id.unwrap(); + let mc_version = input.list_mcversion.unwrap(); + let mod_loader = input.modloader.unwrap(); + let download_folder = input.directory.unwrap(); + lists_insert(config, id, mc_version, mod_loader, download_folder) } -fn change(config: Cfg, args: Option>) -> Result<(), Box> { - let lists = lists_get_all_ids(config.clone())?; - if args.is_none() { println!("Currently selected list: {}", get_current_list(config)?.id); return Ok(()) }; - let argsvec = args.ok_or("BAH")?; - match argsvec.len() { - 1 => { - let list = String::from(&argsvec[0]); - if !lists.contains(&list) { return Err(Box::new(Error::new(ErrorKind::NotFound, "LIST_DOESNT_EXIST"))); }; - config_change_current_list(config, list) - }, - 2.. => Err(Box::new(Error::new(ErrorKind::InvalidInput, "TOO_MANY_ARGUMENTS"))), - _ => panic!("list arguments should never lower than zero"), - } +fn change(config: Cfg, input: Input) -> MLE<()> { + //TODO reimplement current list + config_change_current_list(config, input.list.unwrap().id) } -fn remove(config: Cfg, args: Vec) -> MLE<()> { - match args.len() { - 1 => lists_remove(config, String::from(&args[0])), - 2.. => Err(MLError::new(ErrorType::ArgumentCountError, "TOO_MANY_ARGUMENTS")), - _ => panic!("list arguments should never be zero or lower"), - } +fn remove(config: Cfg, input: Input) -> MLE<()> { + lists_remove(config, input.list.unwrap().id) } /* diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 29fc600..527afc7 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,13 +1,13 @@ //pub mod modification; pub mod list; -//pub mod update; +pub mod update; //pub mod setup; -//pub mod download; -//pub mod io; +pub mod download; +pub mod io; //pub use modification::*; pub use list::*; -//pub use update::*; +pub use update::*; //pub use setup::*; -//pub use download::*; -//pub use io::*; +pub use download::*; +pub use io::*; diff --git a/src/commands/update.rs b/src/commands/update.rs index ca28130..068c3f3 100644 --- a/src/commands/update.rs +++ b/src/commands/update.rs @@ -1,5 +1,3 @@ -use std::io::{Error, ErrorKind}; - use crate::{config::Cfg, modrinth::{projects, Project, versions, extract_current_version, Version}, get_current_list, db::{userlist_get_all_ids, mods_get_versions, userlist_get_applicable_versions, userlist_change_versions, lists_get_all_ids, lists_get, userlist_get_current_version, mods_change_versions}, List, input::Input, files::{delete_version, download_versions, disable_version}, error::{MLE, MLError, ErrorType}}; pub async fn update(config: Cfg, input: Input) -> MLE<()> { @@ -93,7 +91,7 @@ pub async fn cmd_update(config: Cfg, liststack: Vec, clean: bool, direct_d Ok(()) } -async fn specific_update(config: Cfg, clean: bool, list: List, project: Project) -> Result> { +async fn specific_update(config: Cfg, clean: bool, list: List, project: Project) -> MLE { println!("Checking update for '{}' in {}", project.title, list.id); let applicable_versions = versions(String::from(&config.apis.modrinth), String::from(&project.id), list.clone()).await; @@ -114,14 +112,20 @@ async fn specific_update(config: Cfg, clean: bool, list: List, project: Project) //get new versions print!(" | getting new version"); let current_str = extract_current_version(applicable_versions.clone())?; - let current_ver = applicable_versions.into_iter().find(|ver| ver.id == current_str).ok_or("")?; + let current_ver = match applicable_versions.into_iter().find(|ver| ver.id == current_str).ok_or("!no current version in applicable_versions") { + Ok(v) => Ok(v), + Err(e) => Err(MLError::new(ErrorType::Other, e)), + }?; current.push(current_ver.clone()); - let link = current_ver.files.into_iter().find(|f| f.primary).ok_or("")?.url; - userlist_change_versions(config, list.id, current_str, versions.join("|"), link, project.id)?; + let link = match current_ver.files.into_iter().find(|f| f.primary).ok_or("!no primary in links") { + Ok(p) => Ok(p), + Err(e) => Err(MLError::new(ErrorType::Other, e)), + }?.url; + userlist_change_versions(config, list.id, current_str, versions.join("|"), link, project.id); } - if current.is_empty() { return Err(Box::new(Error::new(ErrorKind::NotFound, "NO_UPDATE_AVAILABLE"))) }; + if current.is_empty() { return Err(MLError::new(ErrorType::ModError, "NO_UPDATE_AVAILABLE")) }; println!(" | ✔️"); Ok(current[0].clone()) diff --git a/src/db.rs b/src/db.rs index 06c2459..119b2a5 100644 --- a/src/db.rs +++ b/src/db.rs @@ -177,7 +177,7 @@ pub fn userlist_get_all_ids(config: Cfg, list_id: String) -> MLE> { } -pub fn userlist_remove(config: Cfg, list_id: String, mod_id: String) -> Result<(), Box> { +pub fn userlist_remove(config: Cfg, list_id: String, mod_id: String) -> MLE<()> { let data = devdir(format!("{}/data.db", config.data).as_str()); let connection = Connection::open(data)?; @@ -186,7 +186,7 @@ pub fn userlist_remove(config: Cfg, list_id: String, mod_id: String) -> Result<( } -pub fn userlist_get_applicable_versions(config: Cfg, list_id: String, mod_id: String) -> Result> { +pub fn userlist_get_applicable_versions(config: Cfg, list_id: String, mod_id: String) -> MLE { let data = devdir(format!("{}/data.db", config.data).as_str()); let connection = Connection::open(data).unwrap(); @@ -201,12 +201,12 @@ pub fn userlist_get_applicable_versions(config: Cfg, list_id: String, mod_id: St }; match version.is_empty() { - true => Err(Box::new(Error::new(ErrorKind::NotFound, "MOD_NOT_FOUND"))), + true => Err(MLError::new(ErrorType::DBError, "MOD_NOT_FOUND")), false => Ok(version), } } -pub fn userlist_get_all_applicable_versions_with_mods(config: Cfg, list_id: String) -> Result, Box> { +pub fn userlist_get_all_applicable_versions_with_mods(config: Cfg, list_id: String) -> MLE> { let data = devdir(format!("{}/data.db", config.data).as_str()); let connection = Connection::open(data)?; @@ -221,7 +221,7 @@ pub fn userlist_get_all_applicable_versions_with_mods(config: Cfg, list_id: Stri versions.push((out[0].to_owned(), out[1].to_owned())); }; - if versions.is_empty() { return Err(Box::new(std::io::Error::new(ErrorKind::Other, "NO_MODS_ON_LIST"))); }; + if versions.is_empty() { return Err(MLError::new(ErrorType::DBError, "NO_MODS_ON_LIST")); }; Ok(versions) } @@ -349,6 +349,7 @@ pub fn userlist_get_all_downloads(config: Cfg, list_id: String) -> Result MLE<()> { println!("Creating list {}", id); @@ -420,7 +421,7 @@ pub fn lists_get_all_ids(config: Cfg) -> MLE> { } //config -pub fn config_change_current_list(config: Cfg, id: String) -> Result<(), Box> { +pub fn config_change_current_list(config: Cfg, id: String) -> MLE<()> { let data = devdir(format!("{}/data.db", config.data).as_str()); let connection = Connection::open(data)?; diff --git a/src/error.rs b/src/error.rs index dbe7224..a1f5f2e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -15,9 +15,11 @@ pub enum ErrorType { ArgumentCountError, ConfigError, DBError, + ModError, LibToml, LibSql, LibReq, + LibChrono, IoError, Other, } @@ -31,13 +33,15 @@ impl std::error::Error for MLError { impl fmt::Display for MLError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.etype { - ErrorType::ArgumentError => write!(f, "Wrong argument"), + ErrorType::ArgumentError => write!(f, "User input not accepted: {}", self.message), ErrorType::ArgumentCountError => write!(f, "Too many/too few arguments"), ErrorType::ConfigError => write!(f, "CONFIG"), ErrorType::DBError => write!(f, "DATABASE"), + ErrorType::ModError => write!(f, "Mod: {}", self.message), ErrorType::LibToml => write!(f, "TOML"), ErrorType::LibSql => write!(f, "SQL"), ErrorType::LibReq => write!(f, "REQWEST"), + ErrorType::LibChrono => write!(f, "Chrono error: {}", self.message), ErrorType::IoError => write!(f, "IO"), ErrorType::Other => write!(f, "OTHER") } @@ -68,6 +72,12 @@ impl From for MLError { } } +impl From for MLError { + fn from(error: chrono::ParseError) -> Self { + Self { etype: ErrorType::LibChrono, message: error.to_string() } + } +} + impl From for MLError { fn from(error: std::io::Error) -> Self { Self { etype: ErrorType::IoError, message: error.to_string() } diff --git a/src/files.rs b/src/files.rs index 998ed32..14e5636 100644 --- a/src/files.rs +++ b/src/files.rs @@ -85,12 +85,12 @@ pub fn get_file_path(list: List, versionid: String) -> MLE { Ok(filename.to_owned()) } -pub fn get_downloaded_versions(list: List) -> Result, Box> { +pub fn get_downloaded_versions(list: List) -> MLE> { let mut versions: HashMap = HashMap::new(); for file in read_dir(&list.download_folder)? { let path = file?.path(); - if path.is_file() && path.extension().ok_or("BAH")? == "jar" { - let pathstr = path.to_str().ok_or("BAH")?; + if path.is_file() && path.extension().ok_or("BAH").unwrap() == "jar" { + let pathstr = path.to_str().ok_or("BAH").unwrap(); let namesplit: Vec<&str> = pathstr.split('.').collect(); versions.insert(String::from(namesplit[namesplit.len() - 3]), String::from(namesplit[namesplit.len() - 2])); } diff --git a/src/input.rs b/src/input.rs index 4e59c50..be24660 100644 --- a/src/input.rs +++ b/src/input.rs @@ -7,6 +7,10 @@ pub struct Input { 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, @@ -24,6 +28,7 @@ pub enum Cmd { Update, Download, Io, + Version, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -59,6 +64,10 @@ impl Input { 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; @@ -71,7 +80,9 @@ impl Input { for arg in args { let arg_split: Vec<&str> = arg.trim().split(" ").collect(); match arg_split[0] { - "v" | "version" => { show_version(); }, + "v" | "version" => { + command = Some(Cmd::Version); + }, "d" | "download" => { command = Some(Cmd::Download); }, @@ -81,25 +92,39 @@ impl Input { "ma" => { command = Some(Cmd::Mod); mod_options = Some(ModOptions::Add); - if arg_split.len() != 1 { + 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() != 1 { + if arg_split.len() == 2 { mod_id = Some(String::from(arg_split[1])); } }, - "mv" => { - if arg_split.len() != 1 { - mod_version = Some(String::from(arg_split[1])); - }; - }, - "set-version" => { + "set_version" => { set_version = true; }, + "all_lists" => { + all_lists = true; + }, + "clean" => { + clean = true; + }, + "direct-download" => { + direct_download = true; + }, + "delete_old" => { + delete_old = true; + }, "l" => { list = Some(lists_get(config.clone(), String::from(arg_split[1]))?); } @@ -111,7 +136,10 @@ impl Input { "lr" => { command = Some(Cmd::List); list_options = Some(ListOptions::Remove); - list_id = Some(String::from(arg_split[1])); + if arg_split.len() == 2 { + list_id = Some(String::from(arg_split[1])); + list = Some(lists_get(config.clone(), list_id.clone().unwrap())?) + } }, "lc" => { command = Some(Cmd::List); @@ -138,7 +166,7 @@ impl Input { "f" => { file = Some(String::from(arg_split[1])); }, - _ => return Err(MLError::new(ErrorType::ArgumentError, "UnknownArgument")), + _ => return Err(MLError::new(ErrorType::ArgumentError, format!("Unknown Argument ({})", arg_split[0]).as_str())), } } @@ -148,6 +176,10 @@ impl Input { mod_id, mod_version, set_version, + all_lists, + clean, + direct_download, + delete_old, list, list_options, list_id, @@ -160,47 +192,32 @@ impl Input { } } -fn show_version() { - match std::env::var("DEV") { - Ok(dev) => { - let devint = dev.parse::().unwrap(); - if devint >= 1 { - println!("Modlist by FxQnLr v{} (DEV)", env!("CARGO_PKG_VERSION")); - } else { - println!("Modlist by FxQnLr v{}", env!("CARGO_PKG_VERSION")); - } - }, - Err(..) => println!("Modlist by FxQnLr v{}", env!("CARGO_PKG_VERSION")), - } - std::process::exit(0); -} - 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), - Cmd::Update => check_update(input), - Cmd::Download => check_download(input), - Cmd::Io => check_io(input), + _ => 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_ARGUMENT")); + 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, "MODS_NO_MODID_MODVERSION")); }; - if input.list_id.is_none() { println!("NOLIST"); input.list = Some(get_current_list(config.clone())?); }; + 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() && input.mod_version.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "MODS_NO_MODID_MODVERSION")); }; + if input.mod_id.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "MODS_NO_MODID")); }; Ok(input) }, } @@ -212,9 +229,13 @@ fn check_list(mut input: Input) -> MLE { }; match input.clone().list_options.unwrap() { ListOptions::Add => { - if input.list_id.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "LISTS_NO_ID")); }; - if input.list_mcversion.is_none() { /*TODO Get latest version */ input.list_mcversion = Some(String::from("1.19.3")) }; - if input.modloader.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "LISTS_NO_MODLOADER")); }; + 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) }, @@ -230,18 +251,6 @@ fn check_list(mut input: Input) -> MLE { } } -fn check_update(input: Input) -> MLE { - Ok(input) -} - -fn check_download(input: Input) -> MLE { - Ok(input) -} - -fn check_io(input: Input) -> MLE { - Ok(input) -} - #[test] fn input_from() { let config = Cfg::init("modlist.toml").unwrap(); @@ -253,6 +262,10 @@ fn input_from() { 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")), @@ -277,6 +290,10 @@ async fn get_input_test() { 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, diff --git a/src/lib.rs b/src/lib.rs index ef97a53..eb845d8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,14 @@ -//pub mod apis; +pub mod apis; pub mod config; pub mod commands; pub mod input; pub mod db; pub mod error; -//pub mod files; +pub mod files; use std::path::Path; -//pub use apis::*; +pub use apis::*; pub use commands::*; use error::{MLE, ErrorType, MLError}; diff --git a/src/main.rs b/src/main.rs index 39e46e8..10980fb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ -use std::env; +use std::{env, process}; -use modlist::{config::Cfg, input::get_input}; +use modlist::{config::Cfg, input::{get_input, Cmd}, update, download, list, io}; #[tokio::main] async fn main() { @@ -11,10 +11,49 @@ async fn main() { args.pop(); args.reverse(); - match get_input(config, args).await { - Ok(..) => (), + let input = match get_input(config.clone(), args).await { + Ok(i) => i, Err(e) => { println!("{}", e); + process::exit(1); } }; + + dbg!(&input); + + match input.clone().command.unwrap() { + Cmd::Mod => { + Ok(()) + }, + Cmd::List => { + list(config, input).await + }, + Cmd::Update => { + update(config, input).await + }, + Cmd::Download => { + download(config, input).await + }, + Cmd::Io => { + io(config, input).await + }, + Cmd::Version => { + show_version(); + Ok(()) + }, + }.unwrap() +} + +fn show_version() { + match std::env::var("DEV") { + Ok(dev) => { + let devint = dev.parse::().unwrap(); + if devint >= 1 { + println!("Modlist by FxQnLr v{} (DEV)", env!("CARGO_PKG_VERSION")); + } else { + println!("Modlist by FxQnLr v{}", env!("CARGO_PKG_VERSION")); + } + }, + Err(..) => println!("Modlist by FxQnLr v{}", env!("CARGO_PKG_VERSION")), + } } -- cgit v1.2.3 From 1890d59428dfcca861ea1b7820411d80cc60d713 Mon Sep 17 00:00:00 2001 From: fxqnlr Date: Sun, 22 Jan 2023 22:34:17 +0100 Subject: Added list version cmd, fixed some todos --- .gitignore | 1 + planmodlist.xopp | Bin 322225 -> 322154 bytes src/apis/modrinth.rs | 10 +++++-- src/commands/download.rs | 13 ++------- src/commands/list.rs | 30 +++++++++---------- src/commands/mod.rs | 4 +-- src/commands/modification.rs | 45 +++++++++++------------------ src/commands/setup.rs | 2 +- src/commands/update.rs | 67 ++++++++++++++++++++++--------------------- src/config.rs | 1 - src/db.rs | 26 ++++++++--------- src/error.rs | 2 +- src/files.rs | 29 +++++++++++++++---- src/input.rs | 46 ++++++++++++++++++++--------- src/main.rs | 2 +- 15 files changed, 151 insertions(+), 127 deletions(-) (limited to 'src/main.rs') diff --git a/.gitignore b/.gitignore index 693fb15..8713145 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ data.db.cp export.toml config.toml /dev +/.fleet \ No newline at end of file diff --git a/planmodlist.xopp b/planmodlist.xopp index e8920e0..aeb2fa7 100644 Binary files a/planmodlist.xopp and b/planmodlist.xopp differ diff --git a/src/apis/modrinth.rs b/src/apis/modrinth.rs index 9890cf2..36ab5df 100644 --- a/src/apis/modrinth.rs +++ b/src/apis/modrinth.rs @@ -1,4 +1,3 @@ -use std::io::{Error, ErrorKind}; use chrono::{DateTime, FixedOffset}; use reqwest::Client; use serde::Deserialize; @@ -142,7 +141,7 @@ pub async fn project(api: String, name: &str) -> Project { } pub async fn projects(api: String, ids: Vec) -> Vec { - println!("Getting versions for all mods from modrinth"); + println!("\tGet versions from modrinth\n"); let all = ids.join(r#"",""#); let url = format!(r#"projects?ids=["{}"]"#, all); @@ -188,7 +187,7 @@ pub fn extract_current_version(versions: Vec) -> MLE { } times.sort_by_key(|t| t.1); times.reverse(); - println!("Current Version: {}", times[0].0); + println!("\t └New current version: {}", times[0].0); Ok(times[0].0.to_string()) }, _ => panic!("available_versions should never be negative"), @@ -198,6 +197,7 @@ pub fn extract_current_version(versions: Vec) -> MLE { pub enum MCVersionType { Release, Latest, + Specific, } #[derive(Debug, Deserialize)] @@ -220,6 +220,10 @@ pub async fn get_minecraft_version(api: String, version: MCVersionType) -> Strin &mc_versions[i] }, MCVersionType::Latest => &mc_versions[0], + MCVersionType::Specific => { + println!("Not inplemented"); + &mc_versions[0] + } }; String::from(&ver.version) } diff --git a/src/commands/download.rs b/src/commands/download.rs index 0f63876..7748d15 100644 --- a/src/commands/download.rs +++ b/src/commands/download.rs @@ -1,4 +1,4 @@ -use crate::{files::{get_downloaded_versions, download_versions, delete_version, disable_version}, db::{userlist_get_all_current_versions_with_mods, lists_get_all_ids, lists_get}, modrinth::get_raw_versions, error::{MLE, ErrorType, MLError}}; +use crate::{files::{get_downloaded_versions, download_versions, delete_version, disable_version, clean_list_dir}, db::{userlist_get_all_current_versions_with_mods, lists_get_all_ids, lists_get}, modrinth::get_raw_versions, error::{MLE, ErrorType, MLError}}; use crate::{List, get_current_list, config::Cfg, input::Input}; pub async fn download(config: Cfg, input: Input) -> MLE<()> { @@ -44,17 +44,10 @@ pub async fn download(config: Cfg, input: Input) -> MLE<()> { } } - if input.clean { - let dl_path = ¤t_list.download_folder; - println!("Cleaning {}", dl_path); - for entry in std::fs::read_dir(dl_path)? { - let entry = entry?; - std::fs::remove_file(entry.path())?; - } - } + if input.clean { clean_list_dir(¤t_list)? }; if !to_download.is_empty() { - download_versions(current_list.clone(), get_raw_versions(String::from(&config.apis.modrinth), to_download).await).await?; + download_versions(current_list.clone(), config.clone(), get_raw_versions(String::from(&config.apis.modrinth), to_download).await).await?; } else { println!("There are no new versions to download"); } diff --git a/src/commands/list.rs b/src/commands/list.rs index bc58787..eaf6fa1 100644 --- a/src/commands/list.rs +++ b/src/commands/list.rs @@ -1,4 +1,4 @@ -use crate::{db::{lists_insert, lists_remove, config_change_current_list, config_get_current_list, lists_get}, Modloader, config::Cfg, input::{Input, ListOptions}, /*cmd_update,*/ error::MLE, /*modrinth::MCVersionType*/}; +use crate::{db::{lists_insert, lists_remove, config_change_current_list, config_get_current_list, lists_get, lists_version}, Modloader, config::Cfg, input::{Input, ListOptions}, cmd_update, error::MLE}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct List { @@ -20,13 +20,9 @@ pub async fn list(config: Cfg, input: Input) -> MLE<()> { ListOptions::Remove => { remove(config, input) }, - /* - Subcmd::Version => { - match version(config, Some(input.args.ok_or("NO_VERSION")?), Some(MCVersionType::Release)).await { - Ok(..) => Ok(()), - Err(e) => Err(Box::new(e)) - } - }*/ + ListOptions::Version => { + version(config, input).await + } } } @@ -44,7 +40,7 @@ fn add(config: Cfg, input: Input) -> MLE<()> { } fn change(config: Cfg, input: Input) -> MLE<()> { - //TODO reimplement current list + println!("Change default list to: {}", input.clone().list.unwrap().id); config_change_current_list(config, input.list.unwrap().id) } @@ -52,17 +48,19 @@ fn remove(config: Cfg, input: Input) -> MLE<()> { lists_remove(config, input.list.unwrap().id) } -/* ///Changing the current lists version and updating it /// #Arguments /// /// * `config` - The current config /// * `args` - All args, to extract the new version -async fn version(config: Cfg, args: Option>, version_type: Option) -> MLE<()> { - let current_list = lists_get(config.clone(), config_get_current_list(config.clone())?)?; +async fn version(config: Cfg, input: Input) -> MLE<()> { + println!("Change version for list {} to minecraft version: {}", input.clone().list.unwrap().id, input.clone().list_mcversion.unwrap()); - lists_version(config.clone(), String::from(¤t_list.id), String::from(&args.unwrap()[0]))?; - //update the list & with -- args - cmd_update(config, vec![current_list], true, true, false).await + lists_version(config.clone(), input.clone().list.ok_or("").unwrap().id, input.clone().list_mcversion.ok_or("").unwrap())?; + + //Linebreak readability + println!(""); + + println!("Check for updates for new minecraft version in list {}", input.clone().list.unwrap().id); + cmd_update(config, vec![input.list.ok_or("").unwrap()], true, input.direct_download, input.delete_old).await } -*/ diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 527afc7..38139f9 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,11 +1,11 @@ -//pub mod modification; +pub mod modification; pub mod list; pub mod update; //pub mod setup; pub mod download; pub mod io; -//pub use modification::*; +pub use modification::*; pub use list::*; pub use update::*; //pub use setup::*; diff --git a/src/commands/modification.rs b/src/commands/modification.rs index 7d4be8d..6a03b35 100644 --- a/src/commands/modification.rs +++ b/src/commands/modification.rs @@ -1,33 +1,24 @@ -use std::io::{Error, ErrorKind}; +use crate::{modrinth::{project, versions, extract_current_version, Version, projects}, config::Cfg, db::{mods_insert, userlist_remove, mods_get_id, userlist_insert, mods_get_all_ids, userlist_get_all_ids, userlist_get_current_version, lists_get_all_ids, mods_remove}, input::{Input, ModOptions}, files::{delete_version, download_versions}, List, error::{MLE, ErrorType, MLError}}; -use crate::{modrinth::{project, versions, extract_current_version, Version, projects}, config::Cfg, db::{mods_insert, userlist_remove, mods_get_id, userlist_insert, mods_get_all_ids, userlist_get_all_ids, userlist_get_current_version, lists_get_all_ids, mods_remove}, input::{Input, Subcmd}, get_current_list, files::{delete_version, download_versions}, List}; - -pub async fn modification(config: Cfg, input: Input) -> Result<(), Box> { - match input.subcommand.as_ref().ok_or("")? { - Subcmd::Add => { +pub async fn modification(config: Cfg, input: Input) -> MLE<()> { + match input.clone().mod_options.ok_or("").unwrap() { + ModOptions::Add => { add(config, input).await }, - Subcmd::Remove => { - remove(config, input.args.ok_or("")?) + ModOptions::Remove => { + remove(config, input) }, - _ => Err(Box::new(Error::new(ErrorKind::InvalidInput, "SUBCOMMAND_NOT_AVAILABLE"))) } } -async fn add(config: Cfg, input: Input) -> Result<(), Box> { - - let args = input.args.ok_or("")?; +async fn add(config: Cfg, input: Input) -> MLE<()> { - if args.is_empty() { return Err(Box::new(Error::new(ErrorKind::InvalidInput, "TOO_FEW_ARGUMENTS"))); }; - - let current_list = get_current_list(config.clone())?; - - mod_add(config, vec![String::from(&args[0])], current_list, input.disable_download).await?; + mod_add(config, vec![String::from(input.mod_id.unwrap())], input.list.unwrap(), input.direct_download).await?; Ok(()) } -pub async fn mod_add(config: Cfg, mod_id: Vec, list: List, disable_download: bool) -> Result<(), Box> { +pub async fn mod_add(config: Cfg, mod_id: Vec, list: List, disable_download: bool) -> MLE<()> { println!("Adding mod(s) {:?}", mod_id); let projects = if mod_id.len() == 1 { @@ -50,7 +41,7 @@ pub async fn mod_add(config: Cfg, mod_id: Vec, list: List, disable_downl current_version_id = current_version.clone().unwrap().id; - file = current_version.clone().ok_or("VERSION_CORRUPTED")?.files.into_iter().find(|f| f.primary).unwrap().url; + file = current_version.clone().ok_or("").unwrap().files.into_iter().find(|f| f.primary).unwrap().url; for ver in available_versions { available_versions_vec.push(ver.id); @@ -67,7 +58,7 @@ pub async fn mod_add(config: Cfg, mod_id: Vec, list: List, disable_downl match userlist_get_all_ids(config.clone(), list.clone().id) { Ok(mods) => { if mods.contains(&project.id) { - return Err(Box::new(Error::new(ErrorKind::Other, "MOD_ALREADY_ON_LIST"))); } + return Err(MLError::new(ErrorType::ModError, "MOD_ALREADY_ON_LIST")); } else { userlist_insert(config.clone(), String::from(&list.id), String::from(&project.id), String::from(¤t_version_id), available_versions_vec, file)?; } @@ -88,24 +79,22 @@ pub async fn mod_add(config: Cfg, mod_id: Vec, list: List, disable_downl }, }; - if !disable_download && current_version.is_some() { download_versions(list.clone(), vec![current_version.unwrap()]).await?; }; + if !disable_download && current_version.is_some() { download_versions(list.clone(), config.clone(), vec![current_version.unwrap()]).await?; }; } Ok(()) } -fn remove(config: Cfg, args: Vec) -> Result<(), Box> { - if args.is_empty() { return Err(Box::new(Error::new(ErrorKind::InvalidInput, "TOO_FEW_ARGUMENTS"))); }; +fn remove(config: Cfg, input: Input) -> MLE<()> { - let current_list = get_current_list(config.clone())?; - let mod_id = mods_get_id(config.clone(), String::from(&args[0]))?; + let mod_id = mods_get_id(config.clone(), input.clone().mod_id.unwrap())?; - let version = userlist_get_current_version(config.clone(), String::from(¤t_list.id), String::from(&mod_id))?; + let version = userlist_get_current_version(config.clone(), input.clone().list.unwrap().id, String::from(&mod_id))?; //TODO implement remove from modlist if not in any other lists && config clean is true - userlist_remove(config.clone(), String::from(¤t_list.id), String::from(&mod_id))?; - delete_version(current_list, version)?; + userlist_remove(config.clone(), input.clone().list.unwrap().id, String::from(&mod_id))?; + delete_version(input.list.unwrap(), version)?; let list_ids = lists_get_all_ids(config.clone())?; diff --git a/src/commands/setup.rs b/src/commands/setup.rs index e4fa801..cc7472c 100644 --- a/src/commands/setup.rs +++ b/src/commands/setup.rs @@ -63,4 +63,4 @@ fn to_04(config: Cfg) -> Result<(), Box> { s_insert_column(config.clone(), list_id, String::from("disabled_versions"), String::from("TEXT"), Some(String::from("NONE")))?; } s_config_update_version(config, String::from("0.4")) -} +} \ No newline at end of file diff --git a/src/commands/update.rs b/src/commands/update.rs index 068c3f3..f8bdb82 100644 --- a/src/commands/update.rs +++ b/src/commands/update.rs @@ -1,7 +1,6 @@ -use crate::{config::Cfg, modrinth::{projects, Project, versions, extract_current_version, Version}, get_current_list, db::{userlist_get_all_ids, mods_get_versions, userlist_get_applicable_versions, userlist_change_versions, lists_get_all_ids, lists_get, userlist_get_current_version, mods_change_versions}, List, input::Input, files::{delete_version, download_versions, disable_version}, error::{MLE, MLError, ErrorType}}; +use crate::{config::Cfg, modrinth::{projects, Project, versions, extract_current_version, Version}, get_current_list, db::{userlist_get_all_ids, mods_get_versions, userlist_get_applicable_versions, userlist_change_versions, lists_get_all_ids, lists_get, userlist_get_current_version, mods_change_versions}, List, input::Input, files::{delete_version, download_versions, disable_version, clean_list_dir}, error::{MLE, MLError, ErrorType}}; pub async fn update(config: Cfg, input: Input) -> MLE<()> { - let mut liststack: Vec = vec![]; if input.all_lists { let list_ids = lists_get_all_ids(config.clone())?; @@ -10,10 +9,9 @@ pub async fn update(config: Cfg, input: Input) -> MLE<()> { } } else { let current = get_current_list(config.clone())?; - println!("Checking for updates of mods in {}", current.id); + println!("Check for updates of mods in list {}", current.id); liststack.push(current) } - cmd_update(config, liststack, input.clean, input.direct_download, input.delete_old).await } @@ -29,6 +27,7 @@ pub async fn cmd_update(config: Cfg, liststack: Vec, clean: bool, direct_d let mut projects = projects(String::from(&config.apis.modrinth), mods).await; projects.sort_by_key(|pro| pro.id.clone()); + println!("Comparing mod versions:"); let mut updatestack: Vec = vec![]; for (index, project) in projects.into_iter().enumerate() { //Get versions for project and check if they match up @@ -37,6 +36,8 @@ pub async fn cmd_update(config: Cfg, liststack: Vec, clean: bool, direct_d let v_id = ¤t_version.mod_id; if &p_id != v_id { return Err(MLError::new(ErrorType::Other, "SORTING_ERROR")) }; + println!("\t({}) Check for update", project.title); + //Getting current installed version for disable or delete let disable_version = userlist_get_current_version(config.clone(), String::from(¤t_list.id), String::from(&project.id))?; @@ -49,40 +50,44 @@ pub async fn cmd_update(config: Cfg, liststack: Vec, clean: bool, direct_d current_versions.push((disable_version, p_id)); ver }, - //TODO handle errors (only continue on "NO_UPDATE_AVAILABLE") - Err(..) => { - //Updating versions in modlist for no repeating version calls - mods_change_versions(config.clone(), version_db_string, project.id)?; - println!("({}) No new version found for the specified", project.title); + Err(e) => { + //Catch no update available + if e.to_string() == "Mod: NO_UPDATE_AVAILABLE" { + mods_change_versions(config.clone(), version_db_string, project.id)?; + println!("\t └No new version found for the specified minecraft version"); + } else { + return Err(e); + }; continue; }, }); } else { - println!("({}) No new version found", project.title); + println!("\t └No new version found"); }; }; + + //Linebreak readability + println!(""); - if clean { - let dl_path = ¤t_list.download_folder; - println!("Cleaning {}", dl_path); - for entry in std::fs::read_dir(dl_path)? { - let entry = entry?; - std::fs::remove_file(entry.path())?; - } - } + if clean { clean_list_dir(¤t_list)? }; + //Linebreak readability + println!(""); + if direct_download { - download_versions(current_list.clone(), updatestack).await?; + download_versions(current_list.clone(), config.clone(), updatestack).await?; //Disable old versions - for ver in current_versions { - if delete_old { - println!("Deleting version {} for mod {}", ver.0, ver.1); - delete_version(current_list.clone(), ver.0)?; - } else if ver.0 != "NONE" { - println!("Disabling version {} for mod {}", ver.0, ver.1); - disable_version(config.clone(), current_list.clone(), ver.0, ver.1)?; - }; + if !clean { + for ver in current_versions { + if delete_old { + println!("Deleting version {} for mod {}", ver.0, ver.1); + delete_version(current_list.clone(), ver.0)?; + } else if ver.0 != "NONE" { + println!("Disabling version {} for mod {}", ver.0, ver.1); + disable_version(config.clone(), current_list.clone(), ver.0, ver.1)?; + }; + } } }; @@ -92,8 +97,6 @@ pub async fn cmd_update(config: Cfg, liststack: Vec, clean: bool, direct_d } async fn specific_update(config: Cfg, clean: bool, list: List, project: Project) -> MLE { - println!("Checking update for '{}' in {}", project.title, list.id); - let applicable_versions = versions(String::from(&config.apis.modrinth), String::from(&project.id), list.clone()).await; let mut versions: Vec = vec![]; @@ -110,7 +113,7 @@ async fn specific_update(config: Cfg, clean: bool, list: List, project: Project) let mut current: Vec = vec![]; if clean || (versions.join("|") != userlist_get_applicable_versions(config.clone(), String::from(&list.id), String::from(&project.id))?) { //get new versions - print!(" | getting new version"); + println!("\t └Get versions for specified minecraft versions"); let current_str = extract_current_version(applicable_versions.clone())?; let current_ver = match applicable_versions.into_iter().find(|ver| ver.id == current_str).ok_or("!no current version in applicable_versions") { Ok(v) => Ok(v), @@ -122,12 +125,12 @@ async fn specific_update(config: Cfg, clean: bool, list: List, project: Project) Ok(p) => Ok(p), Err(e) => Err(MLError::new(ErrorType::Other, e)), }?.url; - userlist_change_versions(config, list.id, current_str, versions.join("|"), link, project.id); + userlist_change_versions(config, list.id, current_str, versions.join("|"), link, project.id)?; } if current.is_empty() { return Err(MLError::new(ErrorType::ModError, "NO_UPDATE_AVAILABLE")) }; - println!(" | ✔️"); + //println!(" └✔️"); Ok(current[0].clone()) } diff --git a/src/config.rs b/src/config.rs index 383e7ee..ded0062 100644 --- a/src/config.rs +++ b/src/config.rs @@ -25,7 +25,6 @@ impl Cfg { if err.kind() == std::io::ErrorKind::NotFound { println!("No config file found, creating one"); let default_cfg = Cfg { data: String::from("./"), apis: Apis { modrinth: String::from("https://api.modrinth.com/v2/") } }; - //TODO Error let mut file = File::create(devdir(configfile.to_str().unwrap()))?; println!("Created config file"); file.write_all(&toml::to_string(&default_cfg)?.as_bytes())?; diff --git a/src/db.rs b/src/db.rs index 119b2a5..f47bda6 100644 --- a/src/db.rs +++ b/src/db.rs @@ -5,7 +5,7 @@ use rusqlite::Connection; use crate::{Modloader, config::Cfg, List, devdir, error::{MLE, MLError, ErrorType}}; //mods -pub fn mods_insert(config: Cfg, id: String, name: String, versions: Vec) -> Result<(), Box> { +pub fn mods_insert(config: Cfg, id: String, name: String, versions: Vec) -> MLE<()> { println!("Inserting mod {}({}) into database", name, id); @@ -41,7 +41,7 @@ pub fn mods_get_all_ids(config: Cfg) -> Result, Box Result> { +pub fn mods_get_id(config: Cfg, name: String) -> MLE { let data = devdir(format!("{}/data.db", config.data).as_str()); let connection = Connection::open(data)?; @@ -56,12 +56,12 @@ pub fn mods_get_id(config: Cfg, name: String) -> Result Err(Box::new(Error::new(ErrorKind::NotFound, "MOD_NOT_FOUND"))), + true => Err(MLError::new(ErrorType::DBError, "GI_MOD_NOT_FOUND")), false => Ok(mod_id), } } -pub fn mods_get_name(config: Cfg, id: String) -> Result> { +pub fn mods_get_name(config: Cfg, id: &str) -> MLE { let data = devdir(format!("{}/data.db", config.data).as_str()); let connection = Connection::open(data)?; @@ -76,14 +76,14 @@ pub fn mods_get_name(config: Cfg, id: String) -> Result Err(Box::new(Error::new(ErrorKind::NotFound, "MOD_NOT_FOUND"))), + true => Err(MLError::new(ErrorType::DBError, "GN_MOD_NOT_FOUND")), false => Ok(mod_name), } } pub fn mods_change_versions(config: Cfg, versions: String, mod_id: String) -> MLE<()> { - println!("Updating versions for {} with \n {}", mod_id, versions); + //println!("Updating versions for {} with \n {}", mod_id, versions); let data = devdir(format!("{}/data.db", config.data).as_str()); let connection = Connection::open(data)?; @@ -92,7 +92,7 @@ pub fn mods_change_versions(config: Cfg, versions: String, mod_id: String) -> ML Ok(()) } -pub fn mods_remove(config: Cfg, id: String) -> Result<(), Box> { +pub fn mods_remove(config: Cfg, id: String) -> MLE<()> { println!("Removing mod {} from database", id); @@ -131,7 +131,7 @@ pub fn mods_get_versions(config: Cfg, mods: Vec) -> MLE) -> MLE, current_link: String) -> Result<(), Box> { +pub fn userlist_insert(config: Cfg, list_id: String, mod_id: String, current_version: String, applicable_versions: Vec, current_link: String) -> MLE<()> { println!("Inserting {} into current list({})", mod_id, list_id); let data = devdir(format!("{}/data.db", config.data).as_str()); @@ -201,7 +201,7 @@ pub fn userlist_get_applicable_versions(config: Cfg, list_id: String, mod_id: St }; match version.is_empty() { - true => Err(MLError::new(ErrorType::DBError, "MOD_NOT_FOUND")), + true => Err(MLError::new(ErrorType::DBError, "GAV_MOD_NOT_FOUND")), false => Ok(version), } } @@ -241,7 +241,7 @@ pub fn userlist_get_current_version(config: Cfg, list_id: String, mod_id: String }; match version.is_empty() { - true => Err(MLError::new(ErrorType::DBError, "MOD_NOT_FOUND")), + true => Err(MLError::new(ErrorType::DBError, "GCV_MOD_NOT_FOUND")), false => Ok(version), } } @@ -285,7 +285,7 @@ pub fn userlist_get_all_current_versions_with_mods(config: Cfg, list_id: String) Ok(versions) } -pub fn userlist_change_versions(config: Cfg, list_id: String, current_version: String, versions: String, link: String, mod_id: String) -> Result<(), Box> { +pub fn userlist_change_versions(config: Cfg, list_id: String, current_version: String, versions: String, link: String, mod_id: String) -> MLE<()> { let data = devdir(format!("{}/data.db", config.data).as_str()); let connection = Connection::open(data)?; @@ -322,7 +322,7 @@ pub fn userlist_get_disabled_versions(config:Cfg, list_id: String, mod_id: Strin }; match version.is_empty() { - true => Err(MLError::new(ErrorType::DBError, "MOD_NOT_FOUND")), + true => Err(MLError::new(ErrorType::DBError, "GDV_MOD_NOT_FOUND")), false => Ok(version), } } diff --git a/src/error.rs b/src/error.rs index a1f5f2e..612a2e2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -36,7 +36,7 @@ impl fmt::Display for MLError { ErrorType::ArgumentError => write!(f, "User input not accepted: {}", self.message), ErrorType::ArgumentCountError => write!(f, "Too many/too few arguments"), ErrorType::ConfigError => write!(f, "CONFIG"), - ErrorType::DBError => write!(f, "DATABASE"), + ErrorType::DBError => write!(f, "Database: {}", self.message), ErrorType::ModError => write!(f, "Mod: {}", self.message), ErrorType::LibToml => write!(f, "TOML"), ErrorType::LibSql => write!(f, "SQL"), diff --git a/src/files.rs b/src/files.rs index 14e5636..0d7dc0a 100644 --- a/src/files.rs +++ b/src/files.rs @@ -2,13 +2,19 @@ use std::{fs::{File, read_dir, remove_file, rename}, io::Write, collections::Has use futures_util::StreamExt; use reqwest::Client; -use crate::{List, modrinth::Version, db::userlist_add_disabled_versions, config::Cfg, error::{MLE, MLError, ErrorType}}; +use crate::{List, modrinth::Version, db::{userlist_add_disabled_versions, mods_get_name}, config::Cfg, error::{MLE, MLError, ErrorType}}; -pub async fn download_versions(current_list: List, versions: Vec) -> MLE { +pub async fn download_versions(list: List, config: Cfg, versions: Vec) -> MLE { - let dl_path = String::from(¤t_list.download_folder); + let dl_path = String::from(&list.download_folder); + + println!("Download to directory from: {} ({})", list.id, dl_path); for ver in versions { + //TODO get project name instead of projectid from db + let project_name = mods_get_name(config.clone(), &ver.project_id)?; + print!("\t({})Download version {}", project_name, ver.id); + std::io::stdout().flush().unwrap(); let primary_file = ver.files.into_iter().find(|file| file.primary).unwrap(); let mut splitname: Vec<&str> = primary_file.filename.split('.').collect(); let extension = match splitname.pop().ok_or("") { @@ -16,14 +22,15 @@ pub async fn download_versions(current_list: List, versions: Vec) -> ML Err(..) => return Err(MLError::new(ErrorType::Other, "NO_FILE_EXTENSION")), }; let filename = format!("{}.mr.{}.{}.{}", splitname.join("."), ver.project_id, ver.id, extension); - download_file(primary_file.url, current_list.clone().download_folder, filename).await?; + download_file(primary_file.url, list.clone().download_folder, filename).await?; + tokio::time::sleep(std::time::Duration::new(3, 0)).await; + println!(" ✓"); } Ok(dl_path) } async fn download_file(url: String, path: String, name: String) -> MLE<()> { - println!("Downloading {}", url); let dl_path_file = format!("{}/{}", path, name); let res = Client::new() .get(String::from(&url)) @@ -43,7 +50,7 @@ async fn download_file(url: String, path: String, name: String) -> MLE<()> { } pub fn disable_version(config: Cfg, current_list: List, versionid: String, mod_id: String) -> MLE<()> { - println!("Disabling version {} for mod {}", versionid, mod_id); + //println!("Disabling version {} for mod {}", versionid, mod_id); let file = get_file_path(current_list.clone(), String::from(&versionid))?; let disabled = format!("{}.disabled", file); @@ -97,3 +104,13 @@ pub fn get_downloaded_versions(list: List) -> MLE> { } Ok(versions) } + +pub fn clean_list_dir(list: &List) -> MLE<()> { + let dl_path = &list.download_folder; + println!("Clean directory for: {}", list.id); + for entry in std::fs::read_dir(dl_path)? { + let entry = entry?; + std::fs::remove_file(entry.path())?; + }; + Ok(()) +} diff --git a/src/input.rs b/src/input.rs index be24660..a41f671 100644 --- a/src/input.rs +++ b/src/input.rs @@ -42,6 +42,7 @@ pub enum ListOptions { Add, Remove, Change, + Version, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -119,14 +120,18 @@ impl Input { "clean" => { clean = true; }, - "direct-download" => { - direct_download = true; + "no-download" => { + direct_download = false; }, "delete_old" => { delete_old = true; }, "l" => { - list = Some(lists_get(config.clone(), String::from(arg_split[1]))?); + 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); @@ -136,18 +141,26 @@ impl Input { "lr" => { command = Some(Cmd::List); list_options = Some(ListOptions::Remove); - if arg_split.len() == 2 { - list_id = Some(String::from(arg_split[1])); - list = Some(lists_get(config.clone(), list_id.clone().unwrap())?) - } }, "lc" => { command = Some(Cmd::List); list_options = Some(ListOptions::Change); - list_id = Some(String::from(arg_split[1])); }, "lv" => { - list_mcversion = Some(String::from(arg_split[1])); + 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])?); @@ -199,7 +212,7 @@ pub async fn get_input(config: Cfg, args: Vec) -> MLE { match input.clone().command.unwrap() { Cmd::Mod => check_mod(input, config), - Cmd::List => check_list(input), + Cmd::List => check_list(input, config), _ => Ok(input), } } @@ -223,7 +236,7 @@ fn check_mod(mut input: Input, config: Cfg) -> MLE { } } -fn check_list(mut input: Input) -> MLE { +fn check_list(mut input: Input, config: Cfg) -> MLE { if input.list_options.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "NO_LIST_ARGUMENT")); }; @@ -240,12 +253,19 @@ fn check_list(mut input: Input) -> MLE { Ok(input) }, ListOptions::Remove => { - if input.list_id.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "LISTS_NO_ID")); }; + 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_id.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "LISTS_NO_ID")); }; + 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) } } diff --git a/src/main.rs b/src/main.rs index 10980fb..2fca691 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,7 +19,7 @@ async fn main() { } }; - dbg!(&input); + //dbg!(&input); match input.clone().command.unwrap() { Cmd::Mod => { -- cgit v1.2.3 From 57ab6addda10a49c18dc09208dfb319c0205e869 Mon Sep 17 00:00:00 2001 From: fxqnlr Date: Thu, 26 Jan 2023 17:23:06 +0100 Subject: Todos; fixed input with "-" --- src/commands/modification.rs | 4 +++- src/commands/update.rs | 3 ++- src/files.rs | 1 - src/input.rs | 51 +++++++++++++++++++++++++++++--------------- src/main.rs | 4 ++-- 5 files changed, 41 insertions(+), 22 deletions(-) (limited to 'src/main.rs') diff --git a/src/commands/modification.rs b/src/commands/modification.rs index 6a03b35..c194202 100644 --- a/src/commands/modification.rs +++ b/src/commands/modification.rs @@ -20,6 +20,7 @@ async fn add(config: Cfg, input: Input) -> MLE<()> { pub async fn mod_add(config: Cfg, mod_id: Vec, list: List, disable_download: bool) -> MLE<()> { + //Fix printing (its horrible) println!("Adding mod(s) {:?}", mod_id); let projects = if mod_id.len() == 1 { vec![project(String::from(&config.apis.modrinth), &mod_id[0]).await] @@ -87,7 +88,8 @@ pub async fn mod_add(config: Cfg, mod_id: Vec, list: List, disable_downl } fn remove(config: Cfg, input: Input) -> MLE<()> { - + + //TODO inplement deletion by slug or title let mod_id = mods_get_id(config.clone(), input.clone().mod_id.unwrap())?; let version = userlist_get_current_version(config.clone(), input.clone().list.unwrap().id, String::from(&mod_id))?; diff --git a/src/commands/update.rs b/src/commands/update.rs index f8bdb82..f71f537 100644 --- a/src/commands/update.rs +++ b/src/commands/update.rs @@ -139,6 +139,7 @@ async fn download_updates_test() { use crate::{modrinth::{Version, VersionFile, Hash, VersionType}, Modloader, List}; + let config = Cfg::init("modlist.toml").unwrap(); let current_list = List { id: String::from("..."), mc_version: String::from("..."), modloader: Modloader::Forge, download_folder: String::from("./dl") }; let versions = vec![Version { @@ -171,5 +172,5 @@ async fn download_updates_test() { "fabric".to_string() ] }]; - assert!(download_versions(current_list, versions).await.is_ok()) + assert!(download_versions(current_list, config, versions).await.is_ok()) } diff --git a/src/files.rs b/src/files.rs index 0d7dc0a..ecb6e3e 100644 --- a/src/files.rs +++ b/src/files.rs @@ -11,7 +11,6 @@ pub async fn download_versions(list: List, config: Cfg, versions: Vec) println!("Download to directory from: {} ({})", list.id, dl_path); for ver in versions { - //TODO get project name instead of projectid from db let project_name = mods_get_name(config.clone(), &ver.project_id)?; print!("\t({})Download version {}", project_name, ver.id); std::io::stdout().flush().unwrap(); diff --git a/src/input.rs b/src/input.rs index a41f671..144f22a 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,4 +1,4 @@ -use crate::{error::{MLE, MLError, ErrorType}, Modloader, config::Cfg, db::lists_get, get_current_list, List}; +use crate::{error::{MLE, MLError, ErrorType}, Modloader, config::Cfg, db::lists_get, get_current_list, List, modrinth::{get_minecraft_version, MCVersionType}}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Input { @@ -54,10 +54,8 @@ pub enum IoOptions { 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 args: Vec<&str> = input_string.split(" -").collect(); + args[0] = args[0].split_at(1).1; let mut command: Option = None; @@ -95,6 +93,8 @@ impl Input { mod_options = Some(ModOptions::Add); if arg_split.len() == 2 { mod_id = Some(String::from(arg_split[1])); + } else { + return Err(MLError::new(ErrorType::ArgumentError, "Please specify a list mod slug or id")); } }, "mv" => { @@ -102,6 +102,8 @@ impl Input { mod_options = Some(ModOptions::Add); if arg_split.len() == 2 { mod_version = Some(String::from(arg_split[1])); + } else { + return Err(MLError::new(ErrorType::ArgumentError, "Please specify a version id")); }; }, "mr" => { @@ -109,7 +111,9 @@ impl Input { mod_options = Some(ModOptions::Remove); if arg_split.len() == 2 { mod_id = Some(String::from(arg_split[1])); - } + } else { + return Err(MLError::new(ErrorType::ArgumentError, "Please specify a mod id")); + }; }, "set_version" => { set_version = true; @@ -120,7 +124,7 @@ impl Input { "clean" => { clean = true; }, - "no-download" => { + "no_download" => { direct_download = false; }, "delete_old" => { @@ -136,7 +140,11 @@ impl Input { "la" => { command = Some(Cmd::List); list_options = Some(ListOptions::Add); - list_id = Some(String::from(arg_split[1])); + if arg_split.len() == 2 { + list_id = Some(String::from(arg_split[1])); + } else { + return Err(MLError::new(ErrorType::ArgumentError, "Please give the new list an id")); + } }, "lr" => { command = Some(Cmd::List); @@ -163,10 +171,18 @@ impl Input { } }, "ml" => { - modloader = Some(Modloader::from(arg_split[1])?); + if arg_split.len() == 2 { + modloader = Some(Modloader::from(arg_split[1])?); + } else { + return Err(MLError::new(ErrorType::ArgumentError, "Please specify a modloader")); + } }, "dir" => { - directory = Some(String::from(arg_split[1])); + if arg_split.len() == 2 { + directory = Some(String::from(arg_split[1])); + } else { + return Err(MLError::new(ErrorType::ArgumentError, "Please specify a directory")); + } }, "export" => { command = Some(Cmd::Io); @@ -212,18 +228,16 @@ pub async fn get_input(config: Cfg, args: Vec) -> MLE { match input.clone().command.unwrap() { Cmd::Mod => check_mod(input, config), - Cmd::List => check_list(input, config), + Cmd::List => check_list(input, config).await, _ => 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())?); }; @@ -236,7 +250,7 @@ fn check_mod(mut input: Input, config: Cfg) -> MLE { } } -fn check_list(mut input: Input, config: Cfg) -> MLE { +async fn check_list(mut input: Input, config: Cfg) -> MLE { if input.list_options.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "NO_LIST_ARGUMENT")); }; @@ -245,11 +259,14 @@ fn check_list(mut input: Input, config: Cfg) -> MLE { 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")); + input.list_mcversion = Some(get_minecraft_version(config.apis.modrinth, MCVersionType::Release).await); + }; + if input.directory.is_none() { + let id = input.clone().list_id.unwrap(); + println!("No download directory specified, defaulting to ./downloads/{}", id); + input.directory = Some(format!("./downloads/{}", id)) }; 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 => { diff --git a/src/main.rs b/src/main.rs index 2fca691..d177c3e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use std::{env, process}; -use modlist::{config::Cfg, input::{get_input, Cmd}, update, download, list, io}; +use modlist::{config::Cfg, input::{get_input, Cmd}, update, download, list, io, modification}; #[tokio::main] async fn main() { @@ -23,7 +23,7 @@ async fn main() { match input.clone().command.unwrap() { Cmd::Mod => { - Ok(()) + modification(config, input).await }, Cmd::List => { list(config, input).await -- cgit v1.2.3