package main
import (
"fmt"
"io"
"io/fs"
"log"
"os"
"path/filepath"
"sort"
"strings"
"golang.org/x/xerrors"
"gopkg.in/yaml.v3"
)
type MD struct {
HelmComponent string `yaml:"helm-component"`
}
func main() {
err := produceManifest(os.Stdout, os.DirFS("."))
if err != nil {
log.Fatal(err)
}
}
func produceManifest(out io.Writer, dir fs.FS) error {
mds, err := fs.Glob(dir, "**/metadata.yaml")
if err != nil {
return err
}
versions := make(map[string]string)
for _, md := range mds {
b, err := fs.ReadFile(dir, md)
if err != nil {
return err
}
var mdobj MD
err = yaml.Unmarshal(b, &mdobj)
if err != nil {
return xerrors.Errorf("cannot unmarshal %s: %w", md, err)
}
if mdobj.HelmComponent == "" {
continue
}
imgf, err := fs.ReadFile(dir, filepath.Join(filepath.Dir(md), "imgnames.txt"))
if err != nil {
return xerrors.Errorf("cannot read image names for %s: %w", md, err)
}
imgs := strings.Split(strings.TrimSpace(string(imgf)), "\n")
img := imgs[len(imgs)-1]
segs := strings.Split(img, ":")
if len(segs) != 2 {
return xerrors.Errorf("invalid image format: %s", img)
}
version := segs[1]
versions[mdobj.HelmComponent] = version
}
res := make(map[string]interface{})
comps := make(map[string]interface{})
res["components"] = comps
for k, v := range versions {
var (
m = comps
segs = strings.Split(k+".version", ".")
)
for i, seg := range segs {
if i == len(segs)-1 {
m[seg] = v
continue
}
if _, ok := m[seg]; !ok {
m[seg] = make(map[string]interface{})
}
m = m[seg].(map[string]interface{})
}
}
vers, err := fs.Glob(dir, "**/versions.yaml")
if err != nil {
return err
}
for _, md := range vers {
b, err := fs.ReadFile(dir, md)
if err != nil {
return err
}
var versions struct {
Commit string `yaml:"commit"`
Version string `yaml:"version"`
Components map[string]interface{} `yaml:"components"`
}
err = yaml.Unmarshal(b, &versions)
if err != nil {
return xerrors.Errorf("cannot unmarshal %s: %w", md, err)
}
for k, v := range versions.Components {
res["components"].(map[string]interface{})[k] = v
}
}
return print(out, res, 0)
}
func print(out io.Writer, m map[string]interface{}, indent int) error {
keys := make([]string, 0, len(m))
for v := range m {
keys = append(keys, v)
}
sort.Strings(keys)
for _, k := range keys {
v := m[k]
fmt.Fprintf(out, "%s%s:", strings.Repeat(" ", indent), k)
if c, ok := v.(map[string]interface{}); ok {
fmt.Fprintln(out)
err := print(out, c, indent+1)
if err != nil {
return err
}
continue
}
if c, ok := v.(string); ok {
fmt.Fprintf(out, " %s\n", c)
fmt.Fprintln(out)
continue
}
return xerrors.Errorf("unknown value type - this should never happen")
}
return nil
}