From 9700206b02fee7d99bbb04ace34f08c6bf9a8b17 Mon Sep 17 00:00:00 2001 From: Warren Hood Date: Sun, 18 Aug 2024 23:25:01 +0200 Subject: [PATCH] Added a download command --- src/main.rs | 11 ++++++ src/providers/mod.rs | 8 ++-- src/providers/modrinth.rs | 24 +----------- src/resolver.rs | 81 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 26 deletions(-) diff --git a/src/main.rs b/src/main.rs index d6c9ef0..821b570 100644 --- a/src/main.rs +++ b/src/main.rs @@ -74,6 +74,11 @@ enum Commands { /// Name of the mod to remove from the modpack name: String, }, + /// Download the mods in the pack to a specified folder + Download { + /// Mods directory + mods_dir: PathBuf, + }, } #[tokio::main(flavor = "multi_thread")] @@ -236,6 +241,12 @@ async fn main() -> Result<(), Box> { } }; } + Commands::Download { mods_dir } => { + let pack_lock = + resolver::PinnedPackMeta::load_from_current_directory(false).await?; + pack_lock.download_mods(&mods_dir).await?; + println!("Mods updated"); + } } }; diff --git a/src/providers/mod.rs b/src/providers/mod.rs index a4609a6..c49c1a0 100644 --- a/src/providers/mod.rs +++ b/src/providers/mod.rs @@ -6,15 +6,15 @@ pub mod modrinth; pub mod raw; #[derive(Serialize, Deserialize, Clone)] -enum FileSource { - Download { url: String, sha1: String, sha512: String}, - Local { path: PathBuf, sha1: String, sha512: String }, +pub enum FileSource { + Download { url: String, sha1: String, sha512: String, filename: String}, + Local { path: PathBuf, sha1: String, sha512: String, filename: String }, } #[derive(Serialize, Deserialize, Clone)] pub struct PinnedMod { /// Source of the files for the mod - source: Vec, + pub source: Vec, /// Version of mod pub version: String, /// Pinned dependencies of a pinned mod diff --git a/src/providers/modrinth.rs b/src/providers/modrinth.rs index 7afc3b7..ad3159d 100644 --- a/src/providers/modrinth.rs +++ b/src/providers/modrinth.rs @@ -12,27 +12,6 @@ pub struct Modrinth { client: reqwest::Client, } -#[derive(Serialize, Deserialize)] -struct DonationUrls1 { - id: String, - platform: String, - url: String, -} -#[derive(Serialize, Deserialize)] -struct Gallery1 { - created: String, - description: String, - featured: bool, - ordering: i64, - title: String, - url: String, -} -#[derive(Serialize, Deserialize)] -struct License1 { - id: String, - name: String, - url: String, -} #[derive(Serialize, Deserialize)] struct ModrinthProject { slug: String, @@ -65,7 +44,7 @@ struct VersionFiles { #[derive(Serialize, Deserialize, Debug)] struct ModrinthProjectVersion { // author_id: String, - // date_published: String, + date_published: String, dependencies: Option>, // downloads: i64, files: Vec, @@ -188,6 +167,7 @@ impl Modrinth { url: f.url.clone(), sha1: f.hashes.sha1.clone(), sha512: f.hashes.sha512.clone(), + filename: f.filename.clone() }) .collect(), version: package.version_number.clone(), diff --git a/src/resolver.rs b/src/resolver.rs index 74b79b7..c86906b 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -2,6 +2,7 @@ use serde::{Deserialize, Serialize}; use std::{ collections::{HashMap, HashSet}, error::Error, + ffi::OsStr, path::PathBuf, }; @@ -28,6 +29,86 @@ impl PinnedPackMeta { } } + /// Clears out anything not in the mods list, and then downloads anything in the mods list not present + pub async fn download_mods(&self, mods_dir: &PathBuf) -> Result<(), Box> { + let files = std::fs::read_dir(mods_dir)?; + for file in files.into_iter() { + let file = file?; + if file.file_type()?.is_file() { + println!("Checking if file {:#?} exists in pinned mods...", file.file_name()); + let filename = file.file_name(); + if !self.file_is_pinned(&filename) { + println!( + "Deleting file {:#?} as it is not in the pinned mods", + filename + ); + tokio::fs::remove_file(file.path()).await?; + } + } + } + + for (_, pinned_mod) in self.mods.iter() { + for filesource in pinned_mod.source.iter() { + match filesource { + crate::providers::FileSource::Download { + url, + sha1, + sha512, + filename, + } => { + if mods_dir.join(PathBuf::from(filename)).exists() { + println!("Found existing mod {}", filename); + continue; + } + println!("Downloading {} from {}", filename, url); + let file_contents = reqwest::get(url).await?.bytes().await?; + // TODO: Check hash + tokio::fs::write(mods_dir.join(filename), file_contents).await?; + }, + crate::providers::FileSource::Local { + path, + sha1, + sha512, + filename, + } => unimplemented!(), + } + } + } + + Ok(()) + } + + pub fn file_is_pinned(&self, file_name: &OsStr) -> bool { + for (pinned_mod_name, pinned_mod) in self.mods.iter() { + for filesource in pinned_mod.source.iter() { + match filesource { + crate::providers::FileSource::Download { + url, + sha1, + sha512, + filename, + } => { + if OsStr::new(filename) == file_name { + return true + } + }, + crate::providers::FileSource::Local { + path, + sha1, + sha512, + filename, + } => { + if OsStr::new(filename) == file_name { + return true + } + }, + } + } + } + + return false + } + pub async fn pin_mod_and_deps( &mut self, mod_metadata: &ModMeta,