Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/dev/version-manifest/main.go
2492 views
1
// Copyright (c) 2020 Gitpod GmbH. All rights reserved.
2
// Licensed under the GNU Affero General Public License (AGPL).
3
// See License.AGPL.txt in the project root for license information.
4
5
package main
6
7
import (
8
"fmt"
9
"io"
10
"io/fs"
11
"log"
12
"os"
13
"path/filepath"
14
"sort"
15
"strings"
16
17
"golang.org/x/xerrors"
18
"gopkg.in/yaml.v3"
19
)
20
21
type MD struct {
22
HelmComponent string `yaml:"helm-component"`
23
}
24
25
func main() {
26
err := produceManifest(os.Stdout, os.DirFS("."))
27
if err != nil {
28
log.Fatal(err)
29
}
30
}
31
32
func produceManifest(out io.Writer, dir fs.FS) error {
33
mds, err := fs.Glob(dir, "**/metadata.yaml")
34
if err != nil {
35
return err
36
}
37
versions := make(map[string]string)
38
for _, md := range mds {
39
b, err := fs.ReadFile(dir, md)
40
if err != nil {
41
return err
42
}
43
var mdobj MD
44
err = yaml.Unmarshal(b, &mdobj)
45
if err != nil {
46
return xerrors.Errorf("cannot unmarshal %s: %w", md, err)
47
}
48
if mdobj.HelmComponent == "" {
49
continue
50
}
51
52
imgf, err := fs.ReadFile(dir, filepath.Join(filepath.Dir(md), "imgnames.txt"))
53
if err != nil {
54
return xerrors.Errorf("cannot read image names for %s: %w", md, err)
55
}
56
imgs := strings.Split(strings.TrimSpace(string(imgf)), "\n")
57
img := imgs[len(imgs)-1]
58
segs := strings.Split(img, ":")
59
if len(segs) != 2 {
60
return xerrors.Errorf("invalid image format: %s", img)
61
}
62
version := segs[1]
63
versions[mdobj.HelmComponent] = version
64
}
65
66
// We need to deduplicate keys in the resulting yaml file. To this end, we first build up
67
// a map of maps and later print that map YAML style.
68
res := make(map[string]interface{})
69
comps := make(map[string]interface{})
70
res["components"] = comps
71
for k, v := range versions {
72
var (
73
m = comps
74
segs = strings.Split(k+".version", ".")
75
)
76
for i, seg := range segs {
77
if i == len(segs)-1 {
78
m[seg] = v
79
continue
80
}
81
82
if _, ok := m[seg]; !ok {
83
m[seg] = make(map[string]interface{})
84
}
85
m = m[seg].(map[string]interface{})
86
}
87
}
88
89
vers, err := fs.Glob(dir, "**/versions.yaml")
90
if err != nil {
91
return err
92
}
93
for _, md := range vers {
94
b, err := fs.ReadFile(dir, md)
95
if err != nil {
96
return err
97
}
98
var versions struct {
99
Commit string `yaml:"commit"`
100
Version string `yaml:"version"`
101
Components map[string]interface{} `yaml:"components"`
102
}
103
err = yaml.Unmarshal(b, &versions)
104
if err != nil {
105
return xerrors.Errorf("cannot unmarshal %s: %w", md, err)
106
}
107
108
for k, v := range versions.Components {
109
res["components"].(map[string]interface{})[k] = v
110
}
111
}
112
113
return print(out, res, 0)
114
}
115
116
// print serializes the given map to YAML.
117
// It's not clear how to maintain a stable order of keys using the YAML serializer.
118
// If it were, we could just through this map at the YAML serializer and call it a day.
119
// Right now, we have to produce the YAML ourselves.
120
func print(out io.Writer, m map[string]interface{}, indent int) error {
121
keys := make([]string, 0, len(m))
122
for v := range m {
123
keys = append(keys, v)
124
}
125
sort.Strings(keys)
126
127
for _, k := range keys {
128
v := m[k]
129
fmt.Fprintf(out, "%s%s:", strings.Repeat(" ", indent), k)
130
if c, ok := v.(map[string]interface{}); ok {
131
fmt.Fprintln(out)
132
err := print(out, c, indent+1)
133
if err != nil {
134
return err
135
}
136
continue
137
}
138
if c, ok := v.(string); ok {
139
fmt.Fprintf(out, " %s\n", c)
140
fmt.Fprintln(out)
141
continue
142
}
143
144
return xerrors.Errorf("unknown value type - this should never happen")
145
}
146
return nil
147
}
148
149