From ff23a11e632812b685f594324e6004c6da81cd4d Mon Sep 17 00:00:00 2001 From: fxqnlr Date: Sun, 5 Feb 2023 09:23:29 +0100 Subject: Fixed update shit not correctly updating --- src/apis/modrinth.rs | 6 +-- src/commands/io.rs | 20 ++++----- src/commands/list.rs | 1 + src/commands/mod.rs | 4 +- src/commands/modification.rs | 73 ++++++++++++++++--------------- src/commands/setup.rs | 86 +++++++++++++++++++----------------- src/commands/update.rs | 90 +++++++++++++++++--------------------- src/db.rs | 101 ++++++++++++++++++++++++++++--------------- src/error.rs | 2 +- src/files.rs | 10 ++--- src/input.rs | 19 ++++---- src/main.rs | 14 ++++-- 12 files changed, 230 insertions(+), 196 deletions(-) (limited to 'src') diff --git a/src/apis/modrinth.rs b/src/apis/modrinth.rs index 36ab5df..f3f89a7 100644 --- a/src/apis/modrinth.rs +++ b/src/apis/modrinth.rs @@ -63,9 +63,7 @@ pub enum Type { pub enum Status { approved, rejected, - draft, - unlisted, - archived, + draft, unlisted, archived, processing, unknown } @@ -141,7 +139,6 @@ pub async fn project(api: String, name: &str) -> Project { } pub async fn projects(api: String, ids: Vec) -> Vec { - println!("\tGet versions from modrinth\n"); let all = ids.join(r#"",""#); let url = format!(r#"projects?ids=["{}"]"#, all); @@ -187,7 +184,6 @@ pub fn extract_current_version(versions: Vec) -> MLE { } times.sort_by_key(|t| t.1); times.reverse(); - println!("\t └New current version: {}", times[0].0); Ok(times[0].0.to_string()) }, _ => panic!("available_versions should never be negative"), diff --git a/src/commands/io.rs b/src/commands/io.rs index 4835e3d..44604d1 100644 --- a/src/commands/io.rs +++ b/src/commands/io.rs @@ -2,7 +2,7 @@ use std::fs::File; use std::io::prelude::*; use serde::{Serialize, Deserialize}; -use crate::{input::{Input, IoOptions}, db::{lists_get, userlist_get_all_ids, lists_get_all_ids, lists_insert}, config::Cfg, Modloader, /*mod_add,*/ List, devdir, error::MLE}; +use crate::{input::{Input, IoOptions}, db::{lists_get, userlist_get_all_ids, lists_get_all_ids, lists_insert}, config::Cfg, Modloader, List, devdir, error::MLE, mods_add}; #[derive(Debug, Serialize, Deserialize)] struct Export { @@ -24,7 +24,7 @@ impl ExportList { let list = lists_get(config.clone(), String::from(&list_id))?; let mut dl_folder = None; - if download == true { dl_folder = Some(list.download_folder) }; + if download{ dl_folder = Some(list.download_folder) }; let mods = userlist_get_all_ids(config, list_id)?.join("|"); @@ -51,7 +51,7 @@ fn export(config: Cfg, input: Input) -> MLE<()> { } let mut lists: Vec = vec![]; for list_id in list_ids { - lists.push(ExportList::from(config.clone(), String::from(list_id), true)?); + lists.push(ExportList::from(config.clone(), list_id, true)?); } let toml = toml::to_string( &Export { lists } )?; @@ -59,7 +59,7 @@ fn export(config: Cfg, input: Input) -> MLE<()> { let filestr = dirs::home_dir().unwrap().join("mlexport.toml"); let mut file = File::create(devdir(filestr.into_os_string().into_string().unwrap().as_str()))?; - file.write_all(&toml.as_bytes())?; + file.write_all(toml.as_bytes())?; Ok(()) } @@ -67,8 +67,8 @@ fn export(config: Cfg, input: Input) -> MLE<()> { async fn import(config: Cfg, input: Input) -> MLE<()> { 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())), + Some(args) => args, + None => devdir(dirs::home_dir().unwrap().join("mlexport.toml").into_os_string().into_string().unwrap().as_str()), }; let mut file = File::open(filestr)?; @@ -76,17 +76,17 @@ async fn import(config: Cfg, input: Input) -> MLE<()> { file.read_to_string(&mut content)?; let export: Export = toml::from_str(&content)?; - println!("{:#?}", export); - for exportlist in export.lists { let list = List { id: exportlist.id, mc_version: exportlist.mc_version, modloader: Modloader::from(&exportlist.launcher)?, download_folder: exportlist.download_folder.ok_or("NO_DL").unwrap() }; lists_insert(config.clone(), list.id.clone(), list.mc_version.clone(), list.modloader.clone(), String::from(&list.download_folder))?; - let mods: Vec<&str> = exportlist.mods.split("|").collect(); + let mods: Vec<&str> = 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?; + //TODO impl set_version and good direct download + //TODO impl all at once, dafuck + mods_add(config.clone(), mod_ids, list, input.direct_download, false).await?; } Ok(()) } diff --git a/src/commands/list.rs b/src/commands/list.rs index eaf6fa1..8e86973 100644 --- a/src/commands/list.rs +++ b/src/commands/list.rs @@ -49,6 +49,7 @@ fn remove(config: Cfg, input: Input) -> MLE<()> { } ///Changing the current lists version and updating it +/// /// #Arguments /// /// * `config` - The current config diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 38139f9..0d5bd00 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 setup; +pub mod setup; pub mod download; pub mod io; pub use modification::*; pub use list::*; pub use update::*; -//pub use setup::*; +pub use setup::*; pub use download::*; pub use io::*; diff --git a/src/commands/modification.rs b/src/commands/modification.rs index c82d6b5..12a635f 100644 --- a/src/commands/modification.rs +++ b/src/commands/modification.rs @@ -1,4 +1,9 @@ -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, 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}}; + +//TODO DO IT +pub struct ModVer { + +} pub async fn modification(config: Cfg, input: Input) -> MLE<()> { match input.clone().mod_options.ok_or("").unwrap() { @@ -13,22 +18,26 @@ pub async fn modification(config: Cfg, input: Input) -> MLE<()> { async fn add(config: Cfg, input: Input) -> MLE<()> { - mod_add(config, vec![String::from(input.mod_id.unwrap())], input.list.unwrap(), input.direct_download).await?; + mods_add(config, vec![input.mod_id.unwrap()], input.list.unwrap(), input.direct_download, input.set_version).await?; Ok(()) } - -pub async fn mod_add(config: Cfg, mod_id: Vec, list: List, direct_download: bool) -> MLE<()> { +//TODO impl specific version +pub async fn mods_add(config: Cfg, mod_id: Vec, list: List, direct_download: bool, set_version: bool) -> MLE<()> { - //Fix printing (its horrible) - println!("Adding mod(s) {:?}", mod_id); + println!("Add mods to {}", list.id); + println!(" └Add mods:"); let projects = if mod_id.len() == 1 { vec![project(String::from(&config.apis.modrinth), &mod_id[0]).await] } else { projects(String::from(&config.apis.modrinth), mod_id).await }; + + let mut downloadstack: Vec = Vec::new(); for project in projects { + println!("\t└{}", project.title); + println!("\t └Get versions"); let available_versions = versions(String::from(&config.apis.modrinth), String::from(&project.id), list.clone()).await; let mut available_versions_vec: Vec = Vec::new(); @@ -37,64 +46,56 @@ pub async fn mod_add(config: Cfg, mod_id: Vec, list: List, direct_downlo let file: String; if !available_versions.is_empty() { let current_id = extract_current_version(available_versions.clone())?; + println!("\t └Current version: {}", current_id); current_version = Some(available_versions.clone().into_iter().find(|v| v.id == current_id).unwrap()); current_version_id = current_version.clone().unwrap().id; 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); }; } else { - println!("There's currently no mod version for your specified target"); + println!("\t └There's currently no mod version for your specified target"); current_version = None; current_version_id = String::from("NONE"); file = String::from("NONE"); available_versions_vec.push(String::from("NONE")); } - //add to current list and mod table - match userlist_get_all_ids(config.clone(), list.clone().id) { - Ok(mods) => { - if mods.contains(&project.id) { - 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)?; - } + match userlist_insert(config.clone(), &list.id, &project.id, ¤t_version_id, available_versions_vec, &file, set_version) { + Err(e) => { + let expected_err = format!("SQL: UNIQUE constraint failed: {}.mod_id", list.id); + if e.to_string() == expected_err { Err(MLError::new(ErrorType::ModError, "MOD_ALREADY_ON_SELECTED_LIST")) } else { Err(e) } }, - Err(..) => userlist_insert(config.clone(), String::from(&list.id), String::from(&project.id), String::from(¤t_version_id), available_versions_vec, file)?, - }; + Ok(..) => { Ok(..) }, + }?; - match mods_get_all_ids(config.clone()) { - Ok(mods) => { - if mods.contains(&project.id) { - //return Err(Box::new(Error::new(ErrorKind::Other, "MOD_ALREADY_IN_DATABASE"))) - } else { - mods_insert(config.clone(), String::from(&project.id), String::from(&project.title), project.versions)?; - } - }, - Err(..) => { - mods_insert(config.clone(), String::from(&project.id), String::from(&project.title), project.versions)?; + match mods_insert(config.clone(), &project.id, &project.slug, &project.title) { + Err(e) => { + if e.to_string() == "SQL: UNIQUE constraint failed: mods.id" { Ok(..) } else { Err(e) } }, - }; + Ok(..) => Ok(..), + }?; - if direct_download && current_version.is_some() { download_versions(list.clone(), config.clone(), vec![current_version.unwrap()]).await?; }; - - } + downloadstack.push(current_version.unwrap()); + }; + + //Download all the added mods + if direct_download { + download_versions(list.clone(), config.clone(), downloadstack).await?; + }; Ok(()) } 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 mod_id = mods_get_id(&config.data, input.mod_id.as_ref().unwrap())?; 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(), input.clone().list.unwrap().id, String::from(&mod_id))?; delete_version(input.list.unwrap(), version)?; diff --git a/src/commands/setup.rs b/src/commands/setup.rs index cc7472c..0161bd7 100644 --- a/src/commands/setup.rs +++ b/src/commands/setup.rs @@ -1,66 +1,72 @@ -use std::{fs::File, path::Path, io::{Error, ErrorKind}}; +use std::{fs::File, path::Path}; -use crate::{config::Cfg, db::{db_setup, s_config_get_version, s_config_create_version, s_insert_column, lists_get_all_ids, lists_get, userlist_get_all_current_version_ids, s_userlist_update_download, s_config_update_version}, modrinth::get_raw_versions, devdir}; +use crate::{config::Cfg, db::db_setup, error::MLE, devdir}; -pub async fn setup(config: Cfg) -> Result<(), Box> { +pub async fn setup(config: Cfg) -> MLE<()> { let db_file = devdir(format!("{}/data.db", config.data).as_str()); if !Path::new(&db_file).exists() { - return create(config, db_file); + create(config, db_file)?; } + /* match s_config_get_version(config.clone()) { Ok(ver) => { match ver.as_str() { "0.2" => to_03(config)?, "0.3" => to_04(config)?, - _ => return Err(Box::new(Error::new(ErrorKind::Other, "UNKNOWN_VERSION"))) + _ => return Err(MLError::new(ErrorType::Other, "UNKNOWN_VERSION")) } }, Err(..) => to_02(config).await? }; + */ Ok(()) } -fn create(config: Cfg, db_file: String) -> Result<(), Box> { - File::create(db_file)?; - db_setup(config)?; - Ok(()) -} - -async fn to_02(config: Cfg) -> Result<(), Box> { - let lists = lists_get_all_ids(config.clone())?; - - for list in lists { - println!("Updating {}", list); - s_insert_column(config.clone(), String::from(&list), String::from("current_download"), String::from("TEXT"), None)?; - - let full_list = lists_get(config.clone(), String::from(&list))?; +fn create(config: Cfg, db_file: String) -> MLE<()> { - let versions = userlist_get_all_current_version_ids(config.clone(), full_list.clone().id)?; - - let raw_versions = get_raw_versions(String::from(&config.apis.modrinth), versions).await; - - for ver in raw_versions { - println!("Adding link for {}", ver.project_id); - let file = ver.files.into_iter().find(|f| f.primary).unwrap(); - s_userlist_update_download(config.clone(), String::from(&full_list.id), ver.project_id, file.url)?; - } - }; - s_config_create_version(config)?; + println!("Create database"); + File::create(db_file)?; + db_setup(config)?; Ok(()) } -fn to_03(config: Cfg) -> Result<(), Box> { - s_insert_column(config.clone(), String::from("lists"), String::from("download_folder"), String::from("TEXT"), None)?; - s_config_update_version(config, String::from("0.3")) -} +//async fn to_02(config: Cfg) -> Result<(), Box> { +// let lists = lists_get_all_ids(config.clone())?; +// +// for list in lists { +// println!("Updating {}", list); +// s_insert_column(config.clone(), String::from(&list), String::from("current_download"), String::from("TEXT"), None)?; +// +// let full_list = lists_get(config.clone(), String::from(&list))?; +// +// let versions = userlist_get_all_current_version_ids(config.clone(), full_list.clone().id)?; +// +// let raw_versions = get_raw_versions(String::from(&config.apis.modrinth), versions).await; +// +// for ver in raw_versions { +// println!("Adding link for {}", ver.project_id); +// let file = ver.files.into_iter().find(|f| f.primary).unwrap(); +// s_userlist_update_download(config.clone(), String::from(&full_list.id), ver.project_id, file.url)?; +// } +// }; +// s_config_create_version(config)?; +// +// Ok(()) +//} +// +//fn to_03(config: Cfg) -> Result<(), Box> { +// s_insert_column(config.clone(), String::from("lists"), String::from("download_folder"), String::from("TEXT"), None)?; +// s_config_update_version(config, String::from("0.3")) +//} +// +//fn to_04(config: Cfg) -> Result<(), Box> { +// for list_id in lists_get_all_ids(config.clone())? { +// 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")) +//} -fn to_04(config: Cfg) -> Result<(), Box> { - for list_id in lists_get_all_ids(config.clone())? { - 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 d400a24..bc5b316 100644 --- a/src/commands/update.rs +++ b/src/commands/update.rs @@ -1,4 +1,4 @@ -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}}; +use crate::{config::Cfg, modrinth::{versions, extract_current_version, Version}, get_current_list, db::{userlist_get_all_ids, userlist_get_applicable_versions, userlist_change_versions, lists_get_all_ids, lists_get, userlist_get_current_version, mods_get_title, userlist_get_set_version}, 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![]; @@ -9,7 +9,7 @@ pub async fn update(config: Cfg, input: Input) -> MLE<()> { } } else { let current = get_current_list(config.clone())?; - println!("Check for updates of mods in list {}", current.id); + println!("Update list {}:", current.id); liststack.push(current) } cmd_update(config, liststack, input.clean, input.direct_download, input.delete_old).await @@ -20,59 +20,41 @@ pub async fn cmd_update(config: Cfg, liststack: Vec, clean: bool, direct_d let mods = userlist_get_all_ids(config.clone(), current_list.clone().id)?; let mut current_versions: Vec<(String, String)> = vec![]; + + println!(" └Update mods:"); + let mut updatestack: Vec = vec![]; + + for id in mods { + let title = mods_get_title(config.clone(), &id)?; + println!("\t└{}", title); - let mut versions = mods_get_versions(config.clone(), mods.clone())?; - versions.sort_by_key(|ver| ver.mod_id.clone()); - - let mut projects = projects(String::from(&config.apis.modrinth), mods).await; - projects.sort_by_key(|pro| pro.id.clone()); + if userlist_get_set_version(config.clone(), ¤t_list.id, &id)? { + println!("\t └Set version, skipping update"); + continue; + } - 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 - let current_version = &versions[index]; - let p_id = String::from(&project.id); - 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))?; - - let version_db_string = project.versions.join("|"); + let disable_version = userlist_get_current_version(config.clone(), String::from(¤t_list.id), String::from(&id))?; - //Adding to stack if not the same versions in the list OR if clean == true - if clean || (version_db_string != current_version.versions) { - updatestack.push(match specific_update(config.clone(), clean, current_list.clone(), project.clone()).await { + updatestack.push( + match specific_update(config.clone(), clean, current_list.clone(), String::from(&id)).await { Ok(ver) => { - current_versions.push((disable_version, p_id)); + current_versions.push((disable_version, id)); ver }, 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"); + println!("\t └No new version found for the specified minecraft version"); } else { return Err(e); }; continue; - }, - }); - } else { - println!("\t └No new version found"); - }; + } + } + ) }; - - //Linebreak readability - println!(""); - if clean { clean_list_dir(¤t_list)? }; - - //Linebreak readability - println!(""); + if clean { clean_list_dir(¤t_list)?; }; if direct_download && !updatestack.is_empty() { download_versions(current_list.clone(), config.clone(), updatestack).await?; @@ -81,10 +63,10 @@ pub async fn cmd_update(config: Cfg, liststack: Vec, clean: bool, direct_d if !clean { for ver in current_versions { if delete_old { - println!("Deleting version {} for mod {}", ver.0, ver.1); + println!("\t └Delete version {}", ver.0); delete_version(current_list.clone(), ver.0)?; } else if ver.0 != "NONE" { - println!("Disabling version {} for mod {}", ver.0, ver.1); + println!("\t └Disable version {}", ver.0); disable_version(config.clone(), current_list.clone(), ver.0, ver.1)?; }; } @@ -95,8 +77,8 @@ 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) -> MLE { - let applicable_versions = versions(String::from(&config.apis.modrinth), String::from(&project.id), list.clone()).await; +async fn specific_update(config: Cfg, clean: bool, list: List, id: String) -> MLE { + let applicable_versions = versions(String::from(&config.apis.modrinth), String::from(&id), list.clone()).await; let mut versions: Vec = vec![]; @@ -108,12 +90,20 @@ async fn specific_update(config: Cfg, clean: bool, list: List, project: Project) versions.push(String::from("NONE")); } - 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 - println!("\t └Get versions for specified minecraft versions"); + //TODO Split clean and no match + if clean || (versions.join("|") != userlist_get_applicable_versions(config.clone(), String::from(&list.id), String::from(&id))?) { + let current_str = extract_current_version(applicable_versions.clone())?; + + if clean { + println!("\t └Add version to downloadstack"); + } else { + println!("\t └Get versions for specified minecraft versions"); + println!("\t └New current version: {}", current_str); + }; + + //get new versions 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)), @@ -124,7 +114,7 @@ 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, id)?; } if current.is_empty() { return Err(MLError::new(ErrorType::ModError, "NO_UPDATE_AVAILABLE")) }; @@ -139,7 +129,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 current_list = List { id: String::from("..."), mc_version: String::from("..."), modloader: Modloader::Fabric, download_folder: String::from("./dev/tests/dl") }; let versions = vec![Version { id: "dEqtGnT9".to_string(), diff --git a/src/db.rs b/src/db.rs index f47bda6..ecc6854 100644 --- a/src/db.rs +++ b/src/db.rs @@ -4,17 +4,17 @@ 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) -> MLE<()> { +//MODS +pub fn mods_insert(config: Cfg, id: &str, slug: &str, name: &str) -> MLE<()> { - println!("Inserting mod {}({}) into database", name, id); + println!("\t └Save mod info"); let data = devdir(format!("{}/data.db", config.data).as_str()); let connection = Connection::open(data)?; connection.execute( - "INSERT INTO mods (id, name, versions) VALUES (?1, ?2, ?3)", - [id, name.replace('\'', ""), versions.join("|")] + "INSERT INTO mods (id, slug, title) VALUES (?1, ?2, ?3)", + [id, slug, name.replace('\'', "").as_str()] )?; Ok(()) @@ -41,32 +41,53 @@ pub fn mods_get_all_ids(config: Cfg) -> Result, Box MLE { - let data = devdir(format!("{}/data.db", config.data).as_str()); +///Get mod id based on the slug or name +///# Arguments +/// +///* `data` - file directory of the database +///* `slug` - Slug or Name of a mod +/// +///# Failure +/// +///Will return `MLError` when no mod id is found +pub fn mods_get_id(data: &str, slug: &str) -> MLE { + let data = devdir(format!("{}/data.db", data).as_str()); let connection = Connection::open(data)?; let mut mod_id = String::new(); - let mut stmt = connection.prepare("SELECT id FROM mods WHERE name = ?")?; - let id_iter = stmt.query_map([name], |row| { + + //get from slug + let mut stmt = connection.prepare("SELECT id FROM mods WHERE slug = ?")?; + let id_iter = stmt.query_map([slug], |row| { row.get::(0) })?; for id in id_iter { mod_id = id?; }; - - match mod_id.is_empty() { - true => Err(MLError::new(ErrorType::DBError, "GI_MOD_NOT_FOUND")), - false => Ok(mod_id), + //get from title if no id found from slug + if mod_id.is_empty() { + let mut stmt = connection.prepare("SELECT id FROM mods WHERE title = ?")?; + let id_iter = stmt.query_map([slug], |row| { + row.get::(0) + })?; + + for id in id_iter { + mod_id = id?; + }; } + + if mod_id.is_empty() { return Err(MLError::new(ErrorType::DBError, "GI_MOD_NOT_FOUND")) }; + + Ok(mod_id) } -pub fn mods_get_name(config: Cfg, id: &str) -> MLE { +pub fn mods_get_title(config: Cfg, id: &str) -> MLE { let data = devdir(format!("{}/data.db", config.data).as_str()); let connection = Connection::open(data)?; let mut mod_name = String::new(); - let mut stmt = connection.prepare("SELECT name FROM mods WHERE id = ?")?; + let mut stmt = connection.prepare("SELECT title FROM mods WHERE id = ?")?; let name_iter = stmt.query_map([id], |row| { row.get::(0) })?; @@ -81,17 +102,6 @@ pub fn mods_get_name(config: Cfg, id: &str) -> MLE { } } -pub fn mods_change_versions(config: Cfg, versions: String, mod_id: String) -> MLE<()> { - - //println!("Updating versions for {} with \n {}", mod_id, versions); - - let data = devdir(format!("{}/data.db", config.data).as_str()); - let connection = Connection::open(data)?; - - connection.execute("UPDATE mods SET versions = ?1 WHERE id = ?2", [versions, mod_id])?; - Ok(()) -} - pub fn mods_remove(config: Cfg, id: String) -> MLE<()> { println!("Removing mod {} from database", id); @@ -124,7 +134,7 @@ pub fn mods_get_versions(config: Cfg, mods: Vec) -> MLE = Vec::new(); - let mut stmt = connection.prepare(format!("SELECT id, versions, name FROM mods {}", wherestr).as_str())?; + let mut stmt = connection.prepare(format!("SELECT id, versions, title FROM mods {}", wherestr).as_str())?; let id_iter = stmt.query_map([], |row| { Ok(vec![row.get::(0)?, row.get::(1)?, row.get::(2)?]) })?; @@ -143,14 +153,18 @@ pub fn mods_get_versions(config: Cfg, mods: Vec) -> MLE, current_link: String) -> MLE<()> { - println!("Inserting {} into current list({})", mod_id, list_id); +pub fn userlist_insert(config: Cfg, list_id: &str, mod_id: &str, current_version: &str, applicable_versions: Vec, current_link: &str, set_version: bool) -> MLE<()> { + println!("\t └Insert in list"); let data = devdir(format!("{}/data.db", config.data).as_str()); let connection = Connection::open(data)?; - - connection.execute(format!("INSERT INTO {} VALUES (?1, ?2, ?3, ?4, 'NONE')", list_id).as_str(), [mod_id, current_version, applicable_versions.join("|"), current_link])?; + let sv = match set_version { + true => "1", + false => "0", + }; + + connection.execute(format!("INSERT INTO {} VALUES (?1, ?2, ?3, ?4, 'NONE', ?5)", list_id).as_str(), [mod_id, current_version, applicable_versions.join("|").as_str(), current_link, sv])?; Ok(()) } @@ -285,6 +299,23 @@ pub fn userlist_get_all_current_versions_with_mods(config: Cfg, list_id: String) Ok(versions) } +pub fn userlist_get_set_version(config:Cfg, list_id: &str, mod_id: &str) -> MLE { + let data = devdir(format!("{}/data.db", config.data).as_str()); + let connection = Connection::open(data).unwrap(); + + let mut set_version: bool = false; + let mut stmt = connection.prepare(format!("SELECT set_version FROM {} WHERE mod_id = ?", list_id).as_str())?; + let ver_iter = stmt.query_map([&mod_id], |row| { + row.get::(0) + })?; + + for ver in ver_iter { + set_version = ver?; + }; + + Ok(set_version) +} + 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)?; @@ -357,7 +388,7 @@ pub fn lists_insert(config: Cfg, id: String, mc_version: String, mod_loader: Mod let connection = Connection::open(data)?; connection.execute("INSERT INTO lists VALUES (?1, ?2, ?3, ?4)", [id.clone(), mc_version, mod_loader.to_string(), download_folder])?; - connection.execute(format!("CREATE TABLE {}( 'mod_id' TEXT, 'current_version' TEXT, 'applicable_versions' BLOB, 'current_download' TEXT, 'disabled_versions' TEXT DEFAULT 'NONE' )", id).as_str(), [])?; + connection.execute(format!("CREATE TABLE {}( 'mod_id' TEXT, 'current_version' TEXT, 'applicable_versions' BLOB, 'current_download' TEXT, 'disabled_versions' TEXT DEFAULT 'NONE', 'set_version' INTEGER, CONSTRAINT {}_PK PRIMARY KEY (mod_id) )", id, id).as_str(), [])?; Ok(()) } @@ -505,7 +536,7 @@ pub fn s_insert_column(config: Cfg, table: String, column: String, c_type: Strin Ok(()) } -pub fn db_setup(config: Cfg) -> Result<(), Box> { +pub fn db_setup(config: Cfg) -> MLE<()> { println!("Initiating database"); @@ -514,9 +545,9 @@ pub fn db_setup(config: Cfg) -> Result<(), Box> { connection.execute_batch( "CREATE TABLE 'user_config' ( 'id' TEXT, 'value' TEXT ); - CREATE TABLE 'mods' ( 'id' TEXT, 'name' TEXT, 'versions' TEXT ); + CREATE TABLE 'mods' ( 'id' TEXT, 'slug' TEXT, 'title' TEXT, CONSTRAINT mods_PK PRIMARY KEY (id) ); CREATE TABLE 'lists' ( 'id' TEXT, 'mc_version' TEXT, 'modloader' TEXT, 'download_folder' TEXT ); - INSERT INTO 'user_config' VALUES ( 'db_version', '0.4' ); + INSERT INTO 'user_config' VALUES ( 'db_version', '0.5' ); INSERT INTO 'user_config' VALUES ( 'current_list', '...' )", )?; diff --git a/src/error.rs b/src/error.rs index 612a2e2..794a919 100644 --- a/src/error.rs +++ b/src/error.rs @@ -39,7 +39,7 @@ impl fmt::Display for MLError { ErrorType::DBError => write!(f, "Database: {}", self.message), ErrorType::ModError => write!(f, "Mod: {}", self.message), ErrorType::LibToml => write!(f, "TOML"), - ErrorType::LibSql => write!(f, "SQL"), + ErrorType::LibSql => write!(f, "SQL: {}", self.message), ErrorType::LibReq => write!(f, "REQWEST"), ErrorType::LibChrono => write!(f, "Chrono error: {}", self.message), ErrorType::IoError => write!(f, "IO"), diff --git a/src/files.rs b/src/files.rs index 8c822b2..b9325ea 100644 --- a/src/files.rs +++ b/src/files.rs @@ -2,17 +2,17 @@ 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, mods_get_name}, config::Cfg, error::{MLE, MLError, ErrorType}}; +use crate::{List, modrinth::Version, db::{userlist_add_disabled_versions, mods_get_title}, config::Cfg, error::{MLE, MLError, ErrorType}}; pub async fn download_versions(list: List, config: Cfg, versions: Vec) -> MLE { let dl_path = String::from(&list.download_folder); - println!("Download to directory from: {} ({})", list.id, dl_path); + println!(" └Download mods to {}", dl_path); for ver in versions { - let project_name = mods_get_name(config.clone(), &ver.project_id)?; - print!("\t({})Download version {}", project_name, ver.id); + let project_name = mods_get_title(config.clone(), &ver.project_id)?; + print!("\t└({})Download version {}", project_name, ver.id); //Force flush of stdout, else print! doesn't print instantly std::io::stdout().flush().unwrap(); let primary_file = ver.files.into_iter().find(|file| file.primary).unwrap(); @@ -107,7 +107,7 @@ pub fn get_downloaded_versions(list: List) -> MLE> { pub fn clean_list_dir(list: &List) -> MLE<()> { let dl_path = &list.download_folder; - println!("Clean directory for: {}", list.id); + println!(" └Clean directory for: {}", list.id); for entry in std::fs::read_dir(dl_path)? { let entry = entry?; std::fs::remove_file(entry.path())?; diff --git a/src/input.rs b/src/input.rs index 144f22a..17fc773 100644 --- a/src/input.rs +++ b/src/input.rs @@ -29,6 +29,7 @@ pub enum Cmd { Download, Io, Version, + Setup, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -58,7 +59,7 @@ impl Input { args[0] = args[0].split_at(1).1; let mut command: Option = None; - + let mut mod_options: Option = None; let mut mod_id: Option = None; let mut mod_version: Option = None; @@ -77,7 +78,7 @@ impl Input { let mut file: Option = None; for arg in args { - let arg_split: Vec<&str> = arg.trim().split(" ").collect(); + let arg_split: Vec<&str> = arg.trim().split(' ').collect(); match arg_split[0] { "v" | "version" => { command = Some(Cmd::Version); @@ -97,9 +98,8 @@ impl Input { return Err(MLError::new(ErrorType::ArgumentError, "Please specify a list mod slug or id")); } }, + //TODO impl this "mv" => { - command = Some(Cmd::Mod); - mod_options = Some(ModOptions::Add); if arg_split.len() == 2 { mod_version = Some(String::from(arg_split[1])); } else { @@ -195,6 +195,9 @@ impl Input { "f" => { file = Some(String::from(arg_split[1])); }, + "setup" => { + command = Some(Cmd::Setup); + } _ => return Err(MLError::new(ErrorType::ArgumentError, format!("Unknown Argument ({})", arg_split[0]).as_str())), } } @@ -240,11 +243,12 @@ fn check_mod(mut input: Input, config: Cfg) -> MLE { match input.clone().mod_options.unwrap() { 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())?); }; + if input.list_id.is_none() { input.list = Some(get_current_list(config)?); }; Ok(input) }, ModOptions::Remove => { if input.mod_id.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "MODS_NO_MODID")); }; + if input.list_id.is_none() { input.list = Some(get_current_list(config)?); }; Ok(input) }, } @@ -274,7 +278,6 @@ async fn check_list(mut input: Input, config: Cfg) -> MLE { 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) }, @@ -292,7 +295,7 @@ async fn check_list(mut input: Input, config: Cfg) -> MLE { 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::from(config, vec![String::from("-la test -lv 1.19.3")]).unwrap(), Input { command: Some(Cmd::List), mod_options: None, @@ -310,7 +313,7 @@ fn input_from() { modloader: None, directory: None, io_options: None, - file: None + file: None, } ); diff --git a/src/main.rs b/src/main.rs index d177c3e..32727c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,20 @@ use std::{env, process}; -use modlist::{config::Cfg, input::{get_input, Cmd}, update, download, list, io, modification}; +use modlist::{config::Cfg, input::{get_input, Cmd}, update, download, list, io, modification, setup}; #[tokio::main] async fn main() { let config = Cfg::init("modlist.toml").unwrap(); - + let mut args: Vec = env::args().collect(); args.reverse(); args.pop(); args.reverse(); + + if args.is_empty() { + println!("Please enter an argument"); + process::exit(1); + }; let input = match get_input(config.clone(), args).await { Ok(i) => i, @@ -19,8 +24,6 @@ async fn main() { } }; - //dbg!(&input); - match input.clone().command.unwrap() { Cmd::Mod => { modification(config, input).await @@ -41,6 +44,9 @@ async fn main() { show_version(); Ok(()) }, + Cmd::Setup => { + setup(config).await + }, }.unwrap() } -- cgit v1.2.3