From 5dabfb4ea0ebc7ec067d41d281e7f6ff76f6d402 Mon Sep 17 00:00:00 2001 From: Danielle Hutzley Date: Tue, 14 Dec 2021 17:23:33 -0800 Subject: [PATCH] Fix modpacks, compile to zip --- Cargo.lock | 10 ++++++++++ theseus/Cargo.toml | 1 + theseus/src/modpack/manifest.rs | 6 +++--- theseus/src/modpack/mod.rs | 22 +++++++++++++--------- theseus/src/modpack/modrinth_api.rs | 2 +- theseus/src/modpack/pack.rs | 14 ++++++++------ 6 files changed, 36 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d6aaabb93..f163aef4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1181,6 +1181,7 @@ dependencies = [ "tokio", "uuid", "zip", + "zip-extensions", ] [[package]] @@ -1527,3 +1528,12 @@ dependencies = [ "thiserror", "time", ] + +[[package]] +name = "zip-extensions" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64c3c977bc3434ce2d4bcea8ad3c644672de0f2c402b72b9171ca80a8885d14" +dependencies = [ + "zip", +] diff --git a/theseus/Cargo.toml b/theseus/Cargo.toml index 28eb816e9..46e076313 100644 --- a/theseus/Cargo.toml +++ b/theseus/Cargo.toml @@ -20,6 +20,7 @@ chrono = { version = "0.4", features = ["serde"] } uuid = { version = "0.8", features = ["serde", "v4"] } bytes = "1" zip = "0.5" +zip-extensions = "0.6" sha1 = { version = "0.6.0", features = ["std"]} path-clean = "0.1.0" fs_extra = "1.2.0" diff --git a/theseus/src/modpack/manifest.rs b/theseus/src/modpack/manifest.rs index dab367429..ef7313f4a 100644 --- a/theseus/src/modpack/manifest.rs +++ b/theseus/src/modpack/manifest.rs @@ -100,7 +100,7 @@ impl<'a> TryFrom<&'a pack::Modpack> for Manifest<'a> { pub struct ManifestFile<'a> { #[serde(borrow)] pub path: &'a Path, - pub hashes: ManifestHashes<'a>, + pub hashes: Option>, #[serde(default)] pub env: ManifestEnvs, #[serde(borrow)] @@ -113,7 +113,7 @@ impl TryFrom> for pack::ModpackFile { fn try_from(file: ManifestFile<'_>) -> Result { Ok(Self { path: PathBuf::from(file.path), - hashes: pack::ModpackFileHashes::from(file.hashes), + hashes: file.hashes.map(pack::ModpackFileHashes::from), env: pack::ModpackEnv::try_from(file.env)?, downloads: file.downloads.into_iter().map(ToOwned::to_owned).collect(), }) @@ -124,7 +124,7 @@ impl<'a> From<&'a pack::ModpackFile> for ManifestFile<'a> { fn from(file: &'a pack::ModpackFile) -> Self { Self { path: file.path.as_path(), - hashes: (&file.hashes).into(), + hashes: file.hashes.as_ref().map(ManifestHashes::from), env: file.env.into(), downloads: file .downloads diff --git a/theseus/src/modpack/mod.rs b/theseus/src/modpack/mod.rs index db11b8df3..cbe82b550 100644 --- a/theseus/src/modpack/mod.rs +++ b/theseus/src/modpack/mod.rs @@ -7,6 +7,7 @@ use std::{convert::TryFrom, env, io, path::Path}; use tokio::{fs, try_join}; use uuid::Uuid; use zip::ZipArchive; +use zip_extensions::ZipWriterExtensions; use self::{ manifest::Manifest, @@ -18,6 +19,7 @@ pub mod modrinth_api; pub mod pack; pub const COMPILED_PATH: &'static str = "compiled/"; +pub const COMPILED_ZIP: &'static str = "compiled.mrpack"; pub const MANIFEST_PATH: &'static str = "modrinth.index.json"; pub const OVERRIDES_PATH: &'static str = "overrides/"; pub const PACK_JSON5_PATH: &'static str = "modpack.json5"; @@ -141,7 +143,8 @@ pub fn to_pack_json5(pack: &Modpack) -> ModpackResult { lazy_static::lazy_static! { static ref PACK_GITIGNORE: String = format!(r#" {0} - "#, COMPILED_PATH); + {1} + "#, COMPILED_PATH, COMPILED_ZIP); } pub async fn create_modpack( @@ -166,6 +169,7 @@ pub async fn compile_modpack(dir: &Path) -> ModpackResult<()> { let result_dir = dir.join(COMPILED_PATH); let pack: Modpack = json5::from_str(&fs::read_to_string(dir.join(PACK_JSON5_PATH)).await?)?; + fs::create_dir(&result_dir).await; if dir.join(OVERRIDES_PATH).exists() { fs_extra::dir::copy( dir.join(OVERRIDES_PATH), @@ -174,15 +178,15 @@ pub async fn compile_modpack(dir: &Path) -> ModpackResult<()> { )?; } let manifest = Manifest::try_from(&pack)?; + fs::write( + result_dir.join(MANIFEST_PATH), + serde_json::to_string(&manifest)?, + ) + .await?; - try_join!( - fs::create_dir(&result_dir), - fs::write( - result_dir.join(MANIFEST_PATH), - serde_json::to_string(&manifest)? - ), - )?; + let result_zip = fs::File::create(dir.join(COMPILED_ZIP)).await?.into_std().await; + let mut zip = zip::ZipWriter::new(&result_zip); + zip.create_from_directory(&result_dir)?; Ok(()) } - diff --git a/theseus/src/modpack/modrinth_api.rs b/theseus/src/modpack/modrinth_api.rs index bd663d9ee..d398d59be 100644 --- a/theseus/src/modpack/modrinth_api.rs +++ b/theseus/src/modpack/modrinth_api.rs @@ -60,7 +60,7 @@ struct ModrinthV1ProjectVersionFile<'a> { impl From> for ModpackFile { fn from(file: ModrinthV1ProjectVersionFile<'_>) -> Self { Self { - hashes: ModpackFileHashes::from(file.hashes), + hashes: Some(ModpackFileHashes::from(file.hashes)), downloads: { let mut downloads: HashSet = HashSet::new(); downloads.insert(String::from(file.url)); diff --git a/theseus/src/modpack/pack.rs b/theseus/src/modpack/pack.rs index 09079183d..ebcc95922 100644 --- a/theseus/src/modpack/pack.rs +++ b/theseus/src/modpack/pack.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use std::{ collections::HashSet, hash::Hash, - path::{Path, PathBuf}, + path::{Path, PathBuf}, iter::FromIterator, }; use tokio::fs; @@ -115,15 +115,15 @@ impl Modpack { .collect::>(), ); - if (whitelisted_domains.iter().find(String::from(source.host_str().unwrap())).is_none()) { + if (whitelisted_domains.iter().find(|it| it == &source.host_str().unwrap()).is_none()) { return Err(ModpackError::SourceWhitelistError(String::from(source.host_str().unwrap()))); } let file = ModpackFile { - path: dest, + path: PathBuf::from(dest), hashes, env: env.unwrap_or(ModpackEnv::Both), - downloads: HashSet::from([String::from(source)]) + downloads: HashSet::from_iter([String::from(source)].into_iter().cloned()) }; self.files.insert(file); @@ -148,7 +148,9 @@ pub struct ModpackFile { impl Hash for ModpackFile { fn hash(&self, state: &mut H) { - self.hashes.sha1.hash(state); + if let Some(ref hashes) = self.hashes { + hashes.sha1.hash(state); + } self.path.hash(state); } } @@ -171,7 +173,7 @@ impl ModpackFile { .map(|it| it.as_str()) .collect::>() .as_slice(), - Some(&self.hashes.sha1), + self.hashes.as_ref().map(|it| it.sha1.as_str()), ) .await?; fs::create_dir_all(output.parent().unwrap()).await?;