From 30626b6952bdabe9fcd50ae6f5efa43bb5961699 Mon Sep 17 00:00:00 2001 From: Warren Hood Date: Mon, 19 Aug 2024 00:32:23 +0200 Subject: [PATCH] Download all supported mods for sides --- src/main.rs | 17 ++++++------ src/providers/mod.rs | 56 ++++++++++++++++++++++++++++++++++----- src/providers/modrinth.rs | 4 +-- src/resolver.rs | 24 ++++++++++++----- 4 files changed, 78 insertions(+), 23 deletions(-) diff --git a/src/main.rs b/src/main.rs index c437552..fd2ec2e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ mod resolver; use clap::{Parser, Subcommand}; use mod_meta::{ModMeta, ModProvider}; use modpack::ModpackMeta; +use providers::DownloadSide; use std::{error::Error, path::PathBuf}; /// A Minecraft Modpack Manager @@ -78,6 +79,9 @@ enum Commands { Download { /// Mods directory mods_dir: PathBuf, + /// Side to download for + #[arg(long, short, default_value_t = DownloadSide::Both)] + side: DownloadSide, }, } @@ -183,11 +187,7 @@ async fn main() -> Result<(), Box> { panic!("Reverted modpack meta:\n{}", e); }; - match resolver::PinnedPackMeta::load_from_current_directory( - !locked, - ) - .await - { + match resolver::PinnedPackMeta::load_from_current_directory(!locked).await { Ok(mut modpack_lock) => { let remove_result = modpack_lock.remove_mod(&mod_meta.name, &modpack_meta); if let Err(e) = remove_result { @@ -241,10 +241,9 @@ async fn main() -> Result<(), Box> { } }; } - Commands::Download { mods_dir } => { - let pack_lock = - resolver::PinnedPackMeta::load_from_current_directory(true).await?; - pack_lock.download_mods(&mods_dir).await?; + Commands::Download { mods_dir, side } => { + let pack_lock = resolver::PinnedPackMeta::load_from_current_directory(true).await?; + pack_lock.download_mods(&mods_dir, side).await?; println!("Mods updated"); } } diff --git a/src/providers/mod.rs b/src/providers/mod.rs index 21b7c76..17b8b6a 100644 --- a/src/providers/mod.rs +++ b/src/providers/mod.rs @@ -1,14 +1,58 @@ -use std::{collections::HashSet, path::PathBuf}; -use serde::{Deserialize, Serialize}; use crate::mod_meta::ModMeta; +use serde::{Deserialize, Serialize}; +use std::{collections::HashSet, path::PathBuf, str::FromStr}; pub mod modrinth; pub mod raw; #[derive(Serialize, Deserialize, Clone)] pub enum FileSource { - Download { url: String, sha1: String, sha512: String, filename: String}, - Local { path: PathBuf, sha1: String, sha512: String, filename: String }, + Download { + url: String, + sha1: String, + sha512: String, + filename: String, + }, + Local { + path: PathBuf, + sha1: String, + sha512: String, + filename: String, + }, +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum DownloadSide { + Both, + Server, + Client, +} + +impl FromStr for DownloadSide { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_ascii_lowercase().as_str() { + "both" => Ok(DownloadSide::Both), + "client" => Ok(DownloadSide::Client), + "server" => Ok(DownloadSide::Server), + _ => Err(format!( + "Invalid side {}. Expected one of: both, server, clide", + s + )), + } + } +} + +impl ToString for DownloadSide { + fn to_string(&self) -> String { + match self { + DownloadSide::Both => "Both", + DownloadSide::Server => "Server", + DownloadSide::Client => "Client", + } + .into() + } } #[derive(Serialize, Deserialize, Clone)] @@ -22,5 +66,5 @@ pub struct PinnedMod { /// Server side pub server_side: bool, /// Required on client side - pub client_side: bool -} \ No newline at end of file + pub client_side: bool, +} diff --git a/src/providers/modrinth.rs b/src/providers/modrinth.rs index ed963d3..b495853 100644 --- a/src/providers/modrinth.rs +++ b/src/providers/modrinth.rs @@ -184,8 +184,8 @@ impl Modrinth { } else { None }, - server_side: project.server_side != "optional", - client_side: project.client_side != "optional" + server_side: project.server_side != "unsupported", + client_side: project.client_side != "unsupported" }) } diff --git a/src/resolver.rs b/src/resolver.rs index 2abff2b..103bf8a 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -10,7 +10,7 @@ use std::{ use crate::{ mod_meta::{ModMeta, ModProvider}, modpack::ModpackMeta, - providers::{modrinth::Modrinth, PinnedMod}, + providers::{modrinth::Modrinth, DownloadSide, PinnedMod}, }; const MODPACK_LOCK_FILENAME: &str = "modpack.lock"; @@ -31,7 +31,11 @@ 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> { + pub async fn download_mods( + &self, + mods_dir: &PathBuf, + download_side: DownloadSide, + ) -> Result<(), Box> { let files = std::fs::read_dir(mods_dir)?; for file in files.into_iter() { let file = file?; @@ -41,7 +45,7 @@ impl PinnedPackMeta { file.file_name() ); let filename = file.file_name(); - if !self.file_is_pinned(&filename) { + if !self.file_is_pinned(&filename, download_side) { println!( "Deleting file {:#?} as it is not in the pinned mods", filename @@ -51,7 +55,11 @@ impl PinnedPackMeta { } } - for (_, pinned_mod) in self.mods.iter() { + for (_, pinned_mod) in self.mods.iter().filter(|m| { + download_side == DownloadSide::Both + || download_side == DownloadSide::Client && m.1.client_side + || download_side == DownloadSide::Server && m.1.server_side + }) { for filesource in pinned_mod.source.iter() { match filesource { crate::providers::FileSource::Download { @@ -97,8 +105,12 @@ impl PinnedPackMeta { Ok(()) } - pub fn file_is_pinned(&self, file_name: &OsStr) -> bool { - for (pinned_mod_name, pinned_mod) in self.mods.iter() { + pub fn file_is_pinned(&self, file_name: &OsStr, mod_side: DownloadSide) -> bool { + for (_, pinned_mod) in self.mods.iter().filter(|m| { + mod_side == DownloadSide::Both + || mod_side == DownloadSide::Client && m.1.client_side + || mod_side == DownloadSide::Server && m.1.server_side + }) { for filesource in pinned_mod.source.iter() { match filesource { crate::providers::FileSource::Download {