aferobilly¶
Go has two filesystem abstractions and they don't speak to each other. This bridges
them in one direction: give it a go-billy
filesystem, get an afero.Fs.
fs := aferobilly.New(worktree.Filesystem)
data, err := afero.ReadFile(fs, "go.mod") // afero code, billy filesystem
The usual reason you need this: go-git exposes a
worktree as billy.Filesystem, while most application code — and most test helpers —
are written against afero.Fs. Rather than copying the tree out and syncing it back,
work against it live.
Why¶
- A complete adapter, not a subset. A full
afero.Fsincluding the optional symlink interfaces, with realafero.Filehandles for files and directories. The awkward corners where billy and afero disagree are resolved deliberately — see billy vs afero semantics. - Optional locking that actually holds. Every
FsandFileoperation is serialised through async.Lockeryou supply. Hand it the mutex guarding whatever produced the filesystem and a handle stays safe even after the reference escapes. - The lock boundary can't be bypassed. The returned
Fsexposes no accessor for the underlying billy object — by design, so there is no way to forget to lock. - No VCS dependency. go-git is the common source of a billy filesystem, but this
module never imports it and works with
memfs,osfs,chroot, or your own. A dependency guard keeps it that way.
Where next¶
- Getting started — bridge an in-memory billy filesystem in a few lines.
- Work with a go-git worktree — the flagship use case, read and write live.
- Make a handle concurrency-safe —
what
WithLockerguarantees, and the two footguns. - billy vs afero semantics — every place the two interfaces disagree, and what the adapter does about it.
Reference¶
The API is three symbols — New, Option, WithLocker — documented on
pkg.go.dev.