jx/internal/target/decl.go
Matthew Rich 77be7652a5
Some checks failed
Lint / golangci-lint (push) Failing after 9m51s
Declarative Tests / test (push) Failing after 1m11s
fix lint errors
2024-05-12 22:41:12 -07:00

174 lines
3.9 KiB
Go

// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
package target
import (
_ "context"
_ "encoding/json"
_ "fmt"
_ "gopkg.in/yaml.v3"
"net/url"
"path/filepath"
"decl/internal/resource"
"os"
"compress/gzip"
"io"
_ "errors"
"log/slog"
)
const (
FormatYaml = "yaml"
FormatJson = "json"
)
type DeclFile struct {
Path string `yaml:"path" json:"path"`
Gzip bool `yaml:"gzip,omitempty" json:"gzip,omitempty"`
Format string `yaml:"format,omitempty" json:"format,omitempty"`
encoder resource.Encoder `yaml:"-" json:"-"`
closer func() error `yaml:"-" json:"-"`
}
func NewDeclFile() *DeclFile {
return &DeclFile{ Gzip: false, closer: func() error { return nil } }
}
func NewFileDocTarget(u *url.URL, format string, gzip bool, fileUri bool) DocTarget {
t := NewDeclFile()
t.Format = format
t.Gzip = gzip
if fileUri {
fileAbsolutePath, _ := filepath.Abs(filepath.Join(u.Hostname(), u.RequestURI()))
t.Path = fileAbsolutePath
} else {
t.Path = filepath.Join(u.Hostname(), u.Path)
}
if e := t.Open(); e != nil {
// open target
}
return t
}
func init() {
TargetTypes.Register([]string{"decl", "file"}, func(u *url.URL) DocTarget {
t := NewDeclFile()
if u.Path != "-" {
t.Path,_ = filepath.Abs(filepath.Join(u.Hostname(), u.Path))
} else {
t.Path = "-"
}
if _,ok := u.Query()["gzip"]; ok {
t.Gzip = true
}
if format,ok := u.Query()["format"]; ok {
switch format[0] {
case string(FormatYaml):
t.Format = FormatYaml
case string(FormatJson):
t.Format = FormatJson
}
}
if e := t.Open(); e != nil {
// open target
}
return t
})
TargetTypes.Register([]string{"yaml.gz","yml.gz"}, func(u *url.URL) DocTarget {
switch u.Scheme {
case "yaml", "yml", "file":
return NewFileDocTarget(u, FormatYaml, true, false)
}
return NewFileDocTarget(u, FormatYaml, true, false)
})
TargetTypes.Register([]string{"json.gz"}, func(u *url.URL) DocTarget {
switch u.Scheme {
case "json", "file":
return NewFileDocTarget(u, FormatJson, true, false)
}
return NewFileDocTarget(u, FormatJson, true, false)
})
TargetTypes.Register([]string{"yaml","yml"}, func(u *url.URL) DocTarget {
switch u.Scheme {
case "yaml", "yml", "file":
return NewFileDocTarget(u, FormatYaml, false, false)
}
return NewFileDocTarget(u, FormatYaml, false, false)
})
TargetTypes.Register([]string{"json"}, func(u *url.URL) DocTarget {
switch u.Scheme {
case "json", "file":
return NewFileDocTarget(u, FormatJson, false, false)
}
return NewFileDocTarget(u, FormatJson, false, false)
})
}
func (d *DeclFile) Open() error {
var file *os.File
var fileErr error
var fileWriter io.WriteCloser
if d.Path == "" || d.Path == "-" {
file = os.Stdout
} else {
file, fileErr = os.Open(d.Path)
if fileErr != nil {
return fileErr
}
d.closer = func() error {
d.encoder.Close()
fileWriter.Close()
if file != fileWriter {
file.Close()
}
return nil
}
}
if d.Gzip {
fileWriter = gzip.NewWriter(file)
} else {
fileWriter = file
}
switch d.Format {
case FormatJson:
d.encoder = resource.NewJSONEncoder(fileWriter)
case FormatYaml:
fallthrough
default:
d.encoder = resource.NewYAMLEncoder(fileWriter)
}
return nil
}
func (d *DeclFile) Close() error {
return d.closer()
}
func (d *DeclFile) Type() string { return "decl" }
func (d *DeclFile) EmitResources(documents []*resource.Document, filter resource.ResourceSelector) (error) {
for _, doc := range documents {
emitDoc := resource.NewDocument()
if validationErr := doc.Validate(); validationErr != nil {
return validationErr
}
for _, declaration := range doc.Filter(filter) {
emitDoc.ResourceDecls = append(emitDoc.ResourceDecls, *declaration)
}
slog.Info("EmitResources", "doctarget", d, "encoder", d.encoder, "emit", emitDoc)
if documentErr := d.encoder.Encode(emitDoc); documentErr != nil {
slog.Info("EmitResources", "err", documentErr)
return documentErr
}
}
return nil
}