144 lines
4.2 KiB
Markdown
144 lines
4.2 KiB
Markdown
# virtfs
|
|
|
|
A Go library for declaring synthetic filesystems. Define your namespace structure statically, populate it dynamically at runtime with closures.
|
|
|
|
Produces a `*Tree` usable with any filesystem protocol (9P, FUSE, etc.) or as an in-memory filesystem for testing.
|
|
|
|
## Design
|
|
|
|
Handlers are plain closures that capture their state at binding time. There is no context type parameter — each handler already knows its target via closure capture.
|
|
|
|
Dynamic subtrees use `Each`: a bindings function returns `[]Binding`, where each binding carries pre-bound `Children` (fully-wired subtrees with their own closures).
|
|
|
|
## Quick Start
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"ollie/virtfs"
|
|
)
|
|
|
|
type User struct {
|
|
ID string
|
|
Name string
|
|
}
|
|
|
|
var users = []*User{
|
|
{ID: "1", Name: "alice"},
|
|
{ID: "2", Name: "bob"},
|
|
}
|
|
|
|
func main() {
|
|
spec := virtfs.DirNode("/",
|
|
virtfs.FileNode("version", 0444,
|
|
virtfs.Doc("API version"),
|
|
virtfs.Read(func() ([]byte, error) {
|
|
return []byte("1.0\n"), nil
|
|
}),
|
|
),
|
|
virtfs.Each("{user}", func() ([]virtfs.Binding, error) {
|
|
var out []virtfs.Binding
|
|
for _, u := range users {
|
|
user := u // capture
|
|
out = append(out, virtfs.Binding{
|
|
Name: user.Name,
|
|
Aliases: []string{user.ID},
|
|
Children: []virtfs.FsNodeDecl{
|
|
virtfs.FileNode("id", 0444,
|
|
virtfs.Read(func() ([]byte, error) {
|
|
return []byte(user.ID + "\n"), nil
|
|
}),
|
|
),
|
|
virtfs.FileNode("name", 0444,
|
|
virtfs.Read(func() ([]byte, error) {
|
|
return []byte(user.Name + "\n"), nil
|
|
}),
|
|
),
|
|
},
|
|
})
|
|
}
|
|
return out, nil
|
|
}),
|
|
)
|
|
|
|
tree := virtfs.BuildTree(spec)
|
|
|
|
entries, _ := tree.List()
|
|
for _, e := range entries {
|
|
fmt.Println(e.Name())
|
|
}
|
|
|
|
f, _ := tree.Open("alice/name")
|
|
data, _ := f.Read()
|
|
fmt.Printf("alice/name: %s", data)
|
|
}
|
|
```
|
|
|
|
## API
|
|
|
|
### Constructors
|
|
|
|
| Function | Description |
|
|
|----------|-------------|
|
|
| `DirNode(name, children/options...)` | Static directory |
|
|
| `FileNode(name, mode, options...)` | File with handlers |
|
|
| `Each(name, bindingsFn, options...)` | Dynamic directory — children come from bindings |
|
|
|
|
### Options (NodeOption)
|
|
|
|
| Option | Signature | Description |
|
|
|--------|-----------|-------------|
|
|
| `Read(fn)` | `func() ([]byte, error)` | Non-blocking read |
|
|
| `Write(fn)` | `func([]byte) error` | Write handler |
|
|
| `Stream(fn)` | `func(context.Context, string) ([]byte, string, error)` | Blocking streaming read |
|
|
| `BlockOnce(fn)` | `func(context.Context, string) ([]byte, string, error)` | Blocking read, returns once |
|
|
| `Request(fn)` | `func([]byte) ([]byte, error)` | Write-then-read (rdwr) |
|
|
| `Doc(desc)` | `string` | Human-readable description |
|
|
| `UID(uid)` | `string` | Set owner |
|
|
| `GID(gid)` | `string` | Set group |
|
|
| `StatOverride(fn)` | `func() os.FileInfo` | Custom stat |
|
|
| `RemoveNode(fn)` | `func() error` | Removal handler |
|
|
|
|
### Binding
|
|
|
|
Returned by the `Each` bindings function. Each binding represents one dynamic child.
|
|
|
|
```go
|
|
virtfs.Binding{
|
|
Name: "alice",
|
|
Aliases: []string{"user-id-123"},
|
|
Children: []virtfs.FsNodeDecl{ ... }, // pre-bound subtree
|
|
Remove: func() { ... }, // optional
|
|
Rename: func(newName string) error { ... }, // optional
|
|
}
|
|
```
|
|
|
|
Children are fully-wired — their handlers are closures that already captured the specific instance (no applier/context needed).
|
|
|
|
### Tree Operations
|
|
|
|
```go
|
|
tree := virtfs.BuildTree(spec)
|
|
|
|
tree.List() // list root entries
|
|
tree.Stat(name) // stat a path
|
|
tree.Open(name) // open file for read/write
|
|
tree.Create(name) // create file
|
|
tree.Delete(name) // remove file
|
|
tree.Rename(old, new) // rename file
|
|
tree.Readdir(path) // list subdirectory
|
|
```
|
|
|
|
### Help Generation
|
|
|
|
```go
|
|
help := virtfs.GenerateHelp(spec)
|
|
// Produces formatted docs from Doc() annotations
|
|
```
|
|
|
|
## License
|
|
|
|
GPLv3
|