aferobilly

package module
v0.2.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 15, 2026 License: MIT Imports: 8 Imported by: 0

README

aferobilly

Use a go-billy filesystem anywhere an afero one is expected — with optional locking that makes a live handle concurrency-safe

Go Reference Pipeline Coverage phpboyscout Go toolkit

Part of the phpboyscout Go toolkit — small, framework-free Go modules extracted from go-tool-base. Docs: aferobilly.go.phpboyscout.uk


Go has two widely-used filesystem abstractions and they don't speak to each other. go-git hands you a billy.Filesystem for a worktree; most application code — and most testing helpers — are written against afero.Fs.

aferobilly bridges the gap in one direction: give it a billy filesystem, get an afero.Fs.

fs := aferobilly.New(worktree.Filesystem)

// now any afero-based code works against the worktree
data, err := afero.ReadFile(fs, "go.mod")

Design

  • Complete adapter, not a subset. The result is a full afero.Fs — including the optional symlink interfaces — and both file and directory handles are real afero.Files. Directories are synthesised (billy cannot Open one), so Readdir and Stat behave the way os and afero callers expect.
  • Optional locking, and it actually holds. Every operation is serialised through a configurable sync.Locker. Hand it the mutex that guards whatever produced the filesystem and a live afero.Fs handle becomes genuinely safe for concurrent use — each call re-locks, so a handed-out handle can never touch the filesystem unsynchronised.
  • The lock boundary can't be bypassed. The returned Fs and its files expose no accessor for the wrapped billy object, by design. There is no escape hatch to forget to lock.
  • No VCS dependency. go-git is the most likely source of a billy filesystem, but this module never imports it — it works with memfs, osfs, chroot, or your own. A depfootprint_test.go guard keeps go-git out of the build graph.

Install

go get gitlab.com/phpboyscout/go/aferobilly

Concurrency

Without a locker the adapter adds no synchronisation — it is exactly as safe as the billy filesystem underneath:

fs := aferobilly.New(bfs) // no locking

Pass the mutex guarding the producer and every operation serialises against it:

fs := aferobilly.New(repo.Worktree().Filesystem, aferobilly.WithLocker(&repo.mu))

[!WARNING] Do not use the handle — or any file opened from it — inside a critical section that already holds the same locker. Go mutexes are not reentrant, so that self-deadlocks.

Documentation

Full guides: aferobilly.go.phpboyscout.uk. API reference: pkg.go.dev.

License

See LICENSE.

Documentation

Overview

Package aferobilly adapts a go-billy/v5 Filesystem to an afero.Fs, so code written against afero can operate on a billy filesystem unchanged.

The common case is a go-git worktree — go-git hands you a billy filesystem, while most Go application code is written against afero — but the adapter imports no VCS package and works for any billy implementation (memfs, osfs, chroot).

Safety: every Fs and File operation is serialised through a configurable sync.Locker (default: a no-op). Pass WithLocker the same mutex that guards whatever produces the filesystem — a repository handle, a pool, a cache — and a live afero.Fs becomes genuinely safe for concurrent use: each operation re-locks, so the handle can never touch the underlying filesystem unsynchronised.

The returned afero.Fs and its Files deliberately expose no accessor for the wrapped billy object, so the lock boundary cannot be bypassed.

The corresponding footgun: a handle (and any file opened from it) must NOT be used inside a critical section that already holds the same locker. Standard Go mutexes are not reentrant, so that self-deadlocks.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func New

func New(bfs billy.Filesystem, opts ...Option) afero.Fs

New returns an afero.Fs backed by bfs. See the package doc for the locking contract.

Types

type Option

type Option func(*billyFs)

Option configures the adapter.

func WithLocker

func WithLocker(l sync.Locker) Option

WithLocker serialises every Fs and File operation through l. Pass the mutex that guards the filesystem's producer (e.g. a ThreadSafeRepo's mutex) to make a live handle concurrency-safe. A nil locker is ignored (the no-op default is kept).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL