Documentation
¶
Overview ¶
Package packed ships a folder of embedded text compressed, and unpacks it on the first read.
A folder handed to go:embed lands in the binary verbatim, and prose is the most compressible thing codeaf ships: the v3 chat manual alone is a megabyte of Markdown that is a megabyte of binary. A folder handed to Pack lands as one gzip stream, about a third of that, and the text a caller reads back is identical byte for byte. The raw folder stays in the repository as the source of truth; the archive beside it is generated from the folder by go:generate, regenerated by `make build`, and asserted against it by Verify in the test beside every packed corpus. Nothing is hand-edited.
THE WHOLE FOLDER UNPACKS AT ONCE, ON THE FIRST READ, AND NEVER AGAIN. One stream over every file compresses far better than one stream per file — the pages of a corpus are written in one vocabulary, and gzip's window can only trade on that when they are adjacent — and these corpora are read whole anyway: a manual is indexed entire, a roster is parsed entire. Declaring a folder reads nothing, so a run that never asks it a question never pays for it; `codeaf --version` decompresses none of this.
A Folder is deliberately not an io/fs.FS. An archive has no directories, and a type that half-answers fs.WalkDir is worse than one that never claimed to walk. A caller asks for a name, for a pattern, or for the whole list.
The archive is a gzip stream of entries, each one
uvarint(len(name)) name uvarint(len(data)) data
in Folder.Names order, which is sorted. Pack writes it and Folder reads it; it is not a format anything else is entitled to produce.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Pack ¶
Pack walks a folder and returns the archive New reads. Entry names keep the folder's own base name in front — Pack("chat") names "chat/keys.md" — so the packed names are the names go:embed gave.
It skips what go:embed skips: a name beginning with "." or "_", and anything that is not a regular file. The result is a pure function of the folder's bytes — sorted names, fixed level, no timestamps — so regenerating an unchanged folder rewrites an identical archive and leaves the tree clean. That is what lets `make build` regenerate unconditionally instead of trusting a freshness check.
func Unpacks ¶
func Unpacks() int64
Unpacks is how many packed folders this process has decompressed since it started, across every corpus in the binary.
IT EXISTS SO THAT "THE LAUNCH READS NONE OF THIS" CAN BE A TEST. The package doc above states that law in prose — declaring a folder reads nothing, and `codeaf --version` decompresses none of it — and prose is what a change quietly breaks: one manual lookup moved onto the launch path costs a megabyte of gunzip before the first frame, and nothing would say so. A caller takes the reading either side of the construction it is holding to the law and asserts the difference is zero; counting rather than timing is what makes that assertion the same assertion on every machine.
Types ¶
type Folder ¶
type Folder struct {
// contains filtered or unexported fields
}
Folder is one packed folder, still compressed until something reads it.
func New ¶
New names an archive. Nothing is decompressed here, so a package-level folder costs a pointer at startup and nothing else.
func (*Folder) Glob ¶
Glob returns the packed names matching pattern, in Folder.Names order. The syntax and the ErrBadPattern are io/fs.Glob's, because that is what the callers of a folder were written against.