API reference¶
The package exports three symbols. This page is the authoritative description of each: signature, default, and what happens when you get it wrong. The generated Go documentation is on pkg.go.dev.
Import path:
New — build an afero.Fs from a billy filesystem¶
Returns an afero.Fs backed by bfs. The concrete type is unexported; the only way to
reach it is through the afero.Fs interface and the optional interfaces below.
Parameter bfs |
Any billy.Filesystem. This is the full billy interface (Basic + TempFile + Dir + Symlink + Chroot), not billy.Basic — a Basic-only value will not compile. |
| Returns | afero.Fs. Never nil, and never an error — construction cannot fail. |
| Default locker | A no-op. Without WithLocker the adapter adds no synchronisation of its own. |
What New does at construction time¶
Exactly one thing: it calls bfs.Root() once and stores the result as the value
Name() will return. Nothing is opened, stat-ed or validated. A
filesystem pointing at a path that does not exist constructs happily and fails at the
first operation.
What happens if you pass nil¶
New(nil) panics immediately with runtime error: invalid memory address or nil pointer
dereference, because the constructor calls bfs.Root(). There is no nil check and no
error return: a nil filesystem is a programming error, not a supported input.
Option — the functional-option type¶
Option is exported but its parameter type is not, so you cannot write your own
Option outside this package. It exists so the constructor signature can grow without
a breaking change. WithLocker is currently the only implementation.
WithLocker — serialise every operation through a lock¶
Acquires l around every Fs operation and every File operation, then releases it
before returning.
Parameter l |
Any sync.Locker — a *sync.Mutex, a *sync.RWMutex, or your own type. |
nil argument |
Ignored. The no-op default is kept and no error or panic is raised, so WithLocker(nil) silently produces an unlocked filesystem. |
| Applied at | Construction. The locker cannot be changed afterwards. |
| Scope | Per handle. Two New calls over the same billy filesystem with different lockers do not serialise against each other. |
Which mutex to pass¶
Pass the mutex that guards whatever produced the filesystem — a repository handle, a pool, a cache — not a fresh mutex created for the adapter. A fresh mutex only protects the adapter's own callers from each other; the producer can still touch the underlying filesystem concurrently. Sharing the producer's mutex is what makes an escaped handle safe. See make a handle concurrency-safe.
The locking is per operation, not per sequence¶
Each call takes and releases the lock. Two calls in a row are two critical sections with a gap between them, so a read-modify-write through the handle is not atomic. Holding the lock yourself across the sequence is the fix — and doing so with a handle configured with that same lock deadlocks, because Go mutexes are not reentrant. Both limits are worked through in make a handle concurrency-safe.
Optional interfaces the returned Fs satisfies¶
Type-assert the returned value to reach these. The package asserts afero.Fs,
afero.Lstater and afero.Symlinker at compile time, and afero.Symlinker is defined as
Lstater + Linker + LinkReader — so none of these assertions can fail for a value that
came from New.
| Interface | Methods | Notes |
|---|---|---|
afero.Lstater |
LstatIfPossible |
The returned bool is always true — billy.Filesystem always declares Lstat. |
afero.Linker |
SymlinkIfPossible |
Argument order is afero's (oldname, newname), mapped to billy's Symlink(target, link). |
afero.LinkReader |
ReadlinkIfPossible |
|
afero.Symlinker |
all of the above | afero.Symlinker is defined as Lstater + Linker + LinkReader. |
fs := aferobilly.New(bfs)
if sl, ok := fs.(afero.Symlinker); ok {
_ = sl.SymlinkIfPossible("/target", "/link")
}
There is no accessor for the wrapped billy filesystem¶
Deliberately. Neither the Fs nor its files expose the underlying billy.Filesystem or
billy.File, so there is no way to perform an operation that skips the locker. If you
need the billy value, keep your own reference to what you passed to New.
Related¶
- Filesystem operations — every
afero.Fsandafero.Filemethod. - billy backend support — what each billy backend actually honours.
- What this does not do