aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Schadt <kingdread@gmx.de>2021-11-07 00:36:29 +0100
committerDaniel Schadt <kingdread@gmx.de>2021-11-07 00:36:29 +0100
commitbe5879eaaa4000891b1e5369250fec48433b806b (patch)
tree2bf248e0a4a55629cbd2f76b187cd08d2306b778 /src
parentb7d13549d4ce961b9384611844e62a7156b321c7 (diff)
downloadmodderbaas-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.rs36
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))
}
}