From b125dfd03084fff47ab8e90d002c6699b762d998 Mon Sep 17 00:00:00 2001 From: fxqnlr Date: Tue, 1 Nov 2022 23:00:45 +0100 Subject: added list stuff + beginnings of mods --- .gitignore | 2 +- config.ini | 6 ++-- data.db | Bin 0 -> 36864 bytes planmodlist.xopp | Bin 132624 -> 130585 bytes src/commands/add.rs | 28 ++++++++++++++--- src/commands/list.rs | 80 ++++++++++++++++++++++++++++++++++++++++++++++ src/commands/mod.rs | 2 ++ src/config.rs | 6 ++-- src/db.rs | 87 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/input.rs | 12 +++---- src/lib.rs | 1 + 11 files changed, 204 insertions(+), 20 deletions(-) create mode 100644 data.db create mode 100644 src/commands/list.rs diff --git a/.gitignore b/.gitignore index 29da4f7..ec088fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ /target /api-tests -data.db +/data .planmodlist.autosave.xopp diff --git a/config.ini b/config.ini index 0ea32d5..ce33108 100644 --- a/config.ini +++ b/config.ini @@ -1,3 +1,5 @@ +data = "./" + [apis] -;modrinth = "http://localhost:8080/" -modrinth = "https://api.modrinth.com/v2/" +modrinth = "http://localhost:8080/" +;modrinth = "https://api.modrinth.com/v2/" diff --git a/data.db b/data.db new file mode 100644 index 0000000..60431f1 Binary files /dev/null and b/data.db differ diff --git a/planmodlist.xopp b/planmodlist.xopp index 60fbb4e..6cf4021 100644 Binary files a/planmodlist.xopp and b/planmodlist.xopp differ diff --git a/src/commands/add.rs b/src/commands/add.rs index 67f63de..ed4a6d8 100644 --- a/src/commands/add.rs +++ b/src/commands/add.rs @@ -1,11 +1,28 @@ use std::io::{Error, ErrorKind}; -use crate::{modrinth::{project, versions}, config::Cfg, db::insert_mod, Modloader}; +use crate::{modrinth::{project, versions}, config::Cfg, db::insert_mod, Modloader, input::Input}; -pub async fn add(config: Cfg, mc_mod: String) -> Result<(), Box> { - println!("Adding"); +pub async fn modification(config: Cfg, args: Option>) -> Result<(), Box> { - let project = project(String::from(&config.apis.modrinth), &mc_mod).await; + if args.is_none() { return Err(Box::new(Error::new(ErrorKind::InvalidInput, "TOO_FEW_ARGUMENTS"))) } + + let arguments = Input::from(args.unwrap().join(" "))?; + + if arguments.args.is_none() { return Err(Box::new(Error::new(ErrorKind::InvalidInput, "TOO_FEW_ARGUMENTS"))); }; + + match arguments.command.as_str() { + "add" => { + add(config, arguments.args.unwrap()).await + }, + _ => Err(Box::new(Error::new(ErrorKind::InvalidInput, "UNKNOWN_SUBCOMMAND"))) + } +} + +pub async fn add(config: Cfg, args: Vec) -> Result<(), Box> { + + if args.len() < 1 { return Err(Box::new(Error::new(ErrorKind::InvalidInput, "TOO_FEW_ARGUMENTS"))); }; + + let project = project(String::from(&config.apis.modrinth), &args[0]).await; dbg!(&project); @@ -14,7 +31,8 @@ pub async fn add(config: Cfg, mc_mod: String) -> Result<(), Box { Err(Box::new(err)) }, Ok(()) => Ok(()), diff --git a/src/commands/list.rs b/src/commands/list.rs new file mode 100644 index 0000000..6c260ce --- /dev/null +++ b/src/commands/list.rs @@ -0,0 +1,80 @@ +use std::io::{Error, ErrorKind}; + +use crate::{db::{insert_list, remove_list, change_list, get_lists, get_current_list}, Modloader, config::Cfg, input::Input}; + +pub fn list(config: Cfg, args: Option>) -> Result<(), Box> { + + if args.is_none() { + let lists = get_lists(config.clone())?; + let current_list = get_current_list(config)?; + println!("Your lists:\n{}\n-----\nCurrently selected list: \"{}\"", lists.join(",\n"), current_list); + return Ok(()); + } + + let arguments = Input::from(args.unwrap().join(" "))?; + + if arguments.args.is_none() { return Err(Box::new(Error::new(ErrorKind::InvalidInput, "TOO_FEW_ARGUMENTS"))); }; + + match arguments.command.as_str() { + "add" => { + add(config, arguments.args.unwrap()) + }, + "change" => { + change(config, arguments.args.unwrap()) + }, + "remove" => { + remove(config, arguments.args.unwrap()) + }, + _ => Err(Box::new(Error::new(ErrorKind::InvalidInput, "UNKNOWN_SUBCOMMAND"))) + } +} + +fn add(config: Cfg, args: Vec) -> Result<(), Box> { + match args.len() { + 1 | 2 => Err(Box::new(Error::new(ErrorKind::InvalidInput, "TOO_FEW_ARGUMENTS"))), + 3 => { + let id = String::from(&args[0]); + let mc_version = String::from(&args[1]); + let mod_loader = match args[2].as_str() { + "forge" => Modloader::Forge, + "fabric" => Modloader::Fabric, + _ => return Err(Box::new(Error::new(ErrorKind::InvalidInput, "UNKNOWN_MODLOADER"))) + }; + match insert_list(config, id, mc_version, mod_loader) { + Err(err) => { Err(Box::new(err)) }, + Ok(()) => Ok(()), + } + }, + 5.. => Err(Box::new(Error::new(ErrorKind::InvalidInput, "TOO_MANY_ARGUMENTS"))), + _ => panic!("list arguments should never be zero or lower"), + } +} + +fn change(config: Cfg, args: Vec) -> Result<(), Box> { + let lists = get_lists(config.clone())?; + match args.len() { + 1 => { + let list = String::from(&args[0]); + if !lists.contains(&list) { return Err(Box::new(Error::new(ErrorKind::NotFound, "LIST_DOESNT_EXIST"))); }; + match change_list(config, list) { + Err(err) => { Err(Box::new(err)) }, + Ok(()) => Ok(()), + } + }, + 2.. => Err(Box::new(Error::new(ErrorKind::InvalidInput, "TOO_MANY_ARGUMENTS"))), + _ => panic!("list arguments should never be zero or lower"), + } +} + +fn remove(config: Cfg, args: Vec) -> Result<(), Box> { + match args.len() { + 1 => { + match remove_list(config, String::from(&args[0])) { + Err(err) => { Err(Box::new(err)) }, + Ok(()) => Ok(()), + } + }, + 2.. => Err(Box::new(Error::new(ErrorKind::InvalidInput, "TOO_MANY_ARGUMENTS"))), + _ => panic!("list arguments should never be zero or lower"), + } +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 0cc183a..6432746 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,3 +1,5 @@ pub mod add; +pub mod list; pub use add::*; +pub use list::*; diff --git a/src/config.rs b/src/config.rs index a0dfbbe..ba1b46a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,18 +1,20 @@ use config::{Config, File, FileFormat}; use serde::Deserialize; -#[derive(Debug, Deserialize)] +#[derive(Debug, Clone,Deserialize)] pub struct Cfg { + pub data: String, pub apis: Apis, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Clone, Deserialize)] pub struct Apis { pub modrinth: String, } impl Cfg { pub fn init(path: &str) -> Self { + //TODO Error Handling Config::builder() .add_source(File::new(path, FileFormat::Ini)) .build() diff --git a/src/db.rs b/src/db.rs index 3d50b0f..bbbca87 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,4 +1,8 @@ -use crate::Modloader; +use std::io::ErrorKind; + +use crate::{Modloader, config::Cfg}; + +//TODO use prepared statements pub fn insert_mod(id: String, name: String, current_version: String, old_versions: Vec, mod_loader: Modloader, desired_mc_version: String) -> Result<(), sqlite::Error> { @@ -10,9 +14,88 @@ pub fn insert_mod(id: String, name: String, current_version: String, old_version }; let sql = format!("INSERT INTO mods VALUES ('{}', '{}', '{}', '{}', '{}', '{}')", id, name, current_version, old_versions.join("|"), loader, desired_mc_version); + + connection.execute(sql) +} + +//LIST +pub fn insert_list(config: Cfg, id: String, mc_version: String, mod_loader: Modloader) -> Result<(), sqlite::Error> { + let data = format!("{}/data.db", config.data); + let connection = sqlite::open(data).unwrap(); - dbg!(&sql); + //Setup list in table + let loader = match mod_loader { + Modloader::Fabric => "fabric", + Modloader::Forge => "forge", + }; + + let sql_list = format!("INSERT INTO lists VALUES ('{}', '{}', '{}')", id, mc_version, loader); + let sql_table = format!("CREATE TABLE '{}' ( 'mod_id' TEXT, 'current_version' TEXT, 'applicable_versions' BLOB, 'mod_loader' TEXT )", id); + let sql = format!("{};{};", sql_list, sql_table); connection.execute(sql) +} +pub fn remove_list(config: Cfg, id: String) -> Result<(), sqlite::Error> { + let data = format!("{}/data.db", config.data); + let connection = sqlite::open(data).unwrap(); + + let sql_list = format!("DELETE FROM lists WHERE id = '{}'", id); + let sql_table = format!("DROP TABLE '{}'", id); + let sql = format!("{};{};", sql_list, sql_table); + + connection.execute(sql) +} + +pub fn get_lists(config: Cfg) -> Result, Box> { + let data = format!("{}/data.db", config.data); + let connection = sqlite::open(data).unwrap(); + + let sql = "SELECT id FROM lists"; + + let mut list: Vec = Vec::new(); + //TODO catch sql errors better + connection.iterate(sql, |ids| { + if ids.is_empty() { return false; }; + for &(_column, value) in ids.iter() { + list.push(String::from(value.unwrap())); + } + true + }).unwrap(); + match list.is_empty() { + true => Err(Box::new(std::io::Error::new(ErrorKind::NotFound, "NO_LISTS"))), + false => Ok(list), + } +} + +//config +pub fn change_list(config: Cfg, id: String) -> Result<(), sqlite::Error> { + let data = format!("{}/data.db", config.data); + let connection = sqlite::open(data).unwrap(); + + let sql = format!("UPDATE user_config SET value = '{}' WHERE id = 'current_list'", id); + + connection.execute(sql) +} + +pub fn get_current_list(config: Cfg) -> Result> { + let data = format!("{}/data.db", config.data); + let connection = sqlite::open(data).unwrap(); + + let sql = "SELECT id FROM lists"; + + let mut list: String = String::new(); + //TODO catch sql errors better + connection.iterate(sql, |ids| { + if ids.is_empty() { return false; }; + for &(_column, value) in ids.iter() { + list = String::from(value.unwrap()); + } + true + }).unwrap(); + if list.is_empty() { + get_lists(config)?; + panic!("current list field should never be empty if there are other lists"); + }; + Ok(list) } diff --git a/src/input.rs b/src/input.rs index 689389e..061f1fd 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,5 +1,5 @@ use std::io::{stdin, Error, ErrorKind}; -use crate::{add, config::Cfg}; +use crate::{add, config::Cfg, list}; pub struct Input { pub command: String, @@ -9,14 +9,9 @@ pub struct Input { impl Input { pub fn from(string: String) -> Result> { let mut split: Vec<&str> = string.split(' ').collect(); - let command: String; let mut args: Option> = None; - if split[0].is_empty() { split.remove(0); }; - - dbg!(&split); - match split.len() { 0 => { Err(Box::new(Error::new(ErrorKind::InvalidInput, "NO_ARGS"))) } 1 => Ok( Input { command: split[0].to_string(), args }), @@ -43,8 +38,6 @@ pub async fn get_input(config: Cfg) -> Result<(), Box> { .read_line(&mut user_input) .expect("ERROR"); - dbg!(&user_input); - let input = Input::from(user_input.trim().to_string())?; match input.command.as_str() { @@ -54,6 +47,9 @@ pub async fn get_input(config: Cfg) -> Result<(), Box> { add(config, input.args.unwrap()[0].to_string()).await?; Ok(()) }, + "list" => { + list(config, input.args) + }, _ => Err(Box::new(Error::new(ErrorKind::InvalidInput, "UNKNOWN_COMMAND"))), } } diff --git a/src/lib.rs b/src/lib.rs index 52b0646..4ad7c39 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ pub mod db; pub use apis::*; pub use commands::*; +#[derive(Debug)] pub enum Modloader { Fabric, Forge -- cgit v1.2.3