mod common;
mod rar;
mod sevenz;
mod targz;
mod zip;
use std::io;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ArchiveFormat {
Zip,
Rar,
SevenZip,
TarGz,
}
pub fn detect_format(path: &Path) -> Option<ArchiveFormat> {
if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
let lower = name.to_ascii_lowercase();
if lower.ends_with(".tar.gz") {
return Some(ArchiveFormat::TarGz);
}
}
let ext = path.extension()?.to_str()?.to_ascii_lowercase();
match ext.as_str() {
"zip" => Some(ArchiveFormat::Zip),
"rar" => Some(ArchiveFormat::Rar),
"7z" => Some(ArchiveFormat::SevenZip),
"tgz" => Some(ArchiveFormat::TarGz),
_ => None,
}
}
pub fn extract_archive(archive_path: &Path, dest_dir: &Path) -> io::Result<Vec<PathBuf>> {
let format = detect_format(archive_path).ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("Unrecognised archive format: {}", archive_path.display()),
)
})?;
match format {
ArchiveFormat::Zip => zip::extract_zip(archive_path, dest_dir),
ArchiveFormat::Rar => rar::extract_rar(archive_path, dest_dir),
ArchiveFormat::SevenZip => sevenz::extract_7z(archive_path, dest_dir),
ArchiveFormat::TarGz => targz::extract_tar_gz(archive_path, dest_dir),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_detect_format_zip() {
assert_eq!(
detect_format(Path::new("test.zip")),
Some(ArchiveFormat::Zip)
);
}
#[test]
fn test_detect_format_zip_uppercase() {
assert_eq!(
detect_format(Path::new("test.ZIP")),
Some(ArchiveFormat::Zip)
);
}
#[test]
fn test_detect_format_rar() {
assert_eq!(
detect_format(Path::new("test.rar")),
Some(ArchiveFormat::Rar)
);
}
#[test]
fn test_detect_format_rar_mixed_case() {
assert_eq!(
detect_format(Path::new("test.Rar")),
Some(ArchiveFormat::Rar)
);
}
#[test]
fn test_detect_format_7z() {
assert_eq!(
detect_format(Path::new("test.7z")),
Some(ArchiveFormat::SevenZip)
);
}
#[test]
fn test_detect_format_7z_uppercase() {
assert_eq!(
detect_format(Path::new("test.7Z")),
Some(ArchiveFormat::SevenZip)
);
}
#[test]
fn test_detect_format_tar_gz() {
assert_eq!(
detect_format(Path::new("test.tar.gz")),
Some(ArchiveFormat::TarGz)
);
}
#[test]
fn test_detect_format_tar_gz_uppercase() {
assert_eq!(
detect_format(Path::new("test.TAR.GZ")),
Some(ArchiveFormat::TarGz)
);
}
#[test]
fn test_detect_format_tgz() {
assert_eq!(
detect_format(Path::new("test.tgz")),
Some(ArchiveFormat::TarGz)
);
}
#[test]
fn test_detect_format_tgz_uppercase() {
assert_eq!(
detect_format(Path::new("test.TGZ")),
Some(ArchiveFormat::TarGz)
);
}
#[test]
fn test_detect_format_tar_bz2_none() {
assert_eq!(detect_format(Path::new("test.tar.bz2")), None);
}
#[test]
fn test_detect_format_plain_gz_none() {
assert_eq!(detect_format(Path::new("test.gz")), None);
}
#[test]
fn test_detect_format_srt_none() {
assert_eq!(detect_format(Path::new("test.srt")), None);
}
#[test]
fn test_detect_format_no_extension_none() {
assert_eq!(detect_format(Path::new("testfile")), None);
}
#[test]
fn test_extract_archive_unknown_format() {
let tmp = tempfile::tempdir().unwrap();
let path = tmp.path().join("test.tar.bz2");
std::fs::File::create(&path).unwrap();
let result = extract_archive(&path, tmp.path());
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Unrecognised"));
}
#[cfg(not(feature = "archive-rar"))]
#[test]
fn test_extract_rar_disabled_feature() {
let tmp = tempfile::tempdir().unwrap();
let path = tmp.path().join("test.rar");
std::fs::File::create(&path).unwrap();
let result = extract_archive(&path, tmp.path());
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("not compiled in"));
}
}