standard_plugin_cli/
pack.rs1use std::path::Path;
10
11use standard_plugin_manifest::package::{AccountManifest, halves_from_dir, pack, sha256_hex};
12
13#[derive(Clone, Debug)]
15pub struct Packed {
16 pub bytes: Vec<u8>,
17 pub manifest: AccountManifest,
18}
19
20pub fn package(dir: &Path) -> Result<Packed, String> {
23 let (ui, daemon) = halves_from_dir(dir).map_err(|error| error.to_string())?;
24 let bytes = pack(ui.as_ref(), daemon.as_ref()).map_err(|error| error.to_string())?;
25 let manifest =
26 standard_plugin_manifest::package::account_manifest(ui.as_ref(), daemon.as_ref())
27 .map_err(|error| error.to_string())?;
28 Ok(Packed { bytes, manifest })
29}
30
31pub fn content_hash(bytes: &[u8]) -> String {
33 sha256_hex(bytes)
34}
35
36pub fn entry_names(bytes: &[u8]) -> Result<Vec<String>, String> {
38 let mut names = Vec::new();
39 let mut offset = 0;
40 while offset + 512 <= bytes.len() {
41 let header = &bytes[offset..offset + 512];
42 if header.iter().all(|byte| *byte == 0) {
43 break;
44 }
45 let text = |range: std::ops::Range<usize>| {
46 let field = &header[range];
47 let end = field.iter().position(|b| *b == 0).unwrap_or(field.len());
48 String::from_utf8_lossy(&field[..end]).into_owned()
49 };
50 let size = usize::from_str_radix(text(124..136).trim(), 8)
51 .map_err(|_| "malformed tar size".to_string())?;
52 let (name, prefix) = (text(0..100), text(345..500));
53 names.push(if prefix.is_empty() {
54 name
55 } else {
56 format!("{prefix}/{name}")
57 });
58 offset += 512 + size.div_ceil(512) * 512;
59 }
60 Ok(names)
61}