use crate::runtime::Runtime;
use crate::script::aip_modules::support::{check_access_write, process_path_reference};
use crate::support::zip;
use crate::types::{FileInfo, ZipOptions};
use crate::{Error, Result};
use mlua::{FromLua as _, IntoLua, Lua, Table, Value};
use simple_fs::SPath;
pub fn init_module(lua: &Lua, runtime: &Runtime) -> Result<Table> {
let table = lua.create_table()?;
let rt = runtime.clone();
let create_fn = lua.create_function(
move |lua, (src_dir, dest_zip, options): (String, Option<String>, Option<Value>)| {
zip_create(lua, &rt, src_dir, dest_zip, options)
},
)?;
let rt = runtime.clone();
let extract_fn = lua.create_function(
move |lua, (src_zip, dest_dir, options): (String, Option<String>, Option<Value>)| {
zip_extract(lua, &rt, src_zip, dest_dir, options)
},
)?;
let rt = runtime.clone();
let read_text_fn = lua.create_function(move |lua, (src_zip, content_path): (String, String)| {
zip_read_text(lua, &rt, src_zip, content_path)
})?;
let rt = runtime.clone();
let list_fn = lua.create_function(move |lua, (src_zip, options): (String, Option<Value>)| {
zip_list(lua, &rt, src_zip, options)
})?;
table.set("create", create_fn)?;
table.set("extract", extract_fn)?;
table.set("read_text", read_text_fn)?;
table.set("list", list_fn)?;
Ok(table)
}
fn zip_create(
lua: &Lua,
runtime: &Runtime,
src_dir: String,
dest_zip: Option<String>,
options: Option<Value>,
) -> mlua::Result<mlua::Value> {
let dir_context = runtime.dir_context();
let options = ZipOptions::from_lua(options.unwrap_or(Value::Nil), lua)
.map_err(|e| Error::custom(format!("Failed to parse zip options.\nCause: {e}")))?;
let src_dir_path = process_path_reference(runtime, &src_dir)
.map_err(|err| Error::custom(format!("aip.zip.create failed. {err}")))?;
let dest_zip_path = if let Some(dest_zip) = dest_zip {
process_path_reference(runtime, &dest_zip)
.map_err(|err| Error::custom(format!("aip.zip.create failed. {err}")))?
} else {
let parent = src_dir_path.parent().unwrap_or_else(|| SPath::new("."));
let stem = src_dir_path.name();
parent.join(format!("{stem}.zip"))
};
let wks_dir = dir_context.try_wks_dir_with_err_ctx("aip.zip.create requires a aipack workspace setup")?;
check_access_write(&dest_zip_path, wks_dir)
.map_err(|err| Error::custom(format!("aip.zip.create failed. {err}")))?;
zip::zip_dir_with_globs(&src_dir_path, &dest_zip_path, options.globs.as_ref())
.map_err(|err| Error::custom(format!("aip.zip.create failed. {err}")))?;
let file_info = FileInfo::new(runtime.dir_context(), dest_zip_path.clone(), true);
file_info.into_lua(lua)
}
fn zip_extract(
lua: &Lua,
runtime: &Runtime,
src_zip: String,
dest_dir: Option<String>,
options: Option<Value>,
) -> mlua::Result<Value> {
let dir_context = runtime.dir_context();
let options = ZipOptions::from_lua(options.unwrap_or(Value::Nil), lua)
.map_err(|e| Error::custom(format!("Failed to parse zip options.\nCause: {e}")))?;
let src_zip_path = process_path_reference(runtime, &src_zip)
.map_err(|err| Error::custom(format!("aip.zip.extract failed. {err}")))?;
let dest_dir_path = if let Some(dest_dir) = dest_dir {
process_path_reference(runtime, &dest_dir)
.map_err(|err| Error::custom(format!("aip.zip.extract failed. {err}")))?
} else {
let parent = src_zip_path.parent().unwrap_or_else(|| SPath::new("."));
let stem = src_zip_path.stem();
parent.join(stem)
};
let wks_dir = dir_context.try_wks_dir_with_err_ctx("aip.zip.extract requires a aipack workspace setup")?;
check_access_write(&dest_dir_path, wks_dir)
.map_err(|err| Error::custom(format!("aip.zip.extract failed. {err}")))?;
let extracted_files = zip::unzip_file_with_entries_and_globs(&src_zip_path, &dest_dir_path, options.globs.as_ref())
.map_err(|err| Error::custom(format!("aip.zip.extract failed. {err}")))?;
let file_infos: Vec<FileInfo> = extracted_files
.into_iter()
.map(|rel_path| {
let full_path = dest_dir_path.join(&rel_path);
FileInfo::new(dir_context, full_path.clone(), &full_path)
})
.collect();
file_infos.into_lua(lua)
}
fn zip_read_text(lua: &Lua, runtime: &Runtime, src_zip: String, content_path: String) -> mlua::Result<Value> {
let src_zip_path = process_path_reference(runtime, &src_zip)
.map_err(|err| Error::custom(format!("aip.zip.read_text failed. {err}")))?;
match zip::extract_text_content(&src_zip_path, &content_path) {
Ok(content) => content.into_lua(lua),
Err(Error::ZipFileNotFound { .. }) => Ok(Value::Nil),
Err(err) => Err(mlua::Error::external(Error::custom(format!(
"aip.zip.read_text failed. {err}"
)))),
}
}
fn zip_list(lua: &Lua, runtime: &Runtime, src_zip: String, options: Option<Value>) -> mlua::Result<Value> {
let options = ZipOptions::from_lua(options.unwrap_or(Value::Nil), lua)
.map_err(|e| Error::custom(format!("Failed to parse zip options.\nCause: {e}")))?;
let src_zip_path = process_path_reference(runtime, &src_zip)
.map_err(|err| Error::custom(format!("aip.zip.list failed. {err}")))?;
let entries = zip::list_entries_with_globs(&src_zip_path, options.globs.as_ref())
.map_err(|err| Error::custom(format!("aip.zip.list failed. {err}")))?;
entries.into_lua(lua)
}