2024-07-01 21:54:18 +00:00
|
|
|
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
|
|
|
|
|
|
|
|
package config
|
|
|
|
|
|
|
|
import (
|
|
|
|
_ "context"
|
|
|
|
_ "encoding/json"
|
|
|
|
_ "fmt"
|
|
|
|
_ "gopkg.in/yaml.v3"
|
|
|
|
"net/url"
|
|
|
|
"path/filepath"
|
|
|
|
"decl/internal/transport"
|
|
|
|
"decl/internal/codec"
|
|
|
|
_ "os"
|
|
|
|
"io"
|
|
|
|
"errors"
|
|
|
|
"log/slog"
|
|
|
|
)
|
|
|
|
|
|
|
|
type ConfigFile struct {
|
|
|
|
Path string `yaml:"path" json:"path"`
|
|
|
|
Format codec.Format `yaml:"format" json:"format"`
|
|
|
|
reader *transport.Reader `yaml:"-" json:"-"`
|
|
|
|
writer *transport.Writer `yaml:"-" json:"-"`
|
|
|
|
encoder codec.Encoder `yaml:"-" json:"-"`
|
|
|
|
decoder codec.Decoder `yaml:"-" json:"-"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewConfigFile() *ConfigFile {
|
|
|
|
return &ConfigFile{ Format: codec.FormatYaml }
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewConfigFileFromURI(u *url.URL) *ConfigFile {
|
|
|
|
t := NewConfigFile()
|
|
|
|
if u.Scheme == "file" {
|
2024-07-22 22:03:22 +00:00
|
|
|
t.Path,_ = filepath.Abs(filepath.Join(u.Hostname(), u.Path))
|
2024-07-01 21:54:18 +00:00
|
|
|
} else {
|
|
|
|
t.Path = filepath.Join(u.Hostname(), u.Path)
|
|
|
|
}
|
|
|
|
return t
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewConfigFileSource(u *url.URL) *ConfigFile {
|
|
|
|
t := NewConfigFileFromURI(u)
|
|
|
|
t.reader,_ = transport.NewReader(u)
|
2024-07-17 08:34:57 +00:00
|
|
|
contentType := codec.Format(t.reader.ContentType())
|
|
|
|
if contentType.Validate() == nil {
|
|
|
|
if formatErr := t.Format.Set(t.reader.ContentType()); formatErr != nil {
|
|
|
|
panic(formatErr)
|
|
|
|
}
|
2024-07-01 21:54:18 +00:00
|
|
|
}
|
|
|
|
t.decoder = codec.NewDecoder(t.reader, t.Format)
|
|
|
|
return t
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewConfigFileTarget(u *url.URL) *ConfigFile {
|
|
|
|
t := NewConfigFileFromURI(u)
|
|
|
|
t.writer,_ = transport.NewWriter(u)
|
2024-07-17 08:34:57 +00:00
|
|
|
contentType := codec.Format(t.writer.ContentType())
|
|
|
|
if contentType.Validate() == nil {
|
|
|
|
if formatErr := t.Format.Set(t.writer.ContentType()); formatErr != nil {
|
|
|
|
panic(formatErr)
|
|
|
|
}
|
2024-07-01 21:54:18 +00:00
|
|
|
}
|
|
|
|
t.encoder = codec.NewEncoder(t.writer, t.Format)
|
|
|
|
return t
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
ConfigSourceTypes.Register([]string{"file"}, func(u *url.URL) ConfigSource {
|
|
|
|
return NewConfigFileSource(u)
|
|
|
|
})
|
|
|
|
|
|
|
|
ConfigSourceTypes.Register([]string{"pb","pb.gz","json","json.gz","yaml","yml","yaml.gz","yml.gz"}, func(u *url.URL) ConfigSource {
|
|
|
|
return NewConfigFileSource(u)
|
|
|
|
})
|
|
|
|
|
|
|
|
ConfigTargetTypes.Register([]string{"file"}, func(u *url.URL) ConfigTarget {
|
|
|
|
return NewConfigFileTarget(u)
|
|
|
|
})
|
|
|
|
|
|
|
|
ConfigTargetTypes.Register([]string{"pb","pb.gz","json","json.gz","yaml","yml","yaml.gz","yml.gz"}, func(u *url.URL) ConfigTarget {
|
|
|
|
return NewConfigFileTarget(u)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (c *ConfigFile) Type() string { return "file" }
|
|
|
|
|
|
|
|
func (c *ConfigFile) Extract(filter ConfigurationSelector) ([]*Document, error) {
|
|
|
|
documents := make([]*Document, 0, 100)
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
c.reader.Close()
|
|
|
|
}()
|
|
|
|
|
|
|
|
slog.Info("Extract()", "documents", documents)
|
|
|
|
index := 0
|
|
|
|
for {
|
|
|
|
doc := NewDocument()
|
|
|
|
e := c.decoder.Decode(doc)
|
|
|
|
if errors.Is(e, io.EOF) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if e != nil {
|
|
|
|
return documents, e
|
|
|
|
}
|
|
|
|
slog.Info("Extract()", "res", doc.ConfigBlocks[0].Values)
|
|
|
|
if validationErr := doc.Validate(); validationErr != nil {
|
|
|
|
return documents, validationErr
|
|
|
|
}
|
|
|
|
documents = append(documents, doc)
|
|
|
|
index++
|
|
|
|
}
|
|
|
|
return documents, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ConfigFile) EmitResources(documents []*Document, filter ConfigurationSelector) (error) {
|
|
|
|
defer func() {
|
|
|
|
c.encoder.Close()
|
|
|
|
c.writer.Close()
|
|
|
|
}()
|
|
|
|
|
|
|
|
for _, doc := range documents {
|
|
|
|
emitDoc := NewDocument()
|
|
|
|
if validationErr := doc.Validate(); validationErr != nil {
|
|
|
|
return validationErr
|
|
|
|
}
|
|
|
|
for _, block := range doc.Filter(filter) {
|
|
|
|
emitDoc.ConfigBlocks = append(emitDoc.ConfigBlocks, *block)
|
|
|
|
}
|
|
|
|
slog.Info("EmitResources", "doctarget", c, "encoder", c.encoder, "emit", emitDoc)
|
|
|
|
if documentErr := c.encoder.Encode(emitDoc); documentErr != nil {
|
|
|
|
slog.Info("EmitResources", "err", documentErr)
|
|
|
|
return documentErr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ConfigFile) Close() (error) {
|
|
|
|
return nil
|
|
|
|
}
|