jx/internal/source/docsource.go

122 lines
2.6 KiB
Go
Raw Normal View History

2024-04-18 00:07:12 +00:00
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
package source
import (
_ "context"
_ "encoding/json"
_ "fmt"
_ "gopkg.in/yaml.v3"
"net/url"
"regexp"
_ "strings"
"os"
"io"
"compress/gzip"
"archive/tar"
"errors"
"path/filepath"
"decl/internal/resource"
)
type ResourceSelector func(r resource.Resource) bool
type DocSource interface {
Type() string
ExtractResources(filter ResourceSelector) ([]*resource.Document, error)
}
func NewDocSource(uri string) DocSource {
s, e := SourceTypes.New(uri)
if e == nil {
return s
}
return nil
}
func ExtractResources(uri string, filter ResourceSelector) ([]*resource.Document, error) {
documents := make([]*resource.Document, 0, 100)
d := resource.NewDocument()
documents = append(documents, d)
TarGzipFileName := regexp.MustCompile(`^.*\.(tar\.gz|tgz)$`)
TarFileName := regexp.MustCompile(`^.*\.tar$`)
u,e := url.Parse(uri)
if e != nil {
return nil, e
}
switch u.Scheme {
case "file":
fileAbsolutePath, _ := filepath.Abs(filepath.Join(u.Hostname(), u.RequestURI()))
file, fileErr := os.Open(fileAbsolutePath)
if fileErr != nil {
return documents, fileErr
}
var gzipReader io.Reader
switch u.Path {
case TarGzipFileName.FindString(u.Path):
zr, err := gzip.NewReader(file)
if err != nil {
return documents, err
}
gzipReader = zr
fallthrough
case TarFileName.FindString(u.Path):
var fileReader io.Reader
if gzipReader == nil {
fileReader = file
} else {
fileReader = gzipReader
}
tarReader := tar.NewReader(fileReader)
for {
hdr, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
return documents, err
}
f := resource.NewFile()
if fiErr := f.UpdateAttributesFromFileInfo(hdr.FileInfo()); fiErr != nil {
return documents, fiErr
}
readFileData, readErr := io.ReadAll(tarReader)
if readErr != nil {
return documents, readErr
}
f.Content = string(readFileData)
d.AddResourceDeclaration("file", f)
}
default:
decoder := resource.NewYAMLDecoder(file)
index := 0
for {
doc := documents[index]
e := decoder.Decode(doc)
if errors.Is(e, io.EOF) {
if len(documents) > 1 {
documents[index] = nil
}
break
}
if e != nil {
return documents, e
}
if validationErr := doc.Validate(); validationErr != nil {
return documents, validationErr
}
if applyErr := doc.Apply(); applyErr != nil {
return documents, applyErr
}
documents = append(documents, resource.NewDocument())
index++
}
}
}
return documents, nil
}