split store constructors into own files: tools.go, root.go

This commit is contained in:
Levi Neely 2026-05-19 17:47:13 +02:00
parent 46c025b594
commit 6b1ba9a998
3 changed files with 108 additions and 90 deletions

57
root.go Normal file
View File

@ -0,0 +1,57 @@
package main
import (
"context"
"fmt"
"os"
"strings"
"ollie/pkg/backend"
"ollie/pkg/paths"
"olliesrv/store"
)
// NewRootStore returns a read-only Store for synthetic root-level files.
func NewRootStore() *store.DirStore {
helpPath := paths.CfgDir() + "/help.md"
entries := map[string]func() ([]byte, error){
"backends": func() ([]byte, error) {
return []byte(strings.Join(backend.Backends(), "\n") + "\n"), nil
},
"help": func() ([]byte, error) {
return os.ReadFile(helpPath)
},
}
notBlocking := func(context.Context, string) ([]byte, string, error) {
return nil, "", fmt.Errorf("blocking read not supported")
}
readOnly := func([]byte) error { return fmt.Errorf("read-only") }
return store.NewDirStore(nil, 0444,
store.WithReadOnly(),
store.WithResolver(func(_ []string, name string) (string, error) {
if _, ok := entries[name]; ok {
return name, nil
}
return "", fmt.Errorf("%s: not found", name)
}),
store.WithLister(func(_ []string) ([]os.DirEntry, error) {
return []os.DirEntry{
syntheticEntry("backends", 0444),
syntheticEntry("help", 0444),
}, nil
}),
store.WithOpener(func(_ []string, name string) (StoreEntry, error) {
readFn, ok := entries[name]
if !ok {
return nil, fmt.Errorf("%s: not found", name)
}
return &store.EntryConfig{
StatFn: func() (os.FileInfo, error) { return &syntheticFileInfo{Name_: name, Mode_: 0444}, nil },
ReadFn: readFn,
WriteFn: readOnly,
BlockingReadFn: notBlocking,
}, nil
}),
)
}

View File

@ -42,96 +42,6 @@ func syntheticDirEntry(name string, mode os.FileMode) os.DirEntry {
return store.DirEntry(name, mode)
}
// toolIndex generates a tool index from a store's file listing.
func toolIndex(s Store) ([]byte, error) {
entries, err := s.List()
if err != nil {
return nil, err
}
var sb strings.Builder
for _, e := range entries {
if e.IsDir() || e.Name() == "idx" {
continue
}
entry, err := s.Open(e.Name())
if err != nil {
continue
}
data, err := entry.Read()
if err != nil {
continue
}
var desc, args string
for line := range strings.SplitSeq(string(data), "\n") {
if d, ok := strings.CutPrefix(line, "# description:"); ok {
desc = strings.TrimSpace(d)
} else if a, ok := strings.CutPrefix(line, "# Args:"); ok {
args = strings.TrimSpace(a)
} else if a, ok := strings.CutPrefix(line, "# args:"); ok {
args = strings.TrimSpace(a)
}
if !strings.HasPrefix(line, "#") && line != "" {
break
}
}
if desc == "" {
continue
}
fmt.Fprintf(&sb, "## %s\n", e.Name())
fmt.Fprintf(&sb, "description: %s\n", desc)
if args != "" {
fmt.Fprintf(&sb, "args: %s\n", args)
}
sb.WriteString("\n")
}
return []byte(sb.String()), nil
}
// NewRootStore returns a read-only Store for synthetic root-level files.
func NewRootStore() *store.DirStore {
helpPath := paths.CfgDir() + "/help.md"
entries := map[string]func() ([]byte, error){
"backends": func() ([]byte, error) {
return []byte(strings.Join(backend.Backends(), "\n") + "\n"), nil
},
"help": func() ([]byte, error) {
return os.ReadFile(helpPath)
},
}
notBlocking := func(context.Context, string) ([]byte, string, error) {
return nil, "", fmt.Errorf("blocking read not supported")
}
readOnly := func([]byte) error { return fmt.Errorf("read-only") }
return store.NewDirStore(nil, 0444,
store.WithReadOnly(),
store.WithResolver(func(_ []string, name string) (string, error) {
if _, ok := entries[name]; ok {
return name, nil // virtual path, handled by opener
}
return "", fmt.Errorf("%s: not found", name)
}),
store.WithLister(func(_ []string) ([]os.DirEntry, error) {
return []os.DirEntry{
syntheticEntry("backends", 0444),
syntheticEntry("help", 0444),
}, nil
}),
store.WithOpener(func(_ []string, name string) (StoreEntry, error) {
readFn, ok := entries[name]
if !ok {
return nil, fmt.Errorf("%s: not found", name)
}
return &store.EntryConfig{
StatFn: func() (os.FileInfo, error) { return &syntheticFileInfo{Name_: name, Mode_: 0444}, nil },
ReadFn: readFn,
WriteFn: readOnly,
BlockingReadFn: notBlocking,
}, nil
}),
)
}
const (
QTDir = plan9.QTDIR
QTFile = plan9.QTFILE

51
tools.go Normal file
View File

@ -0,0 +1,51 @@
package main
import (
"fmt"
"strings"
)
// toolIndex generates a tool index from a store's file listing.
func toolIndex(s Store) ([]byte, error) {
entries, err := s.List()
if err != nil {
return nil, err
}
var sb strings.Builder
for _, e := range entries {
if e.IsDir() || e.Name() == "idx" {
continue
}
entry, err := s.Open(e.Name())
if err != nil {
continue
}
data, err := entry.Read()
if err != nil {
continue
}
var desc, args string
for line := range strings.SplitSeq(string(data), "\n") {
if d, ok := strings.CutPrefix(line, "# description:"); ok {
desc = strings.TrimSpace(d)
} else if a, ok := strings.CutPrefix(line, "# Args:"); ok {
args = strings.TrimSpace(a)
} else if a, ok := strings.CutPrefix(line, "# args:"); ok {
args = strings.TrimSpace(a)
}
if !strings.HasPrefix(line, "#") && line != "" {
break
}
}
if desc == "" {
continue
}
fmt.Fprintf(&sb, "## %s\n", e.Name())
fmt.Fprintf(&sb, "description: %s\n", desc)
if args != "" {
fmt.Fprintf(&sb, "args: %s\n", args)
}
sb.WriteString("\n")
}
return []byte(sb.String()), nil
}