// Copyright 2024 Matthew Rich . 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" "decl/internal/codec" ) 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 := codec.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 }