// Copyright 2024 Matthew Rich . All rights reserved. package config import ( _ "context" _ "encoding/json" _ "fmt" _ "gopkg.in/yaml.v3" "net/url" "path/filepath" "decl/internal/codec" "os" "io" "errors" "io/fs" "log/slog" ) type ConfigFS struct { Path string `yaml:"path" json:"path"` subDirsStack []fs.FS `yaml:"-" json:"-"` fsys fs.FS `yaml:"-" json:"-"` } func NewConfigFS(fsys fs.FS) *ConfigFS { return &ConfigFS{ subDirsStack: make([]fs.FS, 0, 100), fsys: fsys, } } func init() { ConfigSourceTypes.Register([]string{"fs"}, func(u *url.URL) ConfigSource { t := NewConfigFS(nil) t.Path,_ = filepath.Abs(filepath.Join(u.Hostname(), u.RequestURI())) t.fsys = os.DirFS(t.Path) return t }) } func (c *ConfigFS) Type() string { return "fs" } func (c *ConfigFS) ExtractDirectory(fsys fs.FS) ([]*Document, error) { documents := make([]*Document, 0, 100) files, err := fs.ReadDir(fsys, ".") if err != nil { return nil, err } for _,file := range files { slog.Info("ConfigFS.ExtractDirectory", "file", file) if file.IsDir() { dir, subErr := fs.Sub(fsys, file.Name()) if subErr != nil { return nil, subErr } c.subDirsStack = append(c.subDirsStack, dir) } else { fileHandle, fileErr := fsys.Open(file.Name()) if fileErr != nil { return nil, fileErr } decoder := codec.NewYAMLDecoder(fileHandle) doc := NewDocument() e := decoder.Decode(doc) if errors.Is(e, io.EOF) { break } if e != nil { return documents, e } slog.Info("ConfigFS.ExtractDirectory", "doc", doc) if validationErr := doc.Validate(); validationErr != nil { return documents, validationErr } documents = append(documents, doc) } } return documents, nil } func (c *ConfigFS) Extract(filter ConfigurationSelector) ([]*Document, error) { documents := make([]*Document, 0, 100) path := c.fsys c.subDirsStack = append(c.subDirsStack, path) for { if len(c.subDirsStack) == 0 { break } var dirPath fs.FS dirPath, c.subDirsStack = c.subDirsStack[len(c.subDirsStack) - 1], c.subDirsStack[:len(c.subDirsStack) - 1] docs, dirErr := c.ExtractDirectory(dirPath) if dirErr != nil { return documents, dirErr } documents = append(documents, docs...) } return documents, nil }