diff options
author | Daniel Schadt <kingdread@gmx.de> | 2021-11-07 00:36:29 +0100 |
---|---|---|
committer | Daniel Schadt <kingdread@gmx.de> | 2021-11-07 00:36:29 +0100 |
commit | be5879eaaa4000891b1e5369250fec48433b806b (patch) | |
tree | 2bf248e0a4a55629cbd2f76b187cd08d2306b778 /src | |
parent | b7d13549d4ce961b9384611844e62a7156b321c7 (diff) | |
download | modderbaas-be5879eaaa4000891b1e5369250fec48433b806b.tar.gz modderbaas-be5879eaaa4000891b1e5369250fec48433b806b.tar.bz2 modderbaas-be5879eaaa4000891b1e5369250fec48433b806b.zip |
make downloads work with more archives
Some mods do not come bundled in a separate directory, so we also
support archives that do not contain an inner directory now (e.g. the
"charcoal" mod).
Diffstat (limited to 'src')
-rw-r--r-- | src/download.rs | 36 |
1 files changed, 25 insertions, 11 deletions
diff --git a/src/download.rs b/src/download.rs index 75bea57..dfce2fc 100644 --- a/src/download.rs +++ b/src/download.rs @@ -1,10 +1,12 @@ use std::{ + fs, io::{Cursor, Read}, str::FromStr, }; use tempdir::TempDir; use url::Url; +use uuid::Uuid; use zip::ZipArchive; use super::{ @@ -103,18 +105,30 @@ impl Downloader { let data = Cursor::new(data); let mut archive = ZipArchive::new(data)?; - // Here we assume that the zipfile contains only one directory, so we just take the first - // name we find and extract the leading directory name. - let name = archive - .file_names() - .next() - .and_then(|name| name.split('/').next()) - .ok_or(Error::EmptyArchive)? - .to_string(); + let dir = self + .temp_dir + .path() + .join(&Uuid::new_v4().to_hyphenated().to_string()); + fs::create_dir(&dir)?; - archive.extract(self.temp_dir.path())?; + archive.extract(&dir)?; - let extracted_path = self.temp_dir.path().join(name); - minemod::open_mod_or_pack(&extracted_path) + // Some archives contain the mod files directly, so try to open it: + if let Ok(pack) = minemod::open_mod_or_pack(&dir) { + return Ok(pack); + } + + // If the archive does not contain the mod directly, we instead try the subdirectories that + // we've extracted. + for entry in fs::read_dir(&dir)? { + let entry = entry?; + let metadata = fs::metadata(&entry.path())?; + if metadata.is_dir() { + if let Ok(pack) = minemod::open_mod_or_pack(&entry.path()) { + return Ok(pack); + } + } + } + Err(Error::InvalidModDir(dir)) } } |