jx/internal/resource/document.go
Matthew Rich 86264c1202
Some checks failed
Lint / golangci-lint (push) Failing after 9m48s
Declarative Tests / test (push) Successful in 1m23s
fix tests
2024-04-21 11:06:53 -07:00

148 lines
3.2 KiB
Go

// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
package resource
import (
"encoding/json"
"fmt"
"gopkg.in/yaml.v3"
"io"
"log/slog"
_ "net/url"
"github.com/sters/yaml-diff/yamldiff"
"strings"
)
type Document struct {
ResourceDecls []Declaration `json:"resources" yaml:"resources"`
}
func NewDocument() *Document {
return &Document{}
}
func (d *Document) Clone() *Document {
clone := NewDocument()
clone.ResourceDecls = make([]Declaration, len(d.ResourceDecls))
for i, res := range d.ResourceDecls {
clone.ResourceDecls[i] = *res.Clone()
}
return clone
}
func (d *Document) Load(r io.Reader) error {
c := NewYAMLDecoder(r)
return c.Decode(d);
}
func (d *Document) Validate() error {
jsonDocument, jsonErr := d.JSON()
slog.Info("document.Validate() json", "json", jsonDocument, "err", jsonErr)
if jsonErr == nil {
s := NewSchema("document")
err := s.Validate(string(jsonDocument))
if err != nil {
return err
}
/*
for i := range d.ResourceDecls {
if e := d.ResourceDecls[i].Resource().Validate(); e != nil {
return fmt.Errorf("failed to validate resource %s; %w", d.ResourceDecls[i].Resource().URI(), e)
}
}
*/
}
return nil
}
func (d *Document) Resources() []Declaration {
return d.ResourceDecls
}
func (d *Document) Apply() error {
if d == nil {
panic("Undefined Document")
}
slog.Info("Document.Apply()", "declarations", d)
for i := range d.ResourceDecls {
if e := d.ResourceDecls[i].Resource().Apply(); e != nil {
return e
}
}
return nil
}
func (d *Document) Generate(w io.Writer) error {
e := NewYAMLEncoder(w)
err := e.Encode(d);
if err == nil {
return e.Close()
}
e.Close()
return err
}
func (d *Document) AddResourceDeclaration(resourceType string, resourceDeclaration Resource) {
decl := NewDeclaration()
decl.Type = TypeName(resourceType)
decl.Attributes = resourceDeclaration
d.ResourceDecls = append(d.ResourceDecls, *decl)
}
func (d *Document) AddResource(uri string) error {
//parsedResourceURI, e := url.Parse(uri)
//if e == nil {
decl := NewDeclaration()
if e := decl.SetURI(uri); e != nil {
return e
}
d.ResourceDecls = append(d.ResourceDecls, *decl)
//}
return nil
}
func (d *Document) JSON() ([]byte, error) {
return json.Marshal(d)
}
func (d *Document) YAML() ([]byte, error) {
return yaml.Marshal(d)
}
func (d *Document) Diff(with *Document, output io.Writer) (string, error) {
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 _,diff := range yamldiff.Do(yamlDiff, withDiff, opts...) {
slog.Info("Diff()", "diff", diff)
fmt.Printf("yaml %#v with %#v\n", yamlDiff, withDiff)
output.Write([]byte(diff.Dump()))
}
slog.Info("Document.Diff() ", "document.yaml", ydata, "with.yaml", wdata)
if stringOutput, ok := output.(*strings.Builder); ok {
return stringOutput.String(), nil
}
return "", nil
}