Allow unpack to accept multiple paks; resolves #10

This commit is contained in:
Truman Kilen 2023-09-17 17:46:27 -05:00
parent 720222ba39
commit 9c9be74946

View file

@ -43,10 +43,10 @@ struct ActionHashList {
struct ActionUnpack { struct ActionUnpack {
/// Input .pak path /// Input .pak path
#[arg(index = 1)] #[arg(index = 1)]
input: String, input: Vec<String>,
/// Output directory. Defaults to next to input pak /// Output directory. Defaults to next to input pak
#[arg(index = 2)] #[arg(short, long)]
output: Option<String>, output: Option<String>,
/// Prefix to strip from entry path /// Prefix to strip from entry path
@ -279,41 +279,47 @@ fn hash_list(aes_key: Option<aes::Aes256>, action: ActionHashList) -> Result<(),
const STYLE: &str = "[{elapsed_precise}] [{wide_bar}] {pos}/{len} ({eta})"; const STYLE: &str = "[{elapsed_precise}] [{wide_bar}] {pos}/{len} ({eta})";
fn unpack(aes_key: Option<aes::Aes256>, action: ActionUnpack) -> Result<(), repak::Error> { fn unpack(aes_key: Option<aes::Aes256>, action: ActionUnpack) -> Result<(), repak::Error> {
let pak = repak::PakReader::new_any_with_optional_key( for input in &action.input {
&mut BufReader::new(File::open(&action.input)?), let pak = repak::PakReader::new_any_with_optional_key(
aes_key, &mut BufReader::new(File::open(input)?),
)?; aes_key.clone(),
let output = action )?;
.output let output = action
.map(PathBuf::from) .output
.unwrap_or_else(|| Path::new(&action.input).with_extension("")); .as_ref()
match fs::create_dir(&output) { .map(PathBuf::from)
Ok(_) => Ok(()), .unwrap_or_else(|| Path::new(input).with_extension(""));
Err(ref e) if e.kind() == std::io::ErrorKind::AlreadyExists => Ok(()), match fs::create_dir(&output) {
Err(e) => Err(e), Ok(_) => Ok(()),
}?; Err(ref e)
if !action.force && output.read_dir()?.next().is_some() { if action.output.is_some() && e.kind() == std::io::ErrorKind::AlreadyExists =>
return Err(repak::Error::OutputNotEmpty( {
output.to_string_lossy().to_string(), Ok(())
)); }
} Err(e) => Err(e),
let mount_point = PathBuf::from(pak.mount_point()); }?;
let prefix = Path::new(&action.strip_prefix); if action.output.is_none() && !action.force && output.read_dir()?.next().is_some() {
return Err(repak::Error::OutputNotEmpty(
output.to_string_lossy().to_string(),
));
}
let mount_point = PathBuf::from(pak.mount_point());
let prefix = Path::new(&action.strip_prefix);
let includes = action let includes = action
.include .include
.iter() .iter()
.map(|i| prefix.join(Path::new(i))) .map(|i| prefix.join(Path::new(i)))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
struct UnpackEntry { struct UnpackEntry {
entry_path: String, entry_path: String,
out_path: PathBuf, out_path: PathBuf,
out_dir: PathBuf, out_dir: PathBuf,
} }
let entries = let entries = pak
pak.files() .files()
.into_iter() .into_iter()
.map(|entry_path| { .map(|entry_path| {
let full_path = mount_point.join(&entry_path); let full_path = mount_point.join(&entry_path);
@ -346,27 +352,33 @@ fn unpack(aes_key: Option<aes::Aes256>, action: ActionUnpack) -> Result<(), repa
.filter_map(|e| e.transpose()) .filter_map(|e| e.transpose())
.collect::<Result<Vec<_>, repak::Error>>()?; .collect::<Result<Vec<_>, repak::Error>>()?;
let progress = indicatif::ProgressBar::new(entries.len() as u64) let progress = indicatif::ProgressBar::new(entries.len() as u64)
.with_style(indicatif::ProgressStyle::with_template(STYLE).unwrap()); .with_style(indicatif::ProgressStyle::with_template(STYLE).unwrap());
entries.par_iter().try_for_each_init( entries.par_iter().try_for_each_init(
|| (progress.clone(), File::open(&action.input)), || (progress.clone(), File::open(input)),
|(progress, file), entry| -> Result<(), repak::Error> { |(progress, file), entry| -> Result<(), repak::Error> {
if action.verbose { if action.verbose {
progress.println(format!("unpacking {}", entry.entry_path)); progress.println(format!("unpacking {}", entry.entry_path));
} }
fs::create_dir_all(&entry.out_dir)?; fs::create_dir_all(&entry.out_dir)?;
pak.read_file( pak.read_file(
&entry.entry_path, &entry.entry_path,
&mut BufReader::new(file.as_ref().unwrap()), // TODO: avoid this unwrap &mut BufReader::new(file.as_ref().unwrap()), // TODO: avoid this unwrap
&mut fs::File::create(&entry.out_path)?, &mut fs::File::create(&entry.out_path)?,
)?; )?;
progress.inc(1); progress.inc(1);
Ok(()) Ok(())
}, },
)?; )?;
progress.finish(); progress.finish();
println!("Unpacked {} files to {}", entries.len(), output.display()); println!(
"Unpacked {} files to {} from {}",
entries.len(),
output.display(),
input
);
}
Ok(()) Ok(())
} }