use std::io::prelude::*;
use std::path::Path;
use anyhow::Result;
use crate::environment::Environment;
pub fn extract_zip(message: &str, zip_bytes: &[u8], dir_path: &Path, environment: &impl Environment) -> Result<()> {
let reader = std::io::Cursor::new(&zip_bytes);
let mut zip = zip::ZipArchive::new(reader)?;
let length = zip.len();
log_debug!(environment, "Extracting zip file to directory: {}", dir_path.display());
environment.log_action_with_progress(
message,
move |update_size| -> Result<()> {
for i in 0..zip.len() {
update_size(i);
let mut file = zip.by_index(i).unwrap();
if let Some(file_name) = file.enclosed_name() {
let file_path = dir_path.join(file_name);
if !file.is_dir() {
if let Some(parent_dir_path) = file_path.parent() {
environment.mk_dir_all(parent_dir_path)?;
}
let mut file_bytes = Vec::new();
file_bytes.try_reserve_exact(file.size() as usize)?;
file.read_to_end(&mut file_bytes)?;
environment.write_file_bytes(&file_path, &file_bytes)?;
} else {
environment.mk_dir_all(&file_path)?;
}
#[cfg(unix)]
if environment.is_real() {
use std::fs;
use std::os::unix::fs::PermissionsExt;
if let Some(mode) = file.unix_mode() {
#[allow(clippy::disallowed_methods)]
fs::set_permissions(&file_path, fs::Permissions::from_mode(mode))
.map_err(|err| anyhow::anyhow!("Error setting permissions to {} for file {}: {:#}", mode, file_path.display(), err))?
}
}
} else {
log_warn!(environment, "Ignoring path in zip because it was not enclosed: {}", file.name());
}
}
Ok(())
},
length,
)?;
Ok(())
}