embala-pkg 0.0.1

macOS .pkg builder — flat packages (xar + BOM + cpio payload), on any OS
Documentation

macOS flat-package (.pkg) builder — product archives on any OS.

[build] writes the same shape productbuild emits: a xar archive holding a Distribution script plus a <name>.pkg/ component directory with PackageInfo, Bom, and a gzipped odc-cpio Payload. Every layer was pinned against Apple tooling on macOS 26.5 (pkgbuild/productbuild output dissected byte-by-byte; results verified with pkgutil --expand-full, lsbom, and installer).

Lower-level pieces are public for reuse and testing: [write_xar] (xar archives with nested directories) and [write_bom] (Bill of Materials over a staged tree).

Spike outcomes the implementation rests on:

  • xar: apple-xar 0.20 has no turn-key writer, but its primitives compose: TableOfContents/File/FileData are public with to_xml(), ChecksumType::digest_data provides digests, and XarHeader derives scroll IOwrite. The only wrinkle is that TableOfContents's inner field is private with no constructor, so we bootstrap one by parsing a minimal template TOC via from_reader and mutating it through its DerefMut<Target = XarToC> impl. No hand-rolled writer needed.
  • BOM: apple-bom 0.3's shipped BomBuilder is unusable — its build_bom() panics unconditionally, and beneath that lie a dozen more writer bugs (wrong checksum algorithm, wrong B-tree order, missing free list, ...; see bom_builder.rs for the catalog). Bounded fallback taken: bom_builder ports the assembly on top of apple-bom's public format types with those fixes; the output matches both mkbom and pkgbuild's embedded Bom under lsbom -p fmugsc (paths, modes, uid, gid, size, cksum). Per-file modes must include the file-type bits (e.g. 0o100755).
  • cpio: the Payload is odc/ASCII cpio (magic 070707), hand-rolled here because the format is a 76-byte octal header and pkgbuild's conventions (sequential inodes, dir nlink = 2 + children, zero pad to a 512-byte boundary) need exact control no crate offered.