use crate::{
errors::ZipFileError,
imports::IMPORTS_DIRECTORY_NAME,
inputs::{INPUTS_DIRECTORY_NAME, INPUT_FILE_EXTENSION},
outputs::{
CHECKSUM_FILE_EXTENSION,
CIRCUIT_FILE_EXTENSION,
OUTPUTS_DIRECTORY_NAME,
PROOF_FILE_EXTENSION,
PROVING_KEY_FILE_EXTENSION,
VERIFICATION_KEY_FILE_EXTENSION,
},
root::{MANIFEST_FILE_NAME, README_FILE_NAME},
source::{SOURCE_DIRECTORY_NAME, SOURCE_FILE_EXTENSION},
};
use serde::Deserialize;
use std::{
fs::{self, File},
io::{Read, Write},
path::{Path, PathBuf},
};
use walkdir::WalkDir;
use zip::write::{FileOptions, ZipWriter};
pub static ZIP_FILE_EXTENSION: &str = ".zip";
#[derive(Deserialize)]
pub struct ZipFile {
pub package_name: String,
}
impl ZipFile {
pub fn new(package_name: &str) -> Self {
Self {
package_name: package_name.to_string(),
}
}
pub fn exists_at(&self, path: &PathBuf) -> bool {
let path = self.setup_file_path(path);
path.exists()
}
pub fn get_file_path(&self, current_dir: &PathBuf) -> PathBuf {
self.setup_file_path(current_dir)
}
pub fn write(&self, src_dir: &PathBuf) -> Result<(), ZipFileError> {
let walkdir = WalkDir::new(src_dir.clone());
let path = self.setup_file_path(src_dir);
let file = &mut File::create(&path)?;
let mut zip = ZipWriter::new(file);
let options = FileOptions::default()
.compression_method(zip::CompressionMethod::Stored)
.unix_permissions(0o755);
let mut buffer = Vec::new();
for entry in walkdir.into_iter().filter_map(|e| e.ok()) {
let path = entry.path();
let name = path.strip_prefix(src_dir.as_path()).unwrap();
let included = is_included(name);
log::debug!("Checking if {:?} is included - {}", name, included);
if !included {
continue;
}
if path.is_file() {
log::info!("Adding file {:?} as {:?}", path, name);
zip.start_file_from_path(name, options)?;
let mut f = File::open(path)?;
f.read_to_end(&mut buffer)?;
zip.write_all(&*buffer)?;
buffer.clear();
} else if name.as_os_str().len() != 0 {
log::info!("Adding directory {:?} as {:?}", path, name);
zip.add_directory_from_path(name, options)?;
}
}
zip.finish()?;
log::info!("Package zip file created successfully {:?}", path);
Ok(())
}
pub fn remove(&self, path: &PathBuf) -> Result<bool, ZipFileError> {
let path = self.setup_file_path(path);
if !path.exists() {
return Ok(false);
}
fs::remove_file(&path).map_err(|_| ZipFileError::FileRemovalError(path.clone()))?;
Ok(true)
}
fn setup_file_path(&self, path: &PathBuf) -> PathBuf {
let mut path = path.to_owned();
if path.is_dir() {
if !path.ends_with(OUTPUTS_DIRECTORY_NAME) {
path.push(PathBuf::from(OUTPUTS_DIRECTORY_NAME));
}
path.push(PathBuf::from(format!("{}{}", self.package_name, ZIP_FILE_EXTENSION)));
}
path
}
}
fn is_included(path: &Path) -> bool {
if path.ends_with(INPUTS_DIRECTORY_NAME.trim_end_matches("/"))
| path.ends_with(OUTPUTS_DIRECTORY_NAME.trim_end_matches("/"))
| path.ends_with(IMPORTS_DIRECTORY_NAME.trim_end_matches("/"))
{
return false;
}
if let Some(true) = path.extension().map(|ext| {
ext.eq(INPUT_FILE_EXTENSION.trim_start_matches("."))
| ext.eq(ZIP_FILE_EXTENSION.trim_start_matches("."))
| ext.eq(PROVING_KEY_FILE_EXTENSION.trim_start_matches("."))
| ext.eq(VERIFICATION_KEY_FILE_EXTENSION.trim_start_matches("."))
| ext.eq(PROOF_FILE_EXTENSION.trim_start_matches("."))
| ext.eq(CHECKSUM_FILE_EXTENSION.trim_start_matches("."))
| ext.eq(ZIP_FILE_EXTENSION.trim_start_matches("."))
| ext.eq(CIRCUIT_FILE_EXTENSION.trim_start_matches("."))
}) {
return false;
}
if (path.ends_with(README_FILE_NAME) | path.ends_with(MANIFEST_FILE_NAME)) & (path.parent() == Some(Path::new("")))
{
return true;
}
if !path.starts_with(SOURCE_DIRECTORY_NAME.trim_end_matches("/")) {
return false;
}
path.extension()
.map(|ext| ext.eq(SOURCE_FILE_EXTENSION.trim_start_matches(".")))
.unwrap_or(false)
}