summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Cargo.lock201
-rw-r--r--Cargo.toml6
-rw-r--r--config.ini1
-rw-r--r--data.dbbin36864 -> 36864 bytes
-rw-r--r--src/apis/modrinth.rs23
-rw-r--r--src/commands/modification.rs11
-rw-r--r--src/commands/update.rs140
-rw-r--r--src/config.rs1
-rw-r--r--src/db.rs32
-rw-r--r--src/input.rs10
-rw-r--r--tests/db/mod.rs4
-rw-r--r--tests/db_integration.rs1
13 files changed, 387 insertions, 45 deletions
diff --git a/.gitignore b/.gitignore
index ec088fc..c91ef38 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
1/target 1/target
2/api-tests 2/api-tests
3/data 3/dl
4.planmodlist.autosave.xopp 4.planmodlist.autosave.xopp
diff --git a/Cargo.lock b/Cargo.lock
index 4f1f0d6..29e309e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -14,6 +14,15 @@ dependencies = [
14] 14]
15 15
16[[package]] 16[[package]]
17name = "android_system_properties"
18version = "0.1.5"
19source = "registry+https://github.com/rust-lang/crates.io-index"
20checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
21dependencies = [
22 "libc",
23]
24
25[[package]]
17name = "async-trait" 26name = "async-trait"
18version = "0.1.58" 27version = "0.1.58"
19source = "registry+https://github.com/rust-lang/crates.io-index" 28source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -76,6 +85,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
76checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 85checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
77 86
78[[package]] 87[[package]]
88name = "chrono"
89version = "0.4.22"
90source = "registry+https://github.com/rust-lang/crates.io-index"
91checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
92dependencies = [
93 "iana-time-zone",
94 "js-sys",
95 "num-integer",
96 "num-traits",
97 "time",
98 "wasm-bindgen",
99 "winapi",
100]
101
102[[package]]
103name = "codespan-reporting"
104version = "0.11.1"
105source = "registry+https://github.com/rust-lang/crates.io-index"
106checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
107dependencies = [
108 "termcolor",
109 "unicode-width",
110]
111
112[[package]]
79name = "config" 113name = "config"
80version = "0.13.2" 114version = "0.13.2"
81source = "registry+https://github.com/rust-lang/crates.io-index" 115source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -130,6 +164,50 @@ dependencies = [
130] 164]
131 165
132[[package]] 166[[package]]
167name = "cxx"
168version = "1.0.80"
169source = "registry+https://github.com/rust-lang/crates.io-index"
170checksum = "6b7d4e43b25d3c994662706a1d4fcfc32aaa6afd287502c111b237093bb23f3a"
171dependencies = [
172 "cc",
173 "cxxbridge-flags",
174 "cxxbridge-macro",
175 "link-cplusplus",
176]
177
178[[package]]
179name = "cxx-build"
180version = "1.0.80"
181source = "registry+https://github.com/rust-lang/crates.io-index"
182checksum = "84f8829ddc213e2c1368e51a2564c552b65a8cb6a28f31e576270ac81d5e5827"
183dependencies = [
184 "cc",
185 "codespan-reporting",
186 "once_cell",
187 "proc-macro2",
188 "quote",
189 "scratch",
190 "syn",
191]
192
193[[package]]
194name = "cxxbridge-flags"
195version = "1.0.80"
196source = "registry+https://github.com/rust-lang/crates.io-index"
197checksum = "e72537424b474af1460806647c41d4b6d35d09ef7fe031c5c2fa5766047cc56a"
198
199[[package]]
200name = "cxxbridge-macro"
201version = "1.0.80"
202source = "registry+https://github.com/rust-lang/crates.io-index"
203checksum = "309e4fb93eed90e1e14bea0da16b209f81813ba9fc7830c20ed151dd7bc0a4d7"
204dependencies = [
205 "proc-macro2",
206 "quote",
207 "syn",
208]
209
210[[package]]
133name = "digest" 211name = "digest"
134version = "0.10.5" 212version = "0.10.5"
135source = "registry+https://github.com/rust-lang/crates.io-index" 213source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -209,6 +287,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
209checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" 287checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
210 288
211[[package]] 289[[package]]
290name = "futures-macro"
291version = "0.3.25"
292source = "registry+https://github.com/rust-lang/crates.io-index"
293checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
294dependencies = [
295 "proc-macro2",
296 "quote",
297 "syn",
298]
299
300[[package]]
212name = "futures-sink" 301name = "futures-sink"
213version = "0.3.25" 302version = "0.3.25"
214source = "registry+https://github.com/rust-lang/crates.io-index" 303source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -227,9 +316,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
227checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" 316checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
228dependencies = [ 317dependencies = [
229 "futures-core", 318 "futures-core",
319 "futures-macro",
230 "futures-task", 320 "futures-task",
231 "pin-project-lite", 321 "pin-project-lite",
232 "pin-utils", 322 "pin-utils",
323 "slab",
233] 324]
234 325
235[[package]] 326[[package]]
@@ -250,7 +341,7 @@ checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
250dependencies = [ 341dependencies = [
251 "cfg-if", 342 "cfg-if",
252 "libc", 343 "libc",
253 "wasi", 344 "wasi 0.11.0+wasi-snapshot-preview1",
254] 345]
255 346
256[[package]] 347[[package]]
@@ -362,6 +453,30 @@ dependencies = [
362] 453]
363 454
364[[package]] 455[[package]]
456name = "iana-time-zone"
457version = "0.1.53"
458source = "registry+https://github.com/rust-lang/crates.io-index"
459checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765"
460dependencies = [
461 "android_system_properties",
462 "core-foundation-sys",
463 "iana-time-zone-haiku",
464 "js-sys",
465 "wasm-bindgen",
466 "winapi",
467]
468
469[[package]]
470name = "iana-time-zone-haiku"
471version = "0.1.1"
472source = "registry+https://github.com/rust-lang/crates.io-index"
473checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"
474dependencies = [
475 "cxx",
476 "cxx-build",
477]
478
479[[package]]
365name = "idna" 480name = "idna"
366version = "0.3.0" 481version = "0.3.0"
367source = "registry+https://github.com/rust-lang/crates.io-index" 482source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -435,6 +550,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
435checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" 550checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
436 551
437[[package]] 552[[package]]
553name = "link-cplusplus"
554version = "1.0.7"
555source = "registry+https://github.com/rust-lang/crates.io-index"
556checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369"
557dependencies = [
558 "cc",
559]
560
561[[package]]
438name = "linked-hash-map" 562name = "linked-hash-map"
439version = "0.5.6" 563version = "0.5.6"
440source = "registry+https://github.com/rust-lang/crates.io-index" 564source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -485,7 +609,7 @@ checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
485dependencies = [ 609dependencies = [
486 "libc", 610 "libc",
487 "log", 611 "log",
488 "wasi", 612 "wasi 0.11.0+wasi-snapshot-preview1",
489 "windows-sys 0.42.0", 613 "windows-sys 0.42.0",
490] 614]
491 615
@@ -493,7 +617,9 @@ dependencies = [
493name = "modlist" 617name = "modlist"
494version = "0.1.0" 618version = "0.1.0"
495dependencies = [ 619dependencies = [
620 "chrono",
496 "config", 621 "config",
622 "futures-util",
497 "reqwest", 623 "reqwest",
498 "serde", 624 "serde",
499 "serde_json", 625 "serde_json",
@@ -530,6 +656,25 @@ dependencies = [
530] 656]
531 657
532[[package]] 658[[package]]
659name = "num-integer"
660version = "0.1.45"
661source = "registry+https://github.com/rust-lang/crates.io-index"
662checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
663dependencies = [
664 "autocfg",
665 "num-traits",
666]
667
668[[package]]
669name = "num-traits"
670version = "0.2.15"
671source = "registry+https://github.com/rust-lang/crates.io-index"
672checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
673dependencies = [
674 "autocfg",
675]
676
677[[package]]
533name = "num_cpus" 678name = "num_cpus"
534version = "1.13.1" 679version = "1.13.1"
535source = "registry+https://github.com/rust-lang/crates.io-index" 680source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -762,6 +907,7 @@ dependencies = [
762 "serde_urlencoded", 907 "serde_urlencoded",
763 "tokio", 908 "tokio",
764 "tokio-native-tls", 909 "tokio-native-tls",
910 "tokio-util",
765 "tower-service", 911 "tower-service",
766 "url", 912 "url",
767 "wasm-bindgen", 913 "wasm-bindgen",
@@ -814,6 +960,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
814checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 960checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
815 961
816[[package]] 962[[package]]
963name = "scratch"
964version = "1.0.2"
965source = "registry+https://github.com/rust-lang/crates.io-index"
966checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898"
967
968[[package]]
817name = "security-framework" 969name = "security-framework"
818version = "2.7.0" 970version = "2.7.0"
819source = "registry+https://github.com/rust-lang/crates.io-index" 971source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -926,9 +1078,9 @@ dependencies = [
926 1078
927[[package]] 1079[[package]]
928name = "sqlite" 1080name = "sqlite"
929version = "0.27.3" 1081version = "0.28.0"
930source = "registry+https://github.com/rust-lang/crates.io-index" 1082source = "registry+https://github.com/rust-lang/crates.io-index"
931checksum = "e66cb949f931ece6201d72bffad3f3601b94998a345793713dd13af70a77c185" 1083checksum = "125b4c6f5428ee2fc895b6c3633f7761084028481bca9a02dce6477d80eff083"
932dependencies = [ 1084dependencies = [
933 "libc", 1085 "libc",
934 "sqlite3-sys", 1086 "sqlite3-sys",
@@ -980,6 +1132,15 @@ dependencies = [
980] 1132]
981 1133
982[[package]] 1134[[package]]
1135name = "termcolor"
1136version = "1.1.3"
1137source = "registry+https://github.com/rust-lang/crates.io-index"
1138checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
1139dependencies = [
1140 "winapi-util",
1141]
1142
1143[[package]]
983name = "thiserror" 1144name = "thiserror"
984version = "1.0.37" 1145version = "1.0.37"
985source = "registry+https://github.com/rust-lang/crates.io-index" 1146source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1000,6 +1161,17 @@ dependencies = [
1000] 1161]
1001 1162
1002[[package]] 1163[[package]]
1164name = "time"
1165version = "0.1.44"
1166source = "registry+https://github.com/rust-lang/crates.io-index"
1167checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
1168dependencies = [
1169 "libc",
1170 "wasi 0.10.0+wasi-snapshot-preview1",
1171 "winapi",
1172]
1173
1174[[package]]
1003name = "tinyvec" 1175name = "tinyvec"
1004version = "1.6.0" 1176version = "1.6.0"
1005source = "registry+https://github.com/rust-lang/crates.io-index" 1177source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1144,6 +1316,12 @@ dependencies = [
1144] 1316]
1145 1317
1146[[package]] 1318[[package]]
1319name = "unicode-width"
1320version = "0.1.10"
1321source = "registry+https://github.com/rust-lang/crates.io-index"
1322checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
1323
1324[[package]]
1147name = "url" 1325name = "url"
1148version = "2.3.1" 1326version = "2.3.1"
1149source = "registry+https://github.com/rust-lang/crates.io-index" 1327source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1178,6 +1356,12 @@ dependencies = [
1178 1356
1179[[package]] 1357[[package]]
1180name = "wasi" 1358name = "wasi"
1359version = "0.10.0+wasi-snapshot-preview1"
1360source = "registry+https://github.com/rust-lang/crates.io-index"
1361checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
1362
1363[[package]]
1364name = "wasi"
1181version = "0.11.0+wasi-snapshot-preview1" 1365version = "0.11.0+wasi-snapshot-preview1"
1182source = "registry+https://github.com/rust-lang/crates.io-index" 1366source = "registry+https://github.com/rust-lang/crates.io-index"
1183checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1367checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
@@ -1275,6 +1459,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1275checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1459checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1276 1460
1277[[package]] 1461[[package]]
1462name = "winapi-util"
1463version = "0.1.5"
1464source = "registry+https://github.com/rust-lang/crates.io-index"
1465checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
1466dependencies = [
1467 "winapi",
1468]
1469
1470[[package]]
1278name = "winapi-x86_64-pc-windows-gnu" 1471name = "winapi-x86_64-pc-windows-gnu"
1279version = "0.4.0" 1472version = "0.4.0"
1280source = "registry+https://github.com/rust-lang/crates.io-index" 1473source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index bbc0456..d5c39d2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,9 +6,11 @@ edition = "2021"
6# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 6# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 7
8[dependencies] 8[dependencies]
9reqwest = { version = "0.11", features = ["json"] } 9reqwest = { version = "0.11", features = ["json", "stream"] }
10tokio = { version = "1", features = ["full"] } 10tokio = { version = "1", features = ["full"] }
11serde = { version = "1.0", features = ["derive"] } 11serde = { version = "1.0", features = ["derive"] }
12serde_json = "1.0.87" 12serde_json = "1.0.87"
13config = "0.13.2" 13config = "0.13.2"
14sqlite = "0.27.3" 14sqlite = "0.28.0"
15futures-util = "0.3.14"
16chrono = "0.4.22"
diff --git a/config.ini b/config.ini
index 0ffe0ac..345a13a 100644
--- a/config.ini
+++ b/config.ini
@@ -1,5 +1,6 @@
1data = "./" 1data = "./"
2clean_remove = false 2clean_remove = false
3downloads = "./dl"
3 4
4[apis] 5[apis]
5modrinth = "http://localhost:8080/" 6modrinth = "http://localhost:8080/"
diff --git a/data.db b/data.db
index 73464d8..2d258dc 100644
--- a/data.db
+++ b/data.db
Binary files differ
diff --git a/src/apis/modrinth.rs b/src/apis/modrinth.rs
index 0c3eca5..c71b47f 100644
--- a/src/apis/modrinth.rs
+++ b/src/apis/modrinth.rs
@@ -1,3 +1,5 @@
1use std::io::{Error, ErrorKind};
2use chrono::{DateTime, FixedOffset};
1use serde::Deserialize; 3use serde::Deserialize;
2 4
3use crate::{Modloader, List}; 5use crate::{Modloader, List};
@@ -153,3 +155,24 @@ pub async fn versions(api: String, id: String, list: List) -> Vec<Version> {
153 155
154 serde_json::from_slice(&data.await.unwrap()).unwrap() 156 serde_json::from_slice(&data.await.unwrap()).unwrap()
155} 157}
158
159pub fn extract_current_version(versions: Vec<Version>) -> Result<String, Box<dyn std::error::Error>> {
160 match versions.len() {
161 0 => Err(Box::new(Error::new(ErrorKind::NotFound, "NO_VERSIONS_AVAILABLE"))),
162 //TODO compare publish dates
163 1.. => {
164 let mut times: Vec<(String, DateTime<FixedOffset>)> = vec![];
165 for ver in versions {
166 let stamp = DateTime::parse_from_rfc3339(&ver.date_published)?;
167 times.push((ver.id, stamp))
168 }
169 dbg!(&times);
170 times.sort_by_key(|t| t.1);
171 times.reverse();
172 dbg!(&times);
173 println!("CW: {}", times[0].0);
174 Ok(times[0].0.to_string())
175 },
176 _ => panic!("available_versions should never be negative"),
177 }
178}
diff --git a/src/commands/modification.rs b/src/commands/modification.rs
index 43e2180..b90c82c 100644
--- a/src/commands/modification.rs
+++ b/src/commands/modification.rs
@@ -1,6 +1,6 @@
1use std::io::{Error, ErrorKind}; 1use std::io::{Error, ErrorKind};
2 2
3use crate::{modrinth::{project, versions, Version}, config::Cfg, db::{insert_mod, remove_mod_from_list, get_mod_id, insert_mod_in_list, get_mods, get_mods_from_list}, input::Input, get_current_list}; 3use crate::{modrinth::{project, versions, extract_current_version}, config::Cfg, db::{insert_mod, remove_mod_from_list, get_mod_id, insert_mod_in_list, get_mods, get_mods_from_list}, input::Input, get_current_list};
4 4
5pub async fn modification(config: Cfg, args: Option<Vec<String>>) -> Result<(), Box<dyn std::error::Error>> { 5pub async fn modification(config: Cfg, args: Option<Vec<String>>) -> Result<(), Box<dyn std::error::Error>> {
6 6
@@ -77,12 +77,3 @@ fn remove(config: Cfg, args: Vec<String>) -> Result<(), Box<dyn std::error::Erro
77 Ok(()) => Ok(()), 77 Ok(()) => Ok(()),
78 } 78 }
79} 79}
80
81fn extract_current_version(versions: Vec<Version>) -> Result<String, Box<dyn std::error::Error>> {
82 match versions.len() {
83 0 => Err(Box::new(Error::new(ErrorKind::NotFound, "NO_VERSIONS_AVAILABLE"))),
84 //TODO compare publish dates
85 1.. => Ok(versions[0].id.to_string()),
86 _ => panic!("available_versions should never be negative"),
87 }
88}
diff --git a/src/commands/update.rs b/src/commands/update.rs
index 14c37ec..6275bce 100644
--- a/src/commands/update.rs
+++ b/src/commands/update.rs
@@ -1,40 +1,138 @@
1use std::io::{Error, ErrorKind}; 1use std::{io::{Error, ErrorKind, Write}, fs::File};
2 2
3use crate::{config::Cfg, modrinth::projects, get_current_list, db::{get_mods_from_list, get_versions}}; 3use reqwest::Client;
4
5use futures_util::StreamExt;
6
7use crate::{config::Cfg, modrinth::{projects, Project, versions, extract_current_version, Version}, get_current_list, db::{get_mods_from_list, get_versions, get_list_version, change_list_versions}, List};
4 8
5pub async fn update(config: Cfg) -> Result<(), Box<dyn std::error::Error>> { 9pub async fn update(config: Cfg) -> Result<(), Box<dyn std::error::Error>> {
6 10
7 let current_list = get_current_list(config.clone())?; 11 let current_list = get_current_list(config.clone())?;
8 12
9 let mods = get_mods_from_list(config.clone(), current_list)?; 13 let mods = get_mods_from_list(config.clone(), current_list.clone())?;
14
15 let mut versions = get_versions(config.clone(), mods.clone())?;
16 versions.sort_by_key(|ver| ver.mod_id.clone());
10 17
11 let mut projects = projects(String::from(&config.apis.modrinth), mods.clone()).await; 18 let mut projects = projects(String::from(&config.apis.modrinth), mods).await;
19 projects.sort_by_key(|pro| pro.id.clone());
12 20
13 let mut versions = get_versions(config, mods)?; 21 let mut updatestack: Vec<Version> = vec![];
22 for (index, project) in projects.into_iter().enumerate() {
23 let current_version = &versions[index];
24
25 let p_id = String::from(&project.id);
26 let v_id = &current_version.mod_id;
27
28 if &p_id != v_id { return Err(Box::new(Error::new(ErrorKind::Other, "SORTING_ERROR"))) };
29
30 if project.versions.join("|") != current_version.versions {
31 updatestack.push(match specific_update(config.clone(), current_list.clone(), project).await {
32 Ok(ver) => ver,
33 //TODO handle errors (only continue on "NO_UPDATE_AVAILABLE")
34 Err(_) => { continue; },
35 });
36 };
37 };
38 //println!("{:?}", updatestack);
39
40 //download_updates(config, updatestack).await?;
41
42 Ok(())
43}
44
45async fn specific_update(config: Cfg, list: List, project: Project) -> Result<Version, Box<dyn std::error::Error>> {
46 print!("Checking update for '{}' in {}", project.title, list.id);
14 47
15 projects.sort_by_key(|p| p.id.clone()); 48 let applicable_versions = versions(String::from(&config.apis.modrinth), String::from(&project.id), list.clone()).await;
49
50 let mut versions: Vec<String> = vec![];
16 51
17 versions.sort_by_key(|v| v.mod_id.clone()); 52 for ver in &applicable_versions {
53 versions.push(String::from(&ver.id));
54 }
18 55
19 let mut update_stack: Vec<String> = vec![]; 56 let mut current: Vec<Version> = vec![];
57 if versions.join("|") != get_list_version(config.clone(), list.clone(), String::from(&project.id))? {
58 //get new versions
59 print!(" | getting new version");
60 let current_str = extract_current_version(applicable_versions.clone())?;
61 current.push(applicable_versions.into_iter().find(|ver| ver.id == current_str).unwrap());
62 change_list_versions(config, list, current_str, versions, project.id)?;
63 }
20 64
21 for (index, project) in projects.iter().enumerate() { 65 if current.is_empty() { return Err(Box::new(Error::new(ErrorKind::NotFound, "NO_UPDATE_AVAILABLE"))) };
66
67 println!(" | ✔️");
68 Ok(current[0].clone())
69}
22 70
23 let cmp_version = &versions[index]; 71async fn download_updates(config: Cfg, versions: Vec<Version>) -> Result<String, Box<dyn std::error::Error>> {
24 72
25 let p_id = &project.id; 73 let dl_path = String::from(&config.downloads);
26 let v_id = &cmp_version.mod_id;
27 74
28 if p_id != v_id { return Err(Box::new(Error::new(ErrorKind::Other, "COMPARE_SORTING_ERR"))); }; 75 for ver in versions {
29 println!("{}:{}", p_id, v_id); 76 let primary_file = ver.files.into_iter().find(|file| file.primary).unwrap();
77 let dl_path_file = format!("{}/{}", config.downloads, primary_file.filename);
78 println!("Downloading {}", primary_file.url);
30 79
31 if project.versions.join("|") != cmp_version.versions { 80 let res = Client::new()
32 update_stack.push(String::from(&project.id)); 81 .get(String::from(&primary_file.url))
33 }; 82 .send()
34 }; 83 .await
84 .or(Err(format!("Failed to GET from '{}'", &primary_file.url)))?;
85
86 // download chunks
87 let mut file = File::create(String::from(&dl_path_file)).or(Err(format!("Failed to create file '{}'", dl_path_file)))?;
88 let mut stream = res.bytes_stream();
35 89
36 //TODO UPDATE 90 while let Some(item) = stream.next().await {
37 dbg!(update_stack); 91 let chunk = item.or(Err("Error while downloading file"))?;
92 file.write_all(&chunk)
93 .or(Err("Error while writing to file"))?;
94 }
95 }
38 96
39 Ok(()) 97 Ok(dl_path)
98}
99
100#[tokio::test]
101async fn download_updates_test() {
102
103 use crate::{modrinth::{Version, VersionFile, Hash, VersionType}, config::{Cfg, Apis}};
104
105 let config = Cfg { data: "...".to_string(), clean_remove: false, downloads: "./dl".to_string(), apis: Apis { modrinth: "...".to_string() } };
106
107 let versions = vec![Version {
108 id: "dEqtGnT9".to_string(),
109 project_id: "kYuIpRLv".to_string(),
110 author_id: "Qnt13hO8".to_string(),
111 featured: true,
112 name: "1.2.2-1.19 - Fabric".to_string(),
113 version_number: "1.2.2-1.19".to_string(),
114 changelog: None,
115 date_published: "2022-11-02T17:41:43.072267Z".to_string(),
116 downloads: 58,
117 version_type: VersionType::release,
118 files: vec![VersionFile {
119 hashes: Hash {
120 sha1: "fdc6dc39427fc92cc1d7ad8b275b5b83325e712b".to_string(),
121 sha512: "5b372f00d6e5d6a5ef225c3897826b9f6a2be5506905f7f71b9e939779765b41be6f2a9b029cfc752ad0751d0d2d5f8bb4544408df1363eebdde15641e99a849".to_string()
122 },
123 url: "https://cdn.modrinth.com/data/kYuIpRLv/versions/dEqtGnT9/waveycapes-fabric-1.2.2-mc1.19.2.jar".to_string(),
124 filename: "waveycapes-fabric-1.2.2-mc1.19.2.jar".to_string(),
125 primary: true,
126 size: 323176
127 }],
128 game_versions: vec![
129 "1.19".to_string(),
130 "1.19.1".to_string(),
131 "1.19.2".to_string()
132 ],
133 loaders: vec![
134 "fabric".to_string()
135 ]
136 }];
137 assert_eq!(download_updates(config, versions).await.unwrap(), "./dl")
40} 138}
diff --git a/src/config.rs b/src/config.rs
index 58d399a..ad59963 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -4,6 +4,7 @@ use serde::Deserialize;
4#[derive(Debug, Clone, Deserialize)] 4#[derive(Debug, Clone, Deserialize)]
5pub struct Cfg { 5pub struct Cfg {
6 pub data: String, 6 pub data: String,
7 pub downloads: String,
7 pub clean_remove: bool, 8 pub clean_remove: bool,
8 pub apis: Apis, 9 pub apis: Apis,
9} 10}
diff --git a/src/db.rs b/src/db.rs
index 33d8344..497cc15 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -2,7 +2,7 @@ use std::io::ErrorKind;
2 2
3use crate::{Modloader, config::Cfg, List, modrinth::Version, get_modloader}; 3use crate::{Modloader, config::Cfg, List, modrinth::Version, get_modloader};
4 4
5//TODO use prepared statements 5//TODO use prepared statements / change to rusqlite
6 6
7//MODS 7//MODS
8pub fn insert_mod(config: Cfg, id: String, name: String, versions: Vec<String>) -> Result<(), sqlite::Error> { 8pub fn insert_mod(config: Cfg, id: String, name: String, versions: Vec<String>) -> Result<(), sqlite::Error> {
@@ -151,6 +151,27 @@ pub fn get_versions(config: Cfg, mods: Vec<String>) -> Result<Vec<DBModlistVersi
151 Ok(versionmaps) 151 Ok(versionmaps)
152} 152}
153 153
154pub fn get_list_version(config: Cfg, list: List, mod_id: String) -> Result<String, Box<dyn std::error::Error>> {
155 let data = format!("{}/data.db", config.data);
156 let connection = sqlite::open(data).unwrap();
157
158 let sql = format!("SELECT applicable_versions FROM {} WHERE mod_id = '{}'", list.id, mod_id);
159
160 //TODO catch sql errors better
161 let mut version: String = String::new();
162 connection.iterate(sql, |ver| {
163 if ver.is_empty() { return false; };
164 for &(_column, value) in ver.iter() {
165 version = String::from(value.unwrap());
166 }
167 true
168 }).unwrap();
169
170 if version.is_empty() { return Err(Box::new(std::io::Error::new(ErrorKind::Other, "NO_MODS_ON_LIST"))); };
171
172 Ok(version)
173}
174
154 175
155//LIST 176//LIST
156pub fn insert_list(config: Cfg, id: String, mc_version: String, mod_loader: Modloader) -> Result<(), sqlite::Error> { 177pub fn insert_list(config: Cfg, id: String, mc_version: String, mod_loader: Modloader) -> Result<(), sqlite::Error> {
@@ -217,6 +238,15 @@ pub fn get_list(config: Cfg, id: String) -> Result<List, Box<dyn std::error::Err
217 Ok(List { id, mc_version: String::from(&list[0]), modloader: get_modloader(String::from(&list[1]))? }) 238 Ok(List { id, mc_version: String::from(&list[0]), modloader: get_modloader(String::from(&list[1]))? })
218} 239}
219 240
241pub fn change_list_versions(config: Cfg, list: List, current_version: String, versions: Vec<String>, mod_id: String) -> Result<(), sqlite::Error> {
242 let data = format!("{}/data.db", config.data);
243 let connection = sqlite::open(data).unwrap();
244
245 let sql = format!("UPDATE {} SET current_version = '{}', applicable_versions = '{}' WHERE mod_id = '{}'", list.id, current_version, versions.join("|"), mod_id);
246
247 connection.execute(sql)
248}
249
220//config 250//config
221pub fn change_list(config: Cfg, id: String) -> Result<(), sqlite::Error> { 251pub fn change_list(config: Cfg, id: String) -> Result<(), sqlite::Error> {
222 let data = format!("{}/data.db", config.data); 252 let data = format!("{}/data.db", config.data);
diff --git a/src/input.rs b/src/input.rs
index 0c13e67..e0c9ae9 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -1,6 +1,7 @@
1use std::io::{stdin, Error, ErrorKind}; 1use std::io::{stdin, Error, ErrorKind};
2use crate::{config::Cfg, list, modification, update}; 2use crate::{config::Cfg, list, modification, update};
3 3
4#[derive(Debug, PartialEq, Eq)]
4pub struct Input { 5pub struct Input {
5 pub command: String, 6 pub command: String,
6 pub args: Option<Vec<String>>, 7 pub args: Option<Vec<String>>,
@@ -27,8 +28,6 @@ impl Input {
27 }, 28 },
28 _ => { panic!("This should never happen") } 29 _ => { panic!("This should never happen") }
29 } 30 }
30
31
32 } 31 }
33} 32}
34 33
@@ -53,3 +52,10 @@ pub async fn get_input(config: Cfg) -> Result<(), Box<dyn std::error::Error>> {
53 _ => Err(Box::new(Error::new(ErrorKind::InvalidInput, "UNKNOWN_COMMAND"))), 52 _ => Err(Box::new(Error::new(ErrorKind::InvalidInput, "UNKNOWN_COMMAND"))),
54 } 53 }
55} 54}
55
56#[test]
57fn input_from() {
58 let string = String::from("list add test 1.19.2 fabric");
59 let input = Input { command: String::from("list"), args: Some(vec![String::from("add"), String::from("test"), String::from("1.19.2"), String::from("fabric")]) };
60 assert_eq!(Input::from(string).unwrap(), input);
61}
diff --git a/tests/db/mod.rs b/tests/db/mod.rs
index b5aed75..50e6887 100644
--- a/tests/db/mod.rs
+++ b/tests/db/mod.rs
@@ -1,5 +1,3 @@
1use std::fs::File;
2
3pub fn setup() { 1pub fn setup() {
4 File::create("./setuptests").unwrap(); 2 //File::create("./setuptests").unwrap();
5} 3}
diff --git a/tests/db_integration.rs b/tests/db_integration.rs
index 82cfe0f..f580595 100644
--- a/tests/db_integration.rs
+++ b/tests/db_integration.rs
@@ -3,5 +3,4 @@ mod db;
3#[test] 3#[test]
4fn test_add() { 4fn test_add() {
5 db::setup(); 5 db::setup();
6 assert!(true);
7} 6}