Add support to unpack archive files

This commit is contained in:
2025-06-07 13:12:41 +08:00
parent ddb54da46c
commit eaee52d64d
3 changed files with 153 additions and 2 deletions

View File

@@ -132,12 +132,20 @@ pub enum Command {
},
/// Import to script
Import(ImportArgs),
/// Pack files to archive
Pack {
/// Input directory
input: String,
/// Output archive file
output: Option<String>,
},
/// Unpack archive to directory
Unpack {
/// Input archive file
input: String,
/// Output directory
output: Option<String>,
},
}
pub fn parse_args() -> Arg {

View File

@@ -975,6 +975,73 @@ pub fn pack_archive(
Ok(())
}
pub fn unpack_archive(
filename: &str,
arg: &args::Arg,
config: &types::ExtraConfig,
output: &Option<String>,
is_dir: bool,
) -> anyhow::Result<types::ScriptResult> {
eprintln!("Unpacking {}", filename);
let mut script = parse_script(filename, arg, config)?.0;
if !script.is_archive() {
return Ok(types::ScriptResult::Ignored);
}
let odir = match output.as_ref() {
Some(output) => {
let mut pb = std::path::PathBuf::from(output);
let filename = std::path::PathBuf::from(filename);
if is_dir {
if let Some(fname) = filename.file_name() {
pb.push(fname);
}
}
pb.to_string_lossy().into_owned()
}
None => {
let mut pb = std::path::PathBuf::from(filename);
pb.set_extension("");
pb.to_string_lossy().into_owned()
}
};
if !std::fs::exists(&odir)? {
std::fs::create_dir_all(&odir)?;
}
for f in script.iter_archive_mut()? {
let f = f?;
let out_path = std::path::PathBuf::from(&odir).join(f.name());
match utils::files::make_sure_dir_exists(&out_path) {
Ok(_) => {}
Err(e) => {
eprintln!(
"Error creating parent directory for {}: {}",
out_path.display(),
e
);
COUNTER.inc_error();
continue;
}
}
match utils::files::write_file(&out_path) {
Ok(mut fi) => match fi.write_all(f.data()) {
Ok(_) => {}
Err(e) => {
eprintln!("Error writing to file {}: {}", out_path.display(), e);
COUNTER.inc_error();
continue;
}
},
Err(e) => {
eprintln!("Error writing file {}: {}", out_path.display(), e);
COUNTER.inc_error();
continue;
}
}
COUNTER.inc(types::ScriptResult::Ok);
}
Ok(types::ScriptResult::Ok)
}
lazy_static::lazy_static! {
static ref COUNTER: utils::counter::Counter = utils::counter::Counter::new();
}
@@ -1089,6 +1156,40 @@ fn main() {
eprintln!("Error packing archive: {}", e);
}
}
args::Command::Unpack { input, output } => {
let (scripts, is_dir) = utils::files::collect_arc_files(input, arg.recursive).unwrap();
if is_dir {
match &output {
Some(output) => {
let op = std::path::Path::new(output);
if op.exists() {
if !op.is_dir() {
eprintln!("Output path is not a directory");
return;
}
} else {
std::fs::create_dir_all(op).unwrap();
}
}
None => {}
}
}
for script in scripts.iter() {
let re = unpack_archive(&script, &arg, &cfg, output, is_dir);
match re {
Ok(s) => {
COUNTER.inc(s);
}
Err(e) => {
COUNTER.inc_error();
eprintln!("Error unpacking {}: {}", script, e);
if arg.backtrace {
eprintln!("Backtrace: {}", e.backtrace());
}
}
}
}
}
}
eprintln!("{}", std::ops::Deref::deref(&COUNTER));
}

View File

@@ -1,10 +1,9 @@
use crate::scripts::{ALL_EXTS, ARCHIVE_EXTS};
use std::fs;
use std::io;
use std::io::{Read, Write};
use std::path::Path;
use crate::scripts::ALL_EXTS;
pub fn find_files(path: &str, recursive: bool, no_ext_filter: bool) -> io::Result<Vec<String>> {
let mut result = Vec::new();
let dir_path = Path::new(&path);
@@ -36,6 +35,35 @@ pub fn find_files(path: &str, recursive: bool, no_ext_filter: bool) -> io::Resul
Ok(result)
}
pub fn find_arc_files(path: &str, recursive: bool) -> io::Result<Vec<String>> {
let mut result = Vec::new();
let dir_path = Path::new(&path);
if dir_path.is_dir() {
for entry in fs::read_dir(dir_path)? {
let entry = entry?;
let path = entry.path();
if path.is_file()
&& path.extension().map_or(false, |ext| {
ARCHIVE_EXTS.contains(&ext.to_string_lossy().to_lowercase())
})
{
if let Some(path_str) = path.to_str() {
result.push(path_str.to_string());
}
} else if recursive && path.is_dir() {
if let Some(path_str) = path.to_str() {
let mut sub_files = find_arc_files(&path_str.to_string(), recursive)?;
result.append(&mut sub_files);
}
}
}
}
Ok(result)
}
pub fn collect_files(
path: &str,
recursive: bool,
@@ -54,6 +82,20 @@ pub fn collect_files(
))
}
pub fn collect_arc_files(path: &str, recursive: bool) -> io::Result<(Vec<String>, bool)> {
let pa = Path::new(path);
if pa.is_dir() {
return Ok((find_arc_files(path, recursive)?, true));
}
if pa.is_file() {
return Ok((vec![path.to_string()], false));
}
Err(io::Error::new(
io::ErrorKind::NotFound,
format!("Path {} is neither a file nor a directory", pa.display()),
))
}
pub fn read_file<F: AsRef<Path> + ?Sized>(f: &F) -> io::Result<Vec<u8>> {
let mut content = Vec::new();
if f.as_ref() == Path::new("-") {