You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

102 lines
2.9 KiB

use super::extract::{Error, Extract};
use log::debug;
use std::fs;
use std::io::{self, Read};
use std::path::Path;
use tempfile::tempfile;
use zip::read::ZipArchive;
pub struct Zip<R: Read> {
response: R,
}
impl<R: Read> Zip<R> {
#[allow(dead_code)]
pub fn new(response: R) -> Self {
Self { response }
}
}
impl<R: Read> Extract for Zip<R> {
fn extract_into<P: AsRef<Path>>(mut self, path: P) -> Result<(), Error> {
let path = path.as_ref();
let mut tmp_zip_file = tempfile().expect("Can't get a temporary file");
debug!("Created a temporary zip file");
io::copy(&mut self.response, &mut tmp_zip_file)?;
debug!(
"Wrote zipfile successfully. Now extracting into {}.",
path.display()
);
let mut archive = ZipArchive::new(&mut tmp_zip_file)?;
for i in 0..archive.len() {
let mut file = archive.by_index(i)?;
let outpath = path.join(file.mangled_name());
{
let comment = file.comment();
if !comment.is_empty() {
debug!("File {} comment: {}", i, comment);
}
}
if file.name().ends_with('/') {
debug!(
"File {} extracted to \"{}\"",
i,
outpath.as_path().display()
);
fs::create_dir_all(&outpath)?;
} else {
debug!(
"Extracting file {} to \"{}\" ({} bytes)",
i,
outpath.as_path().display(),
file.size()
);
if let Some(p) = outpath.parent() {
if !p.exists() {
fs::create_dir_all(&p)?;
}
}
let mut outfile = fs::File::create(&outpath)?;
io::copy(&mut file, &mut outfile)?;
}
// Get and Set permissions
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
if let Some(mode) = file.unix_mode() {
fs::set_permissions(&outpath, fs::Permissions::from_mode(mode))?;
}
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test_log::test]
fn test_zip_extraction() {
let temp_dir = tempfile::tempdir().expect("Can't create a temp directory");
let response = crate::http::get("https://nodejs.org/dist/v12.0.0/node-v12.0.0-win-x64.zip")
.expect("Can't make request to Node v12.0.0 zip file");
Zip::new(response)
.extract_into(&temp_dir)
.expect("Can't unzip files");
let node_file = temp_dir
.as_ref()
.join("node-v12.0.0-win-x64")
.join("node.exe");
assert!(node_file.exists());
}
}