use super::headers::NewHeader;
use super::ArchiveEntity;
use crate::GlobalsFinal;
use anyhow::Result as AResult;
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufReader, BufWriter};
use std::path::Path;
use tar::{Archive, Builder};
use xz2::{read::XzDecoder, write::XzEncoder};
const MB: u64 = 2u64.pow(20);
pub(super) fn convert(src: &Path, dst: &Path, globals: &GlobalsFinal) -> AResult<()> {
let src = File::open(src)?;
let src = BufReader::new(src);
let src = XzDecoder::new(src);
let mut src = Archive::new(src);
let mut dst = if globals.dry_run() {
None
} else {
let dst = File::create(dst)?;
let dst = BufWriter::new(dst);
let dst = XzEncoder::new(dst, 9);
Some(Builder::new(dst))
};
let mut sigma = 0;
let mut count = 0;
let mut typecount = HashMap::new();
let bar = globals.spinner();
for entry in src.entries()? {
let mut entry = entry?;
let entity = ArchiveEntity::identify(&mut entry)?;
{
count += 1;
let delta = entry.size();
sigma += delta;
let sigma = sigma / MB;
let delta = delta / MB;
let msg = format!("[#:{count:>5}, Δ:{delta:>3} MiB, Σ:{sigma:>4} MiB] {entity}");
bar.set_message(msg);
bar.tick();
let entity = format!("{entity}");
let x = 1i32 + typecount.get(&entity).unwrap_or(&0);
typecount.insert(entity, x);
}
match NewHeader::create(&entity, globals)? {
NewHeader::Primary { mut header, path } => {
if let Some(ref mut dst) = dst {
dst.append_data(&mut header, path, &mut entry)?;
}
}
NewHeader::Link {
mut header,
path,
target,
} => {
if let Some(ref mut dst) = dst {
dst.append_link(&mut header, path, target)?;
}
}
}
}
if let Some(ref mut dst) = dst {
dst.finish()?;
}
bar.finish();
log::info!("Remapping completed. Flushing buffers");
for (stype, count) in typecount.iter() {
log::info!("- {stype:<16} : {count:>5}");
}
Ok(())
}