unnest archives with only one dir in it

This commit is contained in:
2026-03-22 14:27:16 +01:00
parent 560562cc25
commit 3f91386763

View File

@@ -1,6 +1,9 @@
use std::{fs, path::Path}; use std::{
fs,
path::{Path, PathBuf},
};
use anyhow::anyhow; use anyhow::{Ok, anyhow};
use log::error; use log::error;
use zip::ZipArchive; use zip::ZipArchive;
@@ -29,6 +32,8 @@ pub fn unpack(archive_path: impl AsRef<Path>, extract_to: impl AsRef<Path>) -> a
} }
}?; }?;
unnest_dir(extract_to)?;
Ok(()) Ok(())
} }
@@ -53,3 +58,47 @@ fn unpack_rar(path: impl AsRef<Path>, to: impl AsRef<Path>) -> anyhow::Result<()
Ok(()) Ok(())
} }
/// Moves a directorys content into the parent if it is the only dir
fn unnest_dir(path: impl AsRef<Path>) -> anyhow::Result<()> {
let path = path.as_ref();
let Some(nested_dir) = check_nested_dir(path) else {
return Ok(());
};
for entry in fs::read_dir(&nested_dir)? {
let entry = entry?;
let src = entry.path();
let dest = path.join(entry.file_name());
fs::rename(&src, &dest)?;
}
fs::remove_dir(&nested_dir)?;
Ok(())
}
/// Check if the extracted archive has a single directory in it which contains the mod files
fn check_nested_dir(path: impl AsRef<Path>) -> Option<PathBuf> {
let path = path.as_ref();
let entries: Vec<_> = fs::read_dir(path).ok()?.filter_map(|e| e.ok()).collect();
if entries.len() == 1 {
let entry = &entries[0];
let entry_path = entry.path();
if entry_path
.file_name()
.is_some_and(|e| e == "Data" || e == "data")
{
return None;
}
if entry_path.is_dir() {
return Some(entry_path);
}
}
None
}