use std::path::Path;
use standard_plugin_manifest::package::{AccountManifest, halves_from_dir, pack, sha256_hex};
#[derive(Clone, Debug)]
pub struct Packed {
pub bytes: Vec<u8>,
pub manifest: AccountManifest,
}
pub fn package(dir: &Path) -> Result<Packed, String> {
let (ui, daemon) = halves_from_dir(dir).map_err(|error| error.to_string())?;
let bytes = pack(ui.as_ref(), daemon.as_ref()).map_err(|error| error.to_string())?;
let manifest =
standard_plugin_manifest::package::account_manifest(ui.as_ref(), daemon.as_ref())
.map_err(|error| error.to_string())?;
Ok(Packed { bytes, manifest })
}
pub fn content_hash(bytes: &[u8]) -> String {
sha256_hex(bytes)
}
pub fn entry_names(bytes: &[u8]) -> Result<Vec<String>, String> {
let mut names = Vec::new();
let mut offset = 0;
while offset + 512 <= bytes.len() {
let header = &bytes[offset..offset + 512];
if header.iter().all(|byte| *byte == 0) {
break;
}
let text = |range: std::ops::Range<usize>| {
let field = &header[range];
let end = field.iter().position(|b| *b == 0).unwrap_or(field.len());
String::from_utf8_lossy(&field[..end]).into_owned()
};
let size = usize::from_str_radix(text(124..136).trim(), 8)
.map_err(|_| "malformed tar size".to_string())?;
let (name, prefix) = (text(0..100), text(345..500));
names.push(if prefix.is_empty() {
name
} else {
format!("{prefix}/{name}")
});
offset += 512 + size.div_ceil(512) * 512;
}
Ok(names)
}