fix(virtfs): support Each() with non-template directory names
Each('peer', ...) creates a named directory whose children come from
Bindings(). Previously, listDir and findChild only checked Bindings
for template names like {foo}. Now they also handle directories that
have Bindings but no Children.
This fixes the peer/ directory in olliesrv which was listing empty
even though peers were configured via peeradd.
Added test for the non-template Each pattern.
This commit is contained in:
parent
8960fb73fd
commit
2a34c4719a
|
|
@ -125,6 +125,27 @@ func build(d *FsNodeDecl, parentUid, parentGid string) *Tree {
|
||||||
|
|
||||||
func listDir(d *FsNodeDecl, uid, gid string) ([]os.DirEntry, error) {
|
func listDir(d *FsNodeDecl, uid, gid string) ([]os.DirEntry, error) {
|
||||||
var entries []os.DirEntry
|
var entries []os.DirEntry
|
||||||
|
|
||||||
|
// If this directory has Bindings (from Each), enumerate them directly.
|
||||||
|
if d.Bindings != nil && len(d.Children) == 0 {
|
||||||
|
nodes, err := d.Bindings()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, n := range nodes {
|
||||||
|
m := n.Mode
|
||||||
|
if m == 0 {
|
||||||
|
m = d.Mode
|
||||||
|
}
|
||||||
|
if len(n.Children) > 0 || n.Bindings != nil {
|
||||||
|
entries = append(entries, dirEntry(n.Name, 0755))
|
||||||
|
} else {
|
||||||
|
entries = append(entries, fileEntry(n.Name, m))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entries, nil
|
||||||
|
}
|
||||||
|
|
||||||
for _, c := range d.Children {
|
for _, c := range d.Children {
|
||||||
if isTemplateName(c.Name) {
|
if isTemplateName(c.Name) {
|
||||||
if c.Bindings != nil {
|
if c.Bindings != nil {
|
||||||
|
|
@ -355,6 +376,21 @@ func findChild(d *FsNodeDecl, name string) *FsNodeDecl {
|
||||||
return findChild(child, rest)
|
return findChild(child, rest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this directory has Bindings and no Children (from Each with non-template name),
|
||||||
|
// look up children in the bindings directly.
|
||||||
|
if d.Bindings != nil && len(d.Children) == 0 {
|
||||||
|
entries, err := d.Bindings()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for i := range entries {
|
||||||
|
if entries[i].Name == name || matchAlias(entries[i].Aliases, name) {
|
||||||
|
return &entries[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Static children.
|
// Static children.
|
||||||
for i := range d.Children {
|
for i := range d.Children {
|
||||||
if !isTemplateName(d.Children[i].Name) && d.Children[i].Name == name {
|
if !isTemplateName(d.Children[i].Name) && d.Children[i].Name == name {
|
||||||
|
|
|
||||||
|
|
@ -668,6 +668,66 @@ func TestNestedPath(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ══════════════════════════════════════════════════════════════════
|
||||||
|
// Each with non-template name (like "peer/")
|
||||||
|
// ══════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
func TestEachNonTemplateName(t *testing.T) {
|
||||||
|
// This tests the pattern used by peer/ in olliesrv:
|
||||||
|
// Each("peer", ...) creates a directory whose children come from Bindings
|
||||||
|
writeData := ""
|
||||||
|
spec := DirNode("/",
|
||||||
|
Each("peer", func() ([]FsNodeDecl, error) {
|
||||||
|
return []FsNodeDecl{
|
||||||
|
{Name: "alice", Mode: 0222, Write: func(data []byte) error { writeData = string(data); return nil }},
|
||||||
|
{Name: "bob", Mode: 0222, Write: func(data []byte) error { writeData = string(data); return nil }},
|
||||||
|
}, nil
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
tree := BuildTree(spec)
|
||||||
|
|
||||||
|
// List root should show "peer" as a directory
|
||||||
|
entries, err := tree.List()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("List root: %v", err)
|
||||||
|
}
|
||||||
|
if len(entries) != 1 {
|
||||||
|
t.Fatalf("got %d root entries, want 1", len(entries))
|
||||||
|
}
|
||||||
|
if entries[0].Name() != "peer" || !entries[0].IsDir() {
|
||||||
|
t.Errorf("root entry = %v (dir=%v), want peer dir", entries[0].Name(), entries[0].IsDir())
|
||||||
|
}
|
||||||
|
|
||||||
|
// List peer/ should show alice and bob
|
||||||
|
entries, err = tree.Readdir("peer")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Readdir peer: %v", err)
|
||||||
|
}
|
||||||
|
if len(entries) != 2 {
|
||||||
|
t.Fatalf("got %d peer entries, want 2", len(entries))
|
||||||
|
}
|
||||||
|
names := map[string]bool{}
|
||||||
|
for _, e := range entries {
|
||||||
|
names[e.Name()] = true
|
||||||
|
}
|
||||||
|
if !names["alice"] || !names["bob"] {
|
||||||
|
t.Errorf("peer entries = %v, want alice and bob", entries)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open and write to peer/alice
|
||||||
|
f, err := tree.Open("peer/alice")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Open peer/alice: %v", err)
|
||||||
|
}
|
||||||
|
if err := f.Write([]byte("hello")); err != nil {
|
||||||
|
t.Fatalf("Write: %v", err)
|
||||||
|
}
|
||||||
|
if writeData != "hello" {
|
||||||
|
t.Errorf("writeData = %q, want hello", writeData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ══════════════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════════════
|
||||||
// GenerateHelp test
|
// GenerateHelp test
|
||||||
// ══════════════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════════════
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue