From 38f8831275b3fea5cfbeba50a41eba3b52e4dd2f Mon Sep 17 00:00:00 2001 From: Matthew Rich Date: Tue, 24 Sep 2024 19:15:47 +0000 Subject: [PATCH] moved extractor/emitter code to the fan pkg --- internal/config/block.go | 134 ----------------- internal/config/block_test.go | 49 ------- internal/config/certificate.go | 26 +++- internal/config/configsource.go | 45 ------ internal/config/configtarget.go | 30 ---- internal/config/configuration.go | 48 ------ internal/config/configuration_test.go | 22 --- internal/config/document.go | 202 -------------------------- internal/config/document_test.go | 53 ------- internal/config/exec.go | 25 +++- internal/config/file.go | 143 ------------------ internal/config/fs.go | 109 -------------- internal/config/generic.go | 26 +++- internal/config/system.go | 2 +- 14 files changed, 69 insertions(+), 845 deletions(-) delete mode 100644 internal/config/block.go delete mode 100644 internal/config/block_test.go delete mode 100644 internal/config/configsource.go delete mode 100644 internal/config/configtarget.go delete mode 100644 internal/config/configuration.go delete mode 100644 internal/config/configuration_test.go delete mode 100644 internal/config/document.go delete mode 100644 internal/config/document_test.go delete mode 100644 internal/config/file.go delete mode 100644 internal/config/fs.go diff --git a/internal/config/block.go b/internal/config/block.go deleted file mode 100644 index cf1af1b..0000000 --- a/internal/config/block.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2024 Matthew Rich . All rights reserved. - -package config - -import ( - "context" - "encoding/json" - "fmt" - "io" - "gopkg.in/yaml.v3" - "log/slog" - "decl/internal/codec" -) - -type BlockType struct { - Name string `json:"name" yaml:"name"` - Type TypeName `json:"type" yaml:"type"` -} - -type Block struct { - Name string `json:"name" yaml:"name"` - Type TypeName `json:"type" yaml:"type"` - Values Configuration `json:"values" yaml:"values"` -} - -func NewBlock() *Block { - return &Block{ Type: "generic" } -} - -func (b *Block) Clone() *Block { - return &Block { - Type: b.Type, - Values: b.Values.Clone(), - } -} - -func (b *Block) Load(r io.Reader) error { - return codec.NewYAMLDecoder(r).Decode(b) -} - -func (b *Block) LoadBlock(yamlBlock string) (err error) { - err = codec.NewYAMLStringDecoder(yamlBlock).Decode(b) - slog.Info("LoadBlock()", "yaml", yamlBlock, "object", b, "err", err) - return -} - -func (b *Block) NewConfiguration() error { - uri := fmt.Sprintf("%s://", b.Type) - newConfig, err := ConfigTypes.New(uri) - b.Values = newConfig - return err -} - -func (b *Block) GetValue(key string) (any, error) { - return b.Values.GetValue(key) -} - -func (b *Block) Configuration() Configuration { - return b.Values -} - -func (b *Block) SetURI(uri string) (e error) { - b.Values = NewConfiguration(uri) - if b.Values == nil { - return ErrUnknownConfigurationType - } - b.Type = TypeName(b.Values.Type()) - _,e = b.Values.Read(context.Background()) - return e -} - - -func (b *Block) UnmarshalValue(value *BlockType) error { - b.Name = value.Name - if value.Type == "" { - b.Type = "generic" - } else { - b.Type = value.Type - } - - newConfig, configErr := ConfigTypes.New(fmt.Sprintf("%s://", b.Type)) - if configErr != nil { - return configErr - } - b.Values = newConfig - return nil -} - -func (b *Block) UnmarshalYAML(value *yaml.Node) error { - t := &BlockType{} - if unmarshalConfigurationTypeErr := value.Decode(t); unmarshalConfigurationTypeErr != nil { - return unmarshalConfigurationTypeErr - } - - if err := b.UnmarshalValue(t); err != nil { - return err - } - - configurationVals := struct { - Values yaml.Node `json:"values"` - }{} - if unmarshalValuesErr := value.Decode(&configurationVals); unmarshalValuesErr != nil { - return unmarshalValuesErr - } - if unmarshalConfigurationErr := configurationVals.Values.Decode(b.Values); unmarshalConfigurationErr != nil { - return unmarshalConfigurationErr - } - _, readErr := b.Values.Read(context.Background()) - return readErr -} - -func (b *Block) UnmarshalJSON(data []byte) error { - t := &BlockType{} - if unmarshalConfigurationTypeErr := json.Unmarshal(data, t); unmarshalConfigurationTypeErr != nil { - return unmarshalConfigurationTypeErr - } - - if err := b.UnmarshalValue(t); err != nil { - return err - } - - configurationVals := struct { - Values Configuration `json:"values"` - }{Values: b.Values} - if unmarshalValuesErr := json.Unmarshal(data, &configurationVals); unmarshalValuesErr != nil { - return unmarshalValuesErr - } - _, readErr := b.Values.Read(context.Background()) - return readErr -} - -func (b *Block) MarshalYAML() (any, error) { - return b, nil -} diff --git a/internal/config/block_test.go b/internal/config/block_test.go deleted file mode 100644 index 37efe27..0000000 --- a/internal/config/block_test.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2024 Matthew Rich . All rights reserved. - -package config - -import ( -_ "fmt" - "github.com/stretchr/testify/assert" - "log" - "os" - "testing" - "strings" -) - -var TempDir string - -func TestMain(m *testing.M) { - var err error - TempDir, err = os.MkdirTemp("", "testconfig") - if err != nil || TempDir == "" { - log.Fatal(err) - } - - rc := m.Run() - - os.RemoveAll(TempDir) - os.Exit(rc) -} - -func TestNewBlock(t *testing.T) { - configYaml := ` -name: "foo" -values: - http_user: "test" - http_pass: "password" -` - docReader := strings.NewReader(configYaml) - - block := NewBlock() - assert.NotNil(t, block) - assert.Nil(t, block.Load(docReader)) - assert.Equal(t, "foo", block.Name) - val, err := block.GetValue("http_user") - assert.Nil(t, err) - assert.Equal(t, "test", val) - - missingVal, missingErr := block.GetValue("content") - assert.ErrorIs(t, missingErr, ErrUnknownConfigurationKey) - assert.Nil(t, missingVal) -} diff --git a/internal/config/certificate.go b/internal/config/certificate.go index 4bd9ecb..53d418f 100644 --- a/internal/config/certificate.go +++ b/internal/config/certificate.go @@ -5,15 +5,18 @@ package config import ( "context" "io" + "fmt" "net/url" "decl/internal/codec" + "decl/internal/data" + "decl/internal/folio" "encoding/json" "gopkg.in/yaml.v3" "crypto/x509" ) func init() { - ConfigTypes.Register([]string{"certificate"}, func(u *url.URL) Configuration { + folio.DocumentRegistry.ConfigurationTypes.Register([]string{"certificate"}, func(u *url.URL) data.Configuration { c := NewCertificate() return c }) @@ -26,6 +29,18 @@ func NewCertificate() *Certificate { return &c } +func (c *Certificate) URI() string { + return fmt.Sprintf("%s://%s", c.Type(), "") +} + +func (c *Certificate) SetURI(uri string) error { + return nil +} + +func (c *Certificate) SetParsedURI(uri *url.URL) error { + return nil +} + func (c *Certificate) Read(ctx context.Context) ([]byte, error) { return nil, nil } @@ -61,7 +76,7 @@ func (c *Certificate) UnmarshalYAML(value *yaml.Node) error { return nil } -func (c *Certificate) Clone() Configuration { +func (c *Certificate) Clone() data.Configuration { jsonGeneric, _ := json.Marshal(c) clone := NewCertificate() if unmarshalErr := json.Unmarshal(jsonGeneric, &clone); unmarshalErr != nil { @@ -77,7 +92,12 @@ func (c *Certificate) Type() string { func (c *Certificate) GetValue(name string) (result any, err error) { var ok bool if result, ok = (*c)[name]; !ok { - err = ErrUnknownConfigurationKey + err = data.ErrUnknownConfigurationKey } return } + +func (c *Certificate) Has(key string) (ok bool) { + _, ok = (*c)[key] + return +} diff --git a/internal/config/configsource.go b/internal/config/configsource.go deleted file mode 100644 index cd94730..0000000 --- a/internal/config/configsource.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2024 Matthew Rich . All rights reserved. - -package config - -import ( -_ "context" -_ "encoding/json" -_ "fmt" -_ "gopkg.in/yaml.v3" -_ "net/url" -_ "regexp" -_ "strings" -_ "os" -_ "io" -_ "compress/gzip" -_ "archive/tar" -_ "errors" -_ "path/filepath" -_ "decl/internal/codec" - "embed" -) - -type ConfigurationSelector func(b *Block) bool - -type ConfigSource interface { - Type() string - - Extract(filter ConfigurationSelector) ([]*Document, error) -} - -func NewConfigSource(uri string) ConfigSource { - s, e := ConfigSourceTypes.New(uri) - if e == nil { - return s - } - return nil -} - -//go:embed configs/*.yaml -var configFiles embed.FS - -func Configurations() ([]*Document, error) { - fs := NewConfigFS(configFiles) - return fs.Extract(nil) -} diff --git a/internal/config/configtarget.go b/internal/config/configtarget.go deleted file mode 100644 index 4af4a51..0000000 --- a/internal/config/configtarget.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2024 Matthew Rich . All rights reserved. - -package config - -import ( -_ "context" -_ "encoding/json" -_ "fmt" -_ "gopkg.in/yaml.v3" -_ "net/url" -_ "regexp" -_ "strings" -_ "os" -_ "io" -) - -type ConfigTarget interface { - Type() string - - EmitResources(documents []*Document, filter ConfigurationSelector) error - Close() error -} - -func NewConfigTarget(uri string) ConfigTarget { - s, e := ConfigTargetTypes.New(uri) - if e == nil { - return s - } - return nil -} diff --git a/internal/config/configuration.go b/internal/config/configuration.go deleted file mode 100644 index 48f44ac..0000000 --- a/internal/config/configuration.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2024 Matthew Rich . All rights reserved. - -package config - -import ( - "errors" - "fmt" -_ "net/url" -_ "decl/internal/codec" -_ "io" - "decl/internal/types" - "decl/internal/data" - "strings" -) - -var ( - ErrUnknownConfigurationType = errors.New("Unknown configuration type") - ErrUnknownConfigurationKey = errors.New("Unknown configuration key") - ConfigTypes *types.Types[Configuration] = types.New[Configuration]() - ConfigSourceTypes *types.Types[ConfigSource] = types.New[ConfigSource]() - ConfigTargetTypes *types.Types[ConfigTarget] = types.New[ConfigTarget]() -) - -type TypeName string //`json:"type"` - -type Configuration interface { - Type() string - data.Reader - GetValue(name string) (any, error) - Clone() Configuration -} - -func NewConfiguration(uri string) Configuration { - c, e := ConfigTypes.New(uri) - if e == nil { - return c - } - return nil -} - -func (n *TypeName) UnmarshalJSON(b []byte) error { - ConfigTypeName := strings.Trim(string(b), "\"") - if ConfigTypes.Has(ConfigTypeName) { - *n = TypeName(ConfigTypeName) - return nil - } - return fmt.Errorf("%w: %s", ErrUnknownConfigurationType, ConfigTypeName) -} diff --git a/internal/config/configuration_test.go b/internal/config/configuration_test.go deleted file mode 100644 index 73c7259..0000000 --- a/internal/config/configuration_test.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2024 Matthew Rich . All rights reserved. - -package config - -import ( -_ "context" -_ "fmt" - "github.com/stretchr/testify/assert" -_ "log" -_ "os" -_ "path/filepath" -_ "strings" - "testing" -) - -func TestNewConfiguration(t *testing.T) { - configurationUri := "generic://" - testConfig := NewConfiguration(configurationUri) - assert.NotNil(t, testConfig) - v, _ := testConfig.GetValue("foo") - assert.Nil(t, v) -} diff --git a/internal/config/document.go b/internal/config/document.go deleted file mode 100644 index 3612598..0000000 --- a/internal/config/document.go +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2024 Matthew Rich . All rights reserved. - -package config - -import ( - "errors" - "encoding/json" - "fmt" - "gopkg.in/yaml.v3" - "io" - "log/slog" -_ "net/url" - "github.com/sters/yaml-diff/yamldiff" - "strings" - "decl/internal/codec" -_ "context" -) - -var ( - ErrConfigUndefinedName = errors.New("Config block is missing a defined name") -) - -type ConfigNamesMap[Value any] map[string]Value - -type Document struct { - names ConfigNamesMap[*Block] - ConfigBlocks []Block `json:"configurations" yaml:"configurations"` -} - -func NewDocument() *Document { - return &Document{ names: make(ConfigNamesMap[*Block]) } -} - -func (d *Document) Filter(filter ConfigurationSelector) []*Block { - configurations := make([]*Block, 0, len(d.ConfigBlocks)) - for i := range d.ConfigBlocks { - filterConfig := &d.ConfigBlocks[i] - if filter == nil || filter(filterConfig) { - configurations = append(configurations, &d.ConfigBlocks[i]) - } - } - return configurations -} - -func (d *Document) Clone() *Document { - clone := NewDocument() - clone.ConfigBlocks = make([]Block, len(d.ConfigBlocks)) - for i, res := range d.ConfigBlocks { - clone.ConfigBlocks[i] = *res.Clone() - } - return clone -} - -func (d *Document) Load(r io.Reader) error { - c := codec.NewYAMLDecoder(r) - return c.Decode(d); -} - -func (d *Document) Validate() error { - jsonDocument, jsonErr := d.JSON() - if jsonErr == nil { - s := NewSchema("document") - err := s.Validate(string(jsonDocument)) - if err != nil { - return err - } - } - return nil -} - -func (d *Document) Configurations() []Block { - return d.ConfigBlocks -} - -func (d *Document) Generate(w io.Writer) error { - e := codec.NewYAMLEncoder(w) - err := e.Encode(d); - if err == nil { - return e.Close() - } - e.Close() - return err -} - -func (d *Document) Append(doc *Document) { - if doc != nil { - for i := range doc.ConfigBlocks { - slog.Info("Document.Append()", "doc", doc, "block", doc.ConfigBlocks[i], "targetdoc", d) - d.AddConfigurationBlock(doc.ConfigBlocks[i].Name, doc.ConfigBlocks[i].Type, doc.ConfigBlocks[i].Values) - } - } -} - -func (d *Document) AddConfigurationBlock(configurationName string, configurationType TypeName, configuration Configuration) { - cfg := NewBlock() - cfg.Name = configurationName - cfg.Type = configurationType - cfg.Values = configuration - d.names[cfg.Name] = cfg - d.ConfigBlocks = append(d.ConfigBlocks, *cfg) -} - -func (d *Document) AddConfiguration(uri string) error { - cfg := NewBlock() - if e := cfg.SetURI(uri); e != nil { - return e - } - if cfg.Name == "" { - return ErrConfigUndefinedName - } - d.names[cfg.Name] = cfg - d.ConfigBlocks = append(d.ConfigBlocks, *cfg) - return nil -} - -func (d *Document) Has(name string) bool { - _, ok := d.names[name] - return ok -} - -func (d *Document) Get(name string) *Block { - return d.names[name] -} - -func (d *Document) JSON() ([]byte, error) { - return json.Marshal(d) -} - -func (d *Document) YAML() ([]byte, error) { - return yaml.Marshal(d) -} - -func (d *Document) IndexName() error { - for _, b := range d.ConfigBlocks { - d.names[b.Name] = &b - } - return nil -} - -func (d *Document) UnmarshalYAML(value *yaml.Node) error { - documentBlocks := struct { - ConfigBlocks *[]Block `json:"configurations" yaml:"configurations"` - }{ ConfigBlocks: &d.ConfigBlocks } - if unmarshalDocumentErr := value.Decode(documentBlocks); unmarshalDocumentErr != nil { - return unmarshalDocumentErr - } - return d.IndexName() -} - -func (d *Document) UnmarshalJSON(data []byte) error { - documentBlocks := struct { - ConfigBlocks *[]Block `json:"configurations" yaml:"configurations"` - }{ ConfigBlocks: &d.ConfigBlocks } - if unmarshalDocumentErr := json.Unmarshal(data, &documentBlocks); unmarshalDocumentErr != nil { - return unmarshalDocumentErr - } - return d.IndexName() -} - -func (d *Document) Diff(with *Document, output io.Writer) (returnOutput string, diffErr error) { - defer func() { - if r := recover(); r != nil { - returnOutput = "" - diffErr = fmt.Errorf("%s", r) - } - }() - slog.Info("Document.Diff()") - opts := []yamldiff.DoOptionFunc{} - if output == nil { - output = &strings.Builder{} - } - ydata, yerr := d.YAML() - if yerr != nil { - return "", yerr - } - yamlDiff,yamlDiffErr := yamldiff.Load(string(ydata)) - if yamlDiffErr != nil { - return "", yamlDiffErr - } - - wdata,werr := with.YAML() - if werr != nil { - return "", werr - } - withDiff,withDiffErr := yamldiff.Load(string(wdata)) - if withDiffErr != nil { - return "", withDiffErr - } - - for _,docDiffResults := range yamldiff.Do(yamlDiff, withDiff, opts...) { - slog.Info("Diff()", "diff", docDiffResults, "dump", docDiffResults.Dump()) - _,e := output.Write([]byte(docDiffResults.Dump())) - if e != nil { - return "", e - } - } - slog.Info("Document.Diff() ", "document.yaml", ydata, "with.yaml", wdata) - if stringOutput, ok := output.(*strings.Builder); ok { - return stringOutput.String(), nil - } - return "", nil -} diff --git a/internal/config/document_test.go b/internal/config/document_test.go deleted file mode 100644 index 7d12d8c..0000000 --- a/internal/config/document_test.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2024 Matthew Rich . All rights reserved. - -package config - -import ( - "github.com/stretchr/testify/assert" - "strings" - "testing" -) - -func TestNewDocument(t *testing.T) { - d := NewDocument() - assert.NotNil(t, d) -} - -func TestDocumentLoader(t *testing.T) { - document := ` ---- -configurations: -- type: generic - name: global - values: - install_dir: /opt/jx -- name: system - values: - dist: ubuntu - release: focal -` - d := NewDocument() - assert.NotNil(t, d) - - docReader := strings.NewReader(document) - - e := d.Load(docReader) - assert.Nil(t, e) - - configurations := d.Configurations() - assert.Equal(t, 2, len(configurations)) - - b := d.Get("system") - assert.NotNil(t, b) - cfg := b.Configuration() - value, valueErr := cfg.GetValue("dist") - assert.Nil(t, valueErr) - assert.Equal(t, "ubuntu", value) -} - -func TestDocumentJSONSchema(t *testing.T) { - document := NewDocument() - document.ConfigBlocks = []Block{} - e := document.Validate() - assert.Nil(t, e) -} diff --git a/internal/config/exec.go b/internal/config/exec.go index 8f89923..396b732 100644 --- a/internal/config/exec.go +++ b/internal/config/exec.go @@ -5,15 +5,18 @@ package config import ( "context" "io" + "fmt" "net/url" "decl/internal/codec" "decl/internal/command" + "decl/internal/data" + "decl/internal/folio" "encoding/json" "gopkg.in/yaml.v3" ) func init() { - ConfigTypes.Register([]string{"exec"}, func(u *url.URL) Configuration { + folio.DocumentRegistry.ConfigurationTypes.Register([]string{"exec"}, func(u *url.URL) data.Configuration { x := NewExec() return x }) @@ -32,6 +35,18 @@ func NewExec() *Exec { return x } +func (x *Exec) SetURI(uri string) error { + return nil +} + +func (x *Exec) SetParsedURI(uri *url.URL) error { + return nil +} + +func (x *Exec) URI() string { + return fmt.Sprintf("%s://%s", x.Type(), x.Path) +} + func (x *Exec) Read(ctx context.Context) ([]byte, error) { out, err := x.ReadCommand.Execute(x) if err != nil { @@ -78,7 +93,7 @@ func (x *Exec) UnmarshalYAML(value *yaml.Node) error { } -func (x *Exec) Clone() Configuration { +func (x *Exec) Clone() data.Configuration { clone := NewExec() clone.Path = x.Path clone.Args = x.Args @@ -95,11 +110,15 @@ func (x *Exec) Type() string { func (x *Exec) GetValue(name string) (result any, err error) { var ok bool if result, ok = x.Values[name]; !ok { - err = ErrUnknownConfigurationKey + err = data.ErrUnknownConfigurationKey } return } +func (x *Exec) Has(key string) (ok bool) { + _, ok = x.Values[key] + return +} func (ex *Exec) NewReadConfigCommand() { ex.ReadCommand = command.NewCommand() diff --git a/internal/config/file.go b/internal/config/file.go deleted file mode 100644 index cb296d3..0000000 --- a/internal/config/file.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2024 Matthew Rich . 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" { - t.Path,_ = filepath.Abs(filepath.Join(u.Hostname(), u.Path)) - } 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) - contentType := codec.Format(t.reader.ContentType()) - if contentType.Validate() == nil { - if formatErr := t.Format.Set(t.reader.ContentType()); formatErr != nil { - panic(formatErr) - } - } - t.decoder = codec.NewDecoder(t.reader, t.Format) - return t -} - -func NewConfigFileTarget(u *url.URL) *ConfigFile { - t := NewConfigFileFromURI(u) - t.writer,_ = transport.NewWriter(u) - contentType := codec.Format(t.writer.ContentType()) - if contentType.Validate() == nil { - if formatErr := t.Format.Set(t.writer.ContentType()); formatErr != nil { - panic(formatErr) - } - } - 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 -} diff --git a/internal/config/fs.go b/internal/config/fs.go deleted file mode 100644 index ecb6dd3..0000000 --- a/internal/config/fs.go +++ /dev/null @@ -1,109 +0,0 @@ -// 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.Path)) - 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 -} - diff --git a/internal/config/generic.go b/internal/config/generic.go index 65c7d3f..f278724 100644 --- a/internal/config/generic.go +++ b/internal/config/generic.go @@ -6,10 +6,13 @@ import ( "context" "encoding/json" "net/url" + "fmt" + "decl/internal/data" + "decl/internal/folio" ) func init() { - ConfigTypes.Register([]string{"generic"}, func(u *url.URL) Configuration { + folio.DocumentRegistry.ConfigurationTypes.Register([]string{"generic"}, func(u *url.URL) data.Configuration { g := NewGeneric[any]() return g }) @@ -22,7 +25,19 @@ func NewGeneric[Value any]() *Generic[Value] { return &g } -func (g *Generic[Value]) Clone() Configuration { +func (g *Generic[Value]) URI() string { + return fmt.Sprintf("%s://%s", g.Type(), "") +} + +func (g *Generic[Value]) SetURI(uri string) error { + return nil +} + +func (g *Generic[Value]) SetParsedURI(uri *url.URL) error { + return nil +} + +func (g *Generic[Value]) Clone() data.Configuration { jsonGeneric, _ := json.Marshal(g) clone := NewGeneric[Value]() if unmarshalErr := json.Unmarshal(jsonGeneric, clone); unmarshalErr != nil { @@ -42,7 +57,12 @@ func (g *Generic[Value]) Read(context.Context) ([]byte, error) { func (g *Generic[Value]) GetValue(name string) (result any, err error) { var ok bool if result, ok = (*g)[name]; !ok { - err = ErrUnknownConfigurationKey + err = data.ErrUnknownConfigurationKey } return } + +func (g *Generic[Value]) Has(key string) (ok bool) { + _, ok = (*g)[key] + return +} diff --git a/internal/config/system.go b/internal/config/system.go index 90e33cc..4a78016 100644 --- a/internal/config/system.go +++ b/internal/config/system.go @@ -75,7 +75,7 @@ func (s *System) Read(context.Context) ([]byte, error) { func (s *System) GetValue(name string) (result any, err error) { var ok bool if result, ok = (*s)[name]; !ok { - err = ErrUnknownConfigurationKey + err = data.ErrUnknownConfigurationKey } return }