summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorfx <[email protected]>2023-04-27 10:10:03 +0200
committerfx <[email protected]>2023-04-27 10:10:03 +0200
commit43ca5fec20933fc31dfe7d7dbd1f1b9258612219 (patch)
treeeef58fecfadad90386b38af581abab8cc3d3cfc0 /src
parent4300ad2eb05dddfa4274e04b204f2ad28c87da05 (diff)
parent4e6466af1329f7b9e341df2e76ab696d11f80c93 (diff)
downloadmodlist-43ca5fec20933fc31dfe7d7dbd1f1b9258612219.tar
modlist-43ca5fec20933fc31dfe7d7dbd1f1b9258612219.tar.gz
modlist-43ca5fec20933fc31dfe7d7dbd1f1b9258612219.zip
Merge pull request 'cache' (#3) from cache into master
Reviewed-on: http://raspberrypi.fritz.box:7920/fx/modlist/pulls/3
Diffstat (limited to 'src')
-rw-r--r--src/cache.rs37
-rw-r--r--src/commands/download.rs2
-rw-r--r--src/commands/io.rs5
-rw-r--r--src/commands/mod.rs2
-rw-r--r--src/commands/setup.rs70
-rw-r--r--src/commands/update.rs98
-rw-r--r--src/config.rs84
-rw-r--r--src/db.rs70
-rw-r--r--src/files.rs72
-rw-r--r--src/lib.rs17
-rw-r--r--src/main.rs26
11 files changed, 255 insertions, 228 deletions
diff --git a/src/cache.rs b/src/cache.rs
new file mode 100644
index 0000000..11645d1
--- /dev/null
+++ b/src/cache.rs
@@ -0,0 +1,37 @@
1use std::{
2 collections::HashMap,
3 fs::{copy, read_dir},
4};
5
6/// .
7///
8/// # Panics
9///
10/// Panics if .
11pub fn get_cached_versions(path: &str) -> HashMap<String, String> {
12 let mut versions: HashMap<String, String> = HashMap::new();
13 for file in read_dir(path).unwrap() {
14 let path = file.unwrap().path();
15 if path.is_file() && path.extension().ok_or("BAH").unwrap() == "jar" {
16 let pathstr = path.to_str().ok_or("BAH").unwrap();
17 let namesplit: Vec<&str> = pathstr.split('.').collect();
18 versions.insert(
19 String::from(namesplit[namesplit.len() - 2]),
20 String::from(pathstr),
21 );
22 }
23 }
24 versions
25}
26
27/// .
28///
29/// # Panics
30///
31/// Panics if .
32pub fn copy_cached_version(version_path: &str, download_path: &str) {
33 let versplit: Vec<&str> = version_path.split('/').collect();
34 let download = format!("{}{}", download_path, versplit[versplit.len() - 1]);
35 // println!("{:#?}", download);
36 copy(version_path, download).unwrap();
37}
diff --git a/src/commands/download.rs b/src/commands/download.rs
index 9434591..1a8eb8f 100644
--- a/src/commands/download.rs
+++ b/src/commands/download.rs
@@ -23,7 +23,7 @@ pub async fn download(config: Cfg, all_lists: bool, clean: bool, delete_old: boo
23 23
24 for current_list in liststack { 24 for current_list in liststack {
25 let downloaded_versions = get_downloaded_versions(current_list.clone())?; 25 let downloaded_versions = get_downloaded_versions(current_list.clone())?;
26 println!("To download: {:#?}", downloaded_versions); 26 // println!("To download: {:#?}", downloaded_versions);
27 let current_version_ids = match userlist_get_all_current_versions_with_mods( 27 let current_version_ids = match userlist_get_all_current_versions_with_mods(
28 config.clone(), 28 config.clone(),
29 String::from(&current_list.id), 29 String::from(&current_list.id),
diff --git a/src/commands/io.rs b/src/commands/io.rs
index 7f03eec..82b30ce 100644
--- a/src/commands/io.rs
+++ b/src/commands/io.rs
@@ -5,7 +5,6 @@ use std::io::prelude::*;
5use crate::{ 5use crate::{
6 config::Cfg, 6 config::Cfg,
7 db::{lists_get, lists_get_all_ids, lists_insert, userlist_get_all_ids}, 7 db::{lists_get, lists_get_all_ids, lists_insert, userlist_get_all_ids},
8 devdir,
9 error::MLE, 8 error::MLE,
10 mod_add, IDSelector, List, Modloader, 9 mod_add, IDSelector, List, Modloader,
11}; 10};
@@ -61,9 +60,7 @@ pub fn export(config: Cfg, list: Option<String>) -> MLE<()> {
61 60
62 let filestr = dirs::home_dir().unwrap().join("mlexport.toml"); 61 let filestr = dirs::home_dir().unwrap().join("mlexport.toml");
63 62
64 let mut file = File::create(devdir( 63 let mut file = File::create(filestr.into_os_string().into_string().unwrap().as_str())?;
65 filestr.into_os_string().into_string().unwrap().as_str(),
66 ))?;
67 file.write_all(toml.as_bytes())?; 64 file.write_all(toml.as_bytes())?;
68 65
69 Ok(()) 66 Ok(())
diff --git a/src/commands/mod.rs b/src/commands/mod.rs
index 1c7c012..0f13056 100644
--- a/src/commands/mod.rs
+++ b/src/commands/mod.rs
@@ -2,12 +2,10 @@ pub mod download;
2pub mod io; 2pub mod io;
3pub mod list; 3pub mod list;
4pub mod modification; 4pub mod modification;
5pub mod setup;
6pub mod update; 5pub mod update;
7 6
8pub use download::*; 7pub use download::*;
9pub use io::*; 8pub use io::*;
10pub use list::*; 9pub use list::*;
11pub use modification::*; 10pub use modification::*;
12pub use setup::*;
13pub use update::*; 11pub use update::*;
diff --git a/src/commands/setup.rs b/src/commands/setup.rs
deleted file mode 100644
index 40e8c0a..0000000
--- a/src/commands/setup.rs
+++ /dev/null
@@ -1,70 +0,0 @@
1use std::{fs::File, path::Path};
2
3use crate::{config::Cfg, db::db_setup, devdir, error::MLE};
4
5pub async fn setup(config: Cfg) -> MLE<()> {
6 let db_file = devdir(format!("{}/data.db", config.data).as_str());
7
8 if !Path::new(&db_file).exists() {
9 create(config, db_file)?;
10 }
11
12 /*
13 match s_config_get_version(config.clone()) {
14 Ok(ver) => {
15 match ver.as_str() {
16 "0.2" => to_03(config)?,
17 "0.3" => to_04(config)?,
18 _ => return Err(MLError::new(ErrorType::Other, "UNKNOWN_VERSION"))
19 }
20 },
21 Err(..) => to_02(config).await?
22 };
23 */
24
25 Ok(())
26}
27
28fn create(config: Cfg, db_file: String) -> MLE<()> {
29 println!("Create database");
30
31 File::create(db_file)?;
32 db_setup(config)?;
33 Ok(())
34}
35
36//async fn to_02(config: Cfg) -> Result<(), Box<dyn std::error::Error>> {
37// let lists = lists_get_all_ids(config.clone())?;
38//
39// for list in lists {
40// println!("Updating {}", list);
41// s_insert_column(config.clone(), String::from(&list), String::from("current_download"), String::from("TEXT"), None)?;
42//
43// let full_list = lists_get(config.clone(), String::from(&list))?;
44//
45// let versions = userlist_get_all_current_version_ids(config.clone(), full_list.clone().id)?;
46//
47// let raw_versions = get_raw_versions(String::from(&config.apis.modrinth), versions).await;
48//
49// for ver in raw_versions {
50// println!("Adding link for {}", ver.project_id);
51// let file = ver.files.into_iter().find(|f| f.primary).unwrap();
52// s_userlist_update_download(config.clone(), String::from(&full_list.id), ver.project_id, file.url)?;
53// }
54// };
55// s_config_create_version(config)?;
56//
57// Ok(())
58//}
59//
60//fn to_03(config: Cfg) -> Result<(), Box<dyn std::error::Error>> {
61// s_insert_column(config.clone(), String::from("lists"), String::from("download_folder"), String::from("TEXT"), None)?;
62// s_config_update_version(config, String::from("0.3"))
63//}
64//
65//fn to_04(config: Cfg) -> Result<(), Box<dyn std::error::Error>> {
66// for list_id in lists_get_all_ids(config.clone())? {
67// s_insert_column(config.clone(), list_id, String::from("disabled_versions"), String::from("TEXT"), Some(String::from("NONE")))?;
68// }
69// s_config_update_version(config, String::from("0.4"))
70//}
diff --git a/src/commands/update.rs b/src/commands/update.rs
index 3d9578b..4bc3ac0 100644
--- a/src/commands/update.rs
+++ b/src/commands/update.rs
@@ -156,52 +156,52 @@ async fn specific_update(config: Cfg, clean: bool, list: List, id: String) -> ML
156 Ok(current[0].clone()) 156 Ok(current[0].clone())
157} 157}
158 158
159#[tokio::test] 159// #[tokio::test]
160async fn download_updates_test() { 160// async fn download_updates_test() {
161 use crate::{ 161// use crate::{
162 modrinth::{Hash, Version, VersionFile, VersionType}, 162// modrinth::{Hash, Version, VersionFile, VersionType},
163 List, Modloader, 163// List, Modloader,
164 }; 164// };
165 165//
166 let config = Cfg::init("modlist.toml").unwrap(); 166// let config = Cfg::init().unwrap();
167 let current_list = List { 167// let current_list = List {
168 id: String::from("..."), 168// id: String::from("..."),
169 mc_version: String::from("..."), 169// mc_version: String::from("..."),
170 modloader: Modloader::Fabric, 170// modloader: Modloader::Fabric,
171 download_folder: String::from("./dev/tests/dl"), 171// download_folder: String::from("./dev/tests/dl"),
172 }; 172// };
173 173//
174 let versions = vec![Version { 174// let versions = vec![Version {
175 id: "dEqtGnT9".to_string(), 175// id: "dEqtGnT9".to_string(),
176 project_id: "kYuIpRLv".to_string(), 176// project_id: "kYuIpRLv".to_string(),
177 author_id: "Qnt13hO8".to_string(), 177// author_id: "Qnt13hO8".to_string(),
178 featured: true, 178// featured: true,
179 name: "1.2.2-1.19 - Fabric".to_string(), 179// name: "1.2.2-1.19 - Fabric".to_string(),
180 version_number: "1.2.2-1.19".to_string(), 180// version_number: "1.2.2-1.19".to_string(),
181 changelog: None, 181// changelog: None,
182 date_published: "2022-11-02T17:41:43.072267Z".to_string(), 182// date_published: "2022-11-02T17:41:43.072267Z".to_string(),
183 downloads: 58, 183// downloads: 58,
184 version_type: VersionType::release, 184// version_type: VersionType::release,
185 files: vec![VersionFile { 185// files: vec![VersionFile {
186 hashes: Hash { 186// hashes: Hash {
187 sha1: "fdc6dc39427fc92cc1d7ad8b275b5b83325e712b".to_string(), 187// sha1: "fdc6dc39427fc92cc1d7ad8b275b5b83325e712b".to_string(),
188 sha512: "5b372f00d6e5d6a5ef225c3897826b9f6a2be5506905f7f71b9e939779765b41be6f2a9b029cfc752ad0751d0d2d5f8bb4544408df1363eebdde15641e99a849".to_string() 188// sha512: "5b372f00d6e5d6a5ef225c3897826b9f6a2be5506905f7f71b9e939779765b41be6f2a9b029cfc752ad0751d0d2d5f8bb4544408df1363eebdde15641e99a849".to_string()
189 }, 189// },
190 url: "https://cdn.modrinth.com/data/kYuIpRLv/versions/dEqtGnT9/waveycapes-fabric-1.2.2-mc1.19.2.jar".to_string(), 190// url: "https://cdn.modrinth.com/data/kYuIpRLv/versions/dEqtGnT9/waveycapes-fabric-1.2.2-mc1.19.2.jar".to_string(),
191 filename: "waveycapes-fabric-1.2.2-mc1.19.2.jar".to_string(), 191// filename: "waveycapes-fabric-1.2.2-mc1.19.2.jar".to_string(),
192 primary: true, 192// primary: true,
193 size: 323176 193// size: 323176
194 }], 194// }],
195 game_versions: vec![ 195// game_versions: vec![
196 "1.19".to_string(), 196// "1.19".to_string(),
197 "1.19.1".to_string(), 197// "1.19.1".to_string(),
198 "1.19.2".to_string() 198// "1.19.2".to_string()
199 ], 199// ],
200 loaders: vec![ 200// loaders: vec![
201 "fabric".to_string() 201// "fabric".to_string()
202 ] 202// ]
203 }]; 203// }];
204 assert!(download_versions(current_list, config, versions) 204// assert!(download_versions(current_list, config, versions)
205 .await 205// .await
206 .is_ok()) 206// .is_ok())
207} 207// }
diff --git a/src/config.rs b/src/config.rs
index 1b54d5f..61db1c7 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,15 +1,17 @@
1use std::{ 1use std::{
2 fs::File, 2 fs::{create_dir_all, File},
3 io::{Read, Write}, 3 io::{Read, Write},
4 path::Path,
4}; 5};
5 6
6use serde::{Deserialize, Serialize}; 7use serde::{Deserialize, Serialize};
7 8
8use crate::{devdir, error::MLE}; 9use crate::{db::db_setup, error::MLE};
9 10
10#[derive(Debug, Clone, Serialize, Deserialize)] 11#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct Cfg { 12pub struct Cfg {
12 pub data: String, 13 pub data: String,
14 pub cache: String,
13 pub apis: Apis, 15 pub apis: Apis,
14} 16}
15 17
@@ -19,24 +21,22 @@ pub struct Apis {
19} 21}
20 22
21impl Cfg { 23impl Cfg {
22 pub fn init(filename: &str) -> MLE<Self> { 24 pub fn init(path: Option<String>) -> MLE<Self> {
23 let configfile = dirs::config_dir().unwrap().join(filename); 25 let configfile = match path.clone() {
26 Some(p) => String::from(p),
27 None => dirs::config_dir()
28 .unwrap()
29 .join("modlist.toml")
30 .to_string_lossy()
31 .to_string(),
32 };
24 33
25 let mut file = match File::open(devdir(configfile.to_str().unwrap())) { 34 let mut file = match File::open(&configfile) {
26 Ok(file) => file, 35 Ok(file) => file,
27 Err(err) => { 36 Err(err) => {
28 if err.kind() == std::io::ErrorKind::NotFound { 37 if err.kind() == std::io::ErrorKind::NotFound && path.is_none() {
29 println!("No config file found, creating one"); 38 create_config(&configfile)?;
30 let default_cfg = Cfg { 39 File::open(&configfile)?
31 data: String::from("./"),
32 apis: Apis {
33 modrinth: String::from("https://api.modrinth.com/v2/"),
34 },
35 };
36 let mut file = File::create(devdir(configfile.to_str().unwrap()))?;
37 println!("Created config file");
38 file.write_all(toml::to_string(&default_cfg)?.as_bytes())?;
39 File::open(devdir(configfile.to_str().unwrap()))?
40 } else { 40 } else {
41 return Err(err.into()); 41 return Err(err.into());
42 } 42 }
@@ -45,6 +45,56 @@ impl Cfg {
45 let mut content = String::new(); 45 let mut content = String::new();
46 file.read_to_string(&mut content)?; 46 file.read_to_string(&mut content)?;
47 let config = toml::from_str::<Cfg>(&content)?; 47 let config = toml::from_str::<Cfg>(&content)?;
48 //Check cache
49 if !Path::new(&config.cache).exists() {
50 create_cache(&config.cache)?;
51 };
52 //Check database
53 //TODO check file
54 let datafile = format!("{}/data.db", config.data);
55 match File::open(&datafile) {
56 Ok(..) => (),
57 Err(..) => create_database(&datafile)?,
58 };
48 Ok(config) 59 Ok(config)
49 } 60 }
50} 61}
62
63fn create_config(path: &str) -> MLE<()> {
64 print!("No config file found, create default");
65 //Force flush of stdout, else print! doesn't print instantly
66 std::io::stdout().flush()?;
67 let default_cfg = Cfg {
68 //TODO get home dir
69 data: String::from("$HOME/.cache/modlist/"),
70 cache: String::from("$HOME/.cache/modlist/cache"),
71 apis: Apis {
72 modrinth: String::from("https://api.modrinth.com/v2/"),
73 },
74 };
75 let mut file = File::create(path)?;
76 file.write_all(toml::to_string(&default_cfg)?.as_bytes())?;
77 println!(" ✓");
78 Ok(())
79}
80
81fn create_database(path: &str) -> MLE<()> {
82 print!("No database found, create base");
83 //Force flush of stdout, else print! doesn't print instantly
84 std::io::stdout().flush()?;
85
86 File::create(path)?;
87 db_setup(path)?;
88 println!(" ✓");
89 Ok(())
90}
91
92fn create_cache(path: &str) -> MLE<()> {
93 print!("No cache direcory found, create one");
94 //Force flush of stdout, else print! doesn't print instantly
95 std::io::stdout().flush()?;
96
97 create_dir_all(path)?;
98 println!(" ✓");
99 Ok(())
100}
diff --git a/src/db.rs b/src/db.rs
index 09d54c2..abfe1dd 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -4,14 +4,13 @@ use rusqlite::Connection;
4 4
5use crate::{ 5use crate::{
6 config::Cfg, 6 config::Cfg,
7 devdir,
8 error::{ErrorType, MLError, MLE}, 7 error::{ErrorType, MLError, MLE},
9 List, Modloader, 8 List, Modloader,
10}; 9};
11 10
12//MODS 11//MODS
13pub fn mods_insert(config: Cfg, id: &str, slug: &str, name: &str) -> MLE<()> { 12pub fn mods_insert(config: Cfg, id: &str, slug: &str, name: &str) -> MLE<()> {
14 let data = devdir(format!("{}/data.db", config.data).as_str()); 13 let data = format!("{}/data.db", config.data);
15 let connection = Connection::open(data)?; 14 let connection = Connection::open(data)?;
16 15
17 connection.execute( 16 connection.execute(
@@ -23,7 +22,7 @@ pub fn mods_insert(config: Cfg, id: &str, slug: &str, name: &str) -> MLE<()> {
23} 22}
24 23
25pub fn mods_get_all_ids(config: Cfg) -> Result<Vec<String>, Box<dyn std::error::Error>> { 24pub fn mods_get_all_ids(config: Cfg) -> Result<Vec<String>, Box<dyn std::error::Error>> {
26 let data = devdir(format!("{}/data.db", config.data).as_str()); 25 let data = format!("{}/data.db", config.data);
27 let connection = Connection::open(data).unwrap(); 26 let connection = Connection::open(data).unwrap();
28 27
29 let mut mods: Vec<String> = Vec::new(); 28 let mut mods: Vec<String> = Vec::new();
@@ -53,7 +52,7 @@ pub fn mods_get_all_ids(config: Cfg) -> Result<Vec<String>, Box<dyn std::error::
53pub fn mods_get_id(data: &str, slug: &str) -> MLE<String> { 52pub fn mods_get_id(data: &str, slug: &str) -> MLE<String> {
54 //TODO check if "slug" is id 53 //TODO check if "slug" is id
55 54
56 let data = devdir(format!("{}/data.db", data).as_str()); 55 let data = format!("{}/data.db", data);
57 let connection = Connection::open(data)?; 56 let connection = Connection::open(data)?;
58 57
59 let mut mod_id = String::new(); 58 let mut mod_id = String::new();
@@ -88,7 +87,7 @@ pub struct ModInfo {
88} 87}
89 88
90pub fn mods_get_info(config: Cfg, id: &str) -> MLE<ModInfo> { 89pub fn mods_get_info(config: Cfg, id: &str) -> MLE<ModInfo> {
91 let data = devdir(format!("{}/data.db", config.data).as_str()); 90 let data = format!("{}/data.db", config.data);
92 let connection = Connection::open(data)?; 91 let connection = Connection::open(data)?;
93 92
94 let mut mod_info: Option<ModInfo> = None; 93 let mut mod_info: Option<ModInfo> = None;
@@ -117,7 +116,7 @@ pub fn mods_get_info(config: Cfg, id: &str) -> MLE<ModInfo> {
117pub fn mods_remove(config: Cfg, id: String) -> MLE<()> { 116pub fn mods_remove(config: Cfg, id: String) -> MLE<()> {
118 println!("Removing mod {} from database", id); 117 println!("Removing mod {} from database", id);
119 118
120 let data = devdir(format!("{}/data.db", config.data).as_str()); 119 let data = format!("{}/data.db", config.data);
121 let connection = Connection::open(data)?; 120 let connection = Connection::open(data)?;
122 121
123 connection.execute("DELETE FROM mods WHERE id = ?", [id])?; 122 connection.execute("DELETE FROM mods WHERE id = ?", [id])?;
@@ -132,7 +131,7 @@ pub struct DBModlistVersions {
132} 131}
133 132
134pub fn mods_get_versions(config: Cfg, mods: Vec<String>) -> MLE<Vec<DBModlistVersions>> { 133pub fn mods_get_versions(config: Cfg, mods: Vec<String>) -> MLE<Vec<DBModlistVersions>> {
135 let data = devdir(format!("{}/data.db", config.data).as_str()); 134 let data = format!("{}/data.db", config.data);
136 let connection = Connection::open(data)?; 135 let connection = Connection::open(data)?;
137 136
138 if mods.is_empty() { 137 if mods.is_empty() {
@@ -188,7 +187,7 @@ pub fn userlist_insert(
188 current_link: &str, 187 current_link: &str,
189 set_version: bool, 188 set_version: bool,
190) -> MLE<()> { 189) -> MLE<()> {
191 let data = devdir(format!("{}/data.db", config.data).as_str()); 190 let data = format!("{}/data.db", config.data);
192 let connection = Connection::open(data)?; 191 let connection = Connection::open(data)?;
193 192
194 let sv = match set_version { 193 let sv = match set_version {
@@ -215,7 +214,7 @@ pub fn userlist_insert(
215} 214}
216 215
217pub fn userlist_get_all_ids(config: Cfg, list_id: String) -> MLE<Vec<String>> { 216pub fn userlist_get_all_ids(config: Cfg, list_id: String) -> MLE<Vec<String>> {
218 let data = devdir(format!("{}/data.db", config.data).as_str()); 217 let data = format!("{}/data.db", config.data);
219 let connection = Connection::open(data).unwrap(); 218 let connection = Connection::open(data).unwrap();
220 219
221 let mut mod_ids: Vec<String> = Vec::new(); 220 let mut mod_ids: Vec<String> = Vec::new();
@@ -234,7 +233,7 @@ pub fn userlist_get_all_ids(config: Cfg, list_id: String) -> MLE<Vec<String>> {
234} 233}
235 234
236pub fn userlist_remove(config: Cfg, list_id: &str, mod_id: &str) -> MLE<()> { 235pub fn userlist_remove(config: Cfg, list_id: &str, mod_id: &str) -> MLE<()> {
237 let data = devdir(format!("{}/data.db", config.data).as_str()); 236 let data = format!("{}/data.db", config.data);
238 let connection = Connection::open(data)?; 237 let connection = Connection::open(data)?;
239 238
240 connection.execute( 239 connection.execute(
@@ -249,7 +248,7 @@ pub fn userlist_get_applicable_versions(
249 list_id: String, 248 list_id: String,
250 mod_id: String, 249 mod_id: String,
251) -> MLE<String> { 250) -> MLE<String> {
252 let data = devdir(format!("{}/data.db", config.data).as_str()); 251 let data = format!("{}/data.db", config.data);
253 let connection = Connection::open(data).unwrap(); 252 let connection = Connection::open(data).unwrap();
254 253
255 let mut version: String = String::new(); 254 let mut version: String = String::new();
@@ -276,7 +275,7 @@ pub fn userlist_get_all_applicable_versions_with_mods(
276 config: Cfg, 275 config: Cfg,
277 list_id: String, 276 list_id: String,
278) -> MLE<Vec<(String, String)>> { 277) -> MLE<Vec<(String, String)>> {
279 let data = devdir(format!("{}/data.db", config.data).as_str()); 278 let data = format!("{}/data.db", config.data);
280 let connection = Connection::open(data)?; 279 let connection = Connection::open(data)?;
281 280
282 let mut versions: Vec<(String, String)> = Vec::new(); 281 let mut versions: Vec<(String, String)> = Vec::new();
@@ -302,7 +301,7 @@ pub fn userlist_get_all_applicable_versions_with_mods(
302} 301}
303 302
304pub fn userlist_get_current_version(config: Cfg, list_id: &str, mod_id: &str) -> MLE<String> { 303pub fn userlist_get_current_version(config: Cfg, list_id: &str, mod_id: &str) -> MLE<String> {
305 let data = devdir(format!("{}/data.db", config.data).as_str()); 304 let data = format!("{}/data.db", config.data);
306 let connection = Connection::open(data).unwrap(); 305 let connection = Connection::open(data).unwrap();
307 306
308 let mut version: String = String::new(); 307 let mut version: String = String::new();
@@ -324,7 +323,7 @@ pub fn userlist_get_all_current_version_ids(
324 config: Cfg, 323 config: Cfg,
325 list_id: String, 324 list_id: String,
326) -> Result<Vec<String>, Box<dyn std::error::Error>> { 325) -> Result<Vec<String>, Box<dyn std::error::Error>> {
327 let data = devdir(format!("{}/data.db", config.data).as_str()); 326 let data = format!("{}/data.db", config.data);
328 let connection = Connection::open(data)?; 327 let connection = Connection::open(data)?;
329 328
330 let mut versions: Vec<String> = Vec::new(); 329 let mut versions: Vec<String> = Vec::new();
@@ -350,7 +349,7 @@ pub fn userlist_get_all_current_versions_with_mods(
350 config: Cfg, 349 config: Cfg,
351 list_id: String, 350 list_id: String,
352) -> Result<Vec<(String, String)>, Box<dyn std::error::Error>> { 351) -> Result<Vec<(String, String)>, Box<dyn std::error::Error>> {
353 let data = devdir(format!("{}/data.db", config.data).as_str()); 352 let data = format!("{}/data.db", config.data);
354 let connection = Connection::open(data)?; 353 let connection = Connection::open(data)?;
355 354
356 let mut versions: Vec<(String, String)> = Vec::new(); 355 let mut versions: Vec<(String, String)> = Vec::new();
@@ -379,7 +378,7 @@ pub fn userlist_get_all_current_versions_with_mods(
379} 378}
380 379
381pub fn userlist_get_set_version(config: Cfg, list_id: &str, mod_id: &str) -> MLE<bool> { 380pub fn userlist_get_set_version(config: Cfg, list_id: &str, mod_id: &str) -> MLE<bool> {
382 let data = devdir(format!("{}/data.db", config.data).as_str()); 381 let data = format!("{}/data.db", config.data);
383 let connection = Connection::open(data).unwrap(); 382 let connection = Connection::open(data).unwrap();
384 383
385 let mut set_version: bool = false; 384 let mut set_version: bool = false;
@@ -402,7 +401,7 @@ pub fn userlist_change_versions(
402 link: String, 401 link: String,
403 mod_id: String, 402 mod_id: String,
404) -> MLE<()> { 403) -> MLE<()> {
405 let data = devdir(format!("{}/data.db", config.data).as_str()); 404 let data = format!("{}/data.db", config.data);
406 let connection = Connection::open(data)?; 405 let connection = Connection::open(data)?;
407 406
408 connection.execute(format!("UPDATE {} SET current_version = ?1, applicable_versions = ?2, current_download = ?3 WHERE mod_id = ?4", list_id).as_str(), [current_version, versions, link, mod_id])?; 407 connection.execute(format!("UPDATE {} SET current_version = ?1, applicable_versions = ?2, current_download = ?3 WHERE mod_id = ?4", list_id).as_str(), [current_version, versions, link, mod_id])?;
@@ -415,7 +414,7 @@ pub fn userlist_add_disabled_versions(
415 disabled_version: String, 414 disabled_version: String,
416 mod_id: String, 415 mod_id: String,
417) -> MLE<()> { 416) -> MLE<()> {
418 let data = devdir(format!("{}/data.db", config.data).as_str()); 417 let data = format!("{}/data.db", config.data);
419 let connection = Connection::open(data)?; 418 let connection = Connection::open(data)?;
420 419
421 let currently_disabled_versions = 420 let currently_disabled_versions =
@@ -437,7 +436,7 @@ pub fn userlist_add_disabled_versions(
437} 436}
438 437
439pub fn userlist_get_disabled_versions(config: Cfg, list_id: String, mod_id: String) -> MLE<String> { 438pub fn userlist_get_disabled_versions(config: Cfg, list_id: String, mod_id: String) -> MLE<String> {
440 let data = devdir(format!("{}/data.db", config.data).as_str()); 439 let data = format!("{}/data.db", config.data);
441 let connection = Connection::open(data).unwrap(); 440 let connection = Connection::open(data).unwrap();
442 441
443 let mut version: String = String::new(); 442 let mut version: String = String::new();
@@ -459,7 +458,7 @@ pub fn userlist_get_all_downloads(
459 config: Cfg, 458 config: Cfg,
460 list_id: String, 459 list_id: String,
461) -> Result<Vec<String>, Box<dyn std::error::Error>> { 460) -> Result<Vec<String>, Box<dyn std::error::Error>> {
462 let data = devdir(format!("{}/data.db", config.data).as_str()); 461 let data = format!("{}/data.db", config.data);
463 let connection = Connection::open(data).unwrap(); 462 let connection = Connection::open(data).unwrap();
464 463
465 let mut links: Vec<String> = Vec::new(); 464 let mut links: Vec<String> = Vec::new();
@@ -494,7 +493,7 @@ pub fn lists_insert(
494) -> MLE<()> { 493) -> MLE<()> {
495 println!("Creating list {}", id); 494 println!("Creating list {}", id);
496 495
497 let data = devdir(format!("{}/data.db", config.data).as_str()); 496 let data = format!("{}/data.db", config.data);
498 let connection = Connection::open(data)?; 497 let connection = Connection::open(data)?;
499 498
500 connection.execute( 499 connection.execute(
@@ -512,7 +511,7 @@ pub fn lists_insert(
512} 511}
513 512
514pub fn lists_remove(config: Cfg, id: String) -> MLE<()> { 513pub fn lists_remove(config: Cfg, id: String) -> MLE<()> {
515 let data = devdir(format!("{}/data.db", config.data).as_str()); 514 let data = format!("{}/data.db", config.data);
516 let connection = Connection::open(data)?; 515 let connection = Connection::open(data)?;
517 516
518 connection.execute("DELETE FROM lists WHERE id = ?", [&id])?; 517 connection.execute("DELETE FROM lists WHERE id = ?", [&id])?;
@@ -521,7 +520,7 @@ pub fn lists_remove(config: Cfg, id: String) -> MLE<()> {
521} 520}
522 521
523pub fn lists_get(config: Cfg, list_id: String) -> MLE<List> { 522pub fn lists_get(config: Cfg, list_id: String) -> MLE<List> {
524 let data = devdir(format!("{}/data.db", config.data).as_str()); 523 let data = format!("{}/data.db", config.data);
525 let connection = Connection::open(data).unwrap(); 524 let connection = Connection::open(data).unwrap();
526 525
527 let mut list = List { 526 let mut list = List {
@@ -559,7 +558,7 @@ pub fn lists_get(config: Cfg, list_id: String) -> MLE<List> {
559} 558}
560 559
561pub fn lists_version(config: Cfg, list_id: &str, version: &str) -> MLE<()> { 560pub fn lists_version(config: Cfg, list_id: &str, version: &str) -> MLE<()> {
562 let data = devdir(format!("{}/data.db", config.data).as_str()); 561 let data = format!("{}/data.db", config.data);
563 let connection = Connection::open(data).unwrap(); 562 let connection = Connection::open(data).unwrap();
564 563
565 connection.execute( 564 connection.execute(
@@ -570,7 +569,7 @@ pub fn lists_version(config: Cfg, list_id: &str, version: &str) -> MLE<()> {
570} 569}
571 570
572pub fn lists_get_all_ids(config: Cfg) -> MLE<Vec<String>> { 571pub fn lists_get_all_ids(config: Cfg) -> MLE<Vec<String>> {
573 let data = devdir(format!("{}/data.db", config.data).as_str()); 572 let data = format!("{}/data.db", config.data);
574 let connection = Connection::open(data).unwrap(); 573 let connection = Connection::open(data).unwrap();
575 574
576 let mut list_ids: Vec<String> = Vec::new(); 575 let mut list_ids: Vec<String> = Vec::new();
@@ -589,7 +588,7 @@ pub fn lists_get_all_ids(config: Cfg) -> MLE<Vec<String>> {
589 588
590//config 589//config
591pub fn config_change_current_list(config: Cfg, id: String) -> MLE<()> { 590pub fn config_change_current_list(config: Cfg, id: String) -> MLE<()> {
592 let data = devdir(format!("{}/data.db", config.data).as_str()); 591 let data = format!("{}/data.db", config.data);
593 let connection = Connection::open(data)?; 592 let connection = Connection::open(data)?;
594 593
595 connection.execute( 594 connection.execute(
@@ -600,7 +599,7 @@ pub fn config_change_current_list(config: Cfg, id: String) -> MLE<()> {
600} 599}
601 600
602pub fn config_get_current_list(config: Cfg) -> MLE<String> { 601pub fn config_get_current_list(config: Cfg) -> MLE<String> {
603 let data = devdir(format!("{}/data.db", config.data).as_str()); 602 let data = format!("{}/data.db", config.data);
604 let connection = Connection::open(data).unwrap(); 603 let connection = Connection::open(data).unwrap();
605 604
606 let mut list_id = String::new(); 605 let mut list_id = String::new();
@@ -625,7 +624,7 @@ pub fn s_userlist_update_download(
625 mod_id: String, 624 mod_id: String,
626 link: String, 625 link: String,
627) -> Result<(), Box<dyn std::error::Error>> { 626) -> Result<(), Box<dyn std::error::Error>> {
628 let data = devdir(format!("{}/data.db", config.data).as_str()); 627 let data = format!("{}/data.db", config.data);
629 let connection = Connection::open(data)?; 628 let connection = Connection::open(data)?;
630 629
631 connection.execute( 630 connection.execute(
@@ -640,7 +639,7 @@ pub fn s_userlist_update_download(
640} 639}
641 640
642pub fn s_config_create_version(config: Cfg) -> Result<(), Box<dyn std::error::Error>> { 641pub fn s_config_create_version(config: Cfg) -> Result<(), Box<dyn std::error::Error>> {
643 let data = devdir(format!("{}/data.db", config.data).as_str()); 642 let data = format!("{}/data.db", config.data);
644 let connection = Connection::open(data)?; 643 let connection = Connection::open(data)?;
645 644
646 connection.execute( 645 connection.execute(
@@ -651,7 +650,7 @@ pub fn s_config_create_version(config: Cfg) -> Result<(), Box<dyn std::error::Er
651} 650}
652 651
653pub fn s_config_update_version(config: Cfg, ver: String) -> Result<(), Box<dyn std::error::Error>> { 652pub fn s_config_update_version(config: Cfg, ver: String) -> Result<(), Box<dyn std::error::Error>> {
654 let data = devdir(format!("{}/data.db", config.data).as_str()); 653 let data = format!("{}/data.db", config.data);
655 let connection = Connection::open(data)?; 654 let connection = Connection::open(data)?;
656 655
657 connection.execute( 656 connection.execute(
@@ -662,7 +661,7 @@ pub fn s_config_update_version(config: Cfg, ver: String) -> Result<(), Box<dyn s
662} 661}
663 662
664pub fn s_config_get_version(config: Cfg) -> Result<String, Box<dyn std::error::Error>> { 663pub fn s_config_get_version(config: Cfg) -> Result<String, Box<dyn std::error::Error>> {
665 let data = devdir(format!("{}/data.db", config.data).as_str()); 664 let data = format!("{}/data.db", config.data);
666 let connection = Connection::open(data)?; 665 let connection = Connection::open(data)?;
667 666
668 let mut version: String = String::new(); 667 let mut version: String = String::new();
@@ -689,7 +688,7 @@ pub fn s_insert_column(
689 c_type: String, 688 c_type: String,
690 default: Option<String>, 689 default: Option<String>,
691) -> Result<(), Box<dyn std::error::Error>> { 690) -> Result<(), Box<dyn std::error::Error>> {
692 let data = devdir(format!("{}/data.db", config.data).as_str()); 691 let data = format!("{}/data.db", config.data);
693 let connection = Connection::open(data)?; 692 let connection = Connection::open(data)?;
694 693
695 let mut sql = format!("ALTER TABLE {} ADD '{}' {}", table, column, c_type); 694 let mut sql = format!("ALTER TABLE {} ADD '{}' {}", table, column, c_type);
@@ -702,11 +701,8 @@ pub fn s_insert_column(
702 Ok(()) 701 Ok(())
703} 702}
704 703
705pub fn db_setup(config: Cfg) -> MLE<()> { 704pub fn db_setup(path: &str) -> MLE<()> {
706 println!("Initiating database"); 705 let connection = Connection::open(path)?;
707
708 let data = devdir(format!("{}/data.db", config.data).as_str());
709 let connection = Connection::open(data)?;
710 706
711 connection.execute_batch( 707 connection.execute_batch(
712 "CREATE TABLE 'user_config' ( 'id' TEXT, 'value' TEXT ); 708 "CREATE TABLE 'user_config' ( 'id' TEXT, 'value' TEXT );
diff --git a/src/files.rs b/src/files.rs
index 6160cb4..59fc7de 100644
--- a/src/files.rs
+++ b/src/files.rs
@@ -2,11 +2,12 @@ use futures_util::StreamExt;
2use reqwest::Client; 2use reqwest::Client;
3use std::{ 3use std::{
4 collections::HashMap, 4 collections::HashMap,
5 fs::{read_dir, remove_file, rename, File}, 5 fs::{copy, read_dir, remove_file, rename, File},
6 io::Write, 6 io::Write,
7}; 7};
8 8
9use crate::{ 9use crate::{
10 cache::{copy_cached_version, get_cached_versions},
10 config::Cfg, 11 config::Cfg,
11 db::{mods_get_info, userlist_add_disabled_versions}, 12 db::{mods_get_info, userlist_add_disabled_versions},
12 error::{ErrorType, MLError, MLE}, 13 error::{ErrorType, MLError, MLE},
@@ -15,31 +16,62 @@ use crate::{
15}; 16};
16 17
17pub async fn download_versions(list: List, config: Cfg, versions: Vec<Version>) -> MLE<String> { 18pub async fn download_versions(list: List, config: Cfg, versions: Vec<Version>) -> MLE<String> {
19 let mut cached = get_cached_versions(&config.cache);
20
21 println!("{:#?}", cached);
22
18 let dl_path = String::from(&list.download_folder); 23 let dl_path = String::from(&list.download_folder);
19 24
20 println!(" └Download mods to {}", dl_path); 25 println!(" └Download mods to {}", dl_path);
21 26
22 for ver in versions { 27 for ver in versions {
23 let project_info = mods_get_info(config.clone(), &ver.project_id)?; 28 let project_info = mods_get_info(config.clone(), &ver.project_id)?;
24 print!("\t└({})Download version {}", project_info.title, ver.id); 29
25 //Force flush of stdout, else print! doesn't print instantly 30 //Check cache if already downloaded
26 std::io::stdout().flush().unwrap(); 31 let c = cached.remove(&ver.id);
27 let primary_file = ver.files.into_iter().find(|file| file.primary).unwrap(); 32 if c.is_some() {
28 let mut splitname: Vec<&str> = primary_file.filename.split('.').collect(); 33 print!(
29 let extension = match splitname.pop().ok_or("") { 34 "\t└({})Get version {} from cache",
30 Ok(e) => e, 35 project_info.title, ver.id
31 Err(..) => return Err(MLError::new(ErrorType::Other, "NO_FILE_EXTENSION")), 36 );
32 }; 37 //Force flush of stdout, else print! doesn't print instantly
33 let filename = format!( 38 std::io::stdout().flush()?;
34 "{}.mr.{}.{}.{}", 39 copy_cached_version(&c.unwrap(), &dl_path);
35 splitname.join("."), 40 println!(" ✓");
36 ver.project_id, 41 } else {
37 ver.id, 42 print!("\t└({})Download version {}", project_info.title, ver.id);
38 extension 43 //Force flush of stdout, else print! doesn't print instantly
39 ); 44 std::io::stdout().flush().unwrap();
40 download_file(primary_file.url, list.clone().download_folder, filename).await?; 45 let primary_file = ver.files.into_iter().find(|file| file.primary).unwrap();
41 //tokio::time::sleep(std::time::Duration::new(3, 0)).await; 46 let mut splitname: Vec<&str> = primary_file.filename.split('.').collect();
42 println!(" ✓"); 47 let extension = match splitname.pop().ok_or("") {
48 Ok(e) => e,
49 Err(..) => return Err(MLError::new(ErrorType::Other, "NO_FILE_EXTENSION")),
50 };
51 let filename = format!(
52 "{}.mr.{}.{}.{}",
53 splitname.join("."),
54 ver.project_id,
55 ver.id,
56 extension
57 );
58 download_file(
59 primary_file.url,
60 list.clone().download_folder,
61 filename.clone(),
62 )
63 .await?;
64 println!(" ✓");
65 //Copy file to cache
66 print!("\t └Copy to cache");
67 //Force flush of stdout, else print! doesn't print instantly
68 std::io::stdout().flush().unwrap();
69 let dl_path_file = format!("{}/{}", list.download_folder, filename);
70 let cache_path = format!("{}/{}", &config.clone().cache, filename);
71 // println!("{}:{}", dl_path_file, cache_path);
72 copy(dl_path_file, cache_path)?;
73 println!(" ✓");
74 }
43 } 75 }
44 76
45 Ok(dl_path) 77 Ok(dl_path)
diff --git a/src/lib.rs b/src/lib.rs
index 43f0fe7..185edd7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,11 +1,12 @@
1pub mod apis; 1pub mod apis;
2pub mod cache;
2pub mod commands; 3pub mod commands;
3pub mod config; 4pub mod config;
4pub mod db; 5pub mod db;
5pub mod error; 6pub mod error;
6pub mod files; 7pub mod files;
7 8
8use std::{fmt::Display, path::Path}; 9use std::fmt::Display;
9 10
10pub use apis::*; 11pub use apis::*;
11pub use commands::*; 12pub use commands::*;
@@ -35,17 +36,3 @@ impl Display for Modloader {
35 } 36 }
36 } 37 }
37} 38}
38
39pub fn devdir(path: &str) -> String {
40 let p = Path::new(path);
41 let dev = std::env::var("DEV");
42 let lvl = match dev {
43 Ok(dev) => dev.parse::<i32>().unwrap(),
44 Err(..) => 0,
45 };
46 if lvl >= 1 {
47 format!("./dev/{}", p.file_name().unwrap().to_str().unwrap())
48 } else {
49 String::from(path)
50 }
51}
diff --git a/src/main.rs b/src/main.rs
index 2006856..0ecb850 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,8 +2,8 @@ use clap::{Parser, Subcommand};
2use modlist::{ 2use modlist::{
3 config::Cfg, 3 config::Cfg,
4 db::{config_get_current_list, lists_get, lists_get_all_ids}, 4 db::{config_get_current_list, lists_get, lists_get_all_ids},
5 devdir, download, export, get_current_list, import, list_add, list_change, list_remove, 5 download, export, get_current_list, import, list_add, list_change, list_remove, list_version,
6 list_version, mod_add, mod_remove, update, IDSelector, List, Modloader, 6 mod_add, mod_remove, update, IDSelector, List, Modloader,
7}; 7};
8 8
9//TODO implement remote sql db 9//TODO implement remote sql db
@@ -14,6 +14,10 @@ use modlist::{
14struct Cli { 14struct Cli {
15 #[command(subcommand)] 15 #[command(subcommand)]
16 command: Commands, 16 command: Commands,
17
18 /// config file path
19 #[arg(short, long)]
20 config: Option<String>,
17} 21}
18 22
19#[derive(Subcommand)] 23#[derive(Subcommand)]
@@ -143,10 +147,9 @@ enum ListCommands {
143async fn main() { 147async fn main() {
144 let cli = Cli::parse(); 148 let cli = Cli::parse();
145 149
146 let config = Cfg::init("modlist.toml").unwrap(); 150 let config = Cfg::init(cli.config).unwrap();
147 println!("{:?}", config); 151 println!("{:?}", config);
148 152
149 //TODO setup? maybe setup on install
150 match cli.command { 153 match cli.command {
151 Commands::Mod { command } => { 154 Commands::Mod { command } => {
152 match command { 155 match command {
@@ -250,15 +253,12 @@ async fn main() {
250 Commands::Import { file, download } => { 253 Commands::Import { file, download } => {
251 let filestr: String = match file { 254 let filestr: String = match file {
252 Some(args) => args, 255 Some(args) => args,
253 None => devdir( 256 None => dirs::home_dir()
254 dirs::home_dir() 257 .unwrap()
255 .unwrap() 258 .join("mlexport.toml")
256 .join("mlexport.toml") 259 .into_os_string()
257 .into_os_string() 260 .into_string()
258 .into_string() 261 .unwrap(),
259 .unwrap()
260 .as_str(),
261 ),
262 }; 262 };
263 263
264 import(config, filestr, download).await 264 import(config, filestr, download).await