...
1 package sources
2
3
4
5 import (
6 "context"
7 "io/fs"
8 "os"
9 "path/filepath"
10 "slices"
11 "strings"
12
13 "gopkg.in/yaml.v3"
14 )
15
16 func NewYAMLSourcesReaderWriter(ctx context.Context, path string) (ReaderWriter, error) {
17 return &fileSourcesReaderWriter{
18 ctx: ctx,
19 path: path,
20 }, nil
21 }
22
23 type fileSourcesReaderWriter struct {
24 ctx context.Context
25 path string
26 }
27
28 func (fcr *fileSourcesReaderWriter) WriteSources(mds Sources) error {
29 yamlData, _ := yaml.Marshal(mds)
30 return os.WriteFile(fcr.path, yamlData, 0644)
31 }
32
33 func (fcr *fileSourcesReaderWriter) UpdateSource(md Source) error {
34 dbs, err := fcr.GetSources()
35 if err != nil {
36 return err
37 }
38 for i, db := range dbs {
39 if db.Name == md.Name {
40 dbs[i] = md
41 return fcr.WriteSources(dbs)
42 }
43 }
44 dbs = append(dbs, md)
45 return fcr.WriteSources(dbs)
46 }
47
48 func (fcr *fileSourcesReaderWriter) DeleteSource(name string) error {
49 dbs, err := fcr.GetSources()
50 if err != nil {
51 return err
52 }
53 dbs = slices.DeleteFunc(dbs, func(md Source) bool { return md.Name == name })
54 return fcr.WriteSources(dbs)
55 }
56
57 func (fcr *fileSourcesReaderWriter) GetSources() (dbs Sources, err error) {
58 var fi fs.FileInfo
59 if fi, err = os.Stat(fcr.path); err != nil {
60 return
61 }
62 switch mode := fi.Mode(); {
63 case mode.IsDir():
64 err = filepath.WalkDir(fcr.path, func(path string, d fs.DirEntry, err error) error {
65 if err != nil {
66 return err
67 }
68 name := strings.ToLower(d.Name())
69 if d.IsDir() || !strings.HasSuffix(name, ".yaml") && !strings.HasSuffix(name, ".yml") {
70 return nil
71 }
72 var mdbs Sources
73 if mdbs, err = fcr.getSources(path); err == nil {
74 dbs = append(dbs, mdbs...)
75 }
76 return err
77 })
78 case mode.IsRegular():
79 dbs, err = fcr.getSources(fcr.path)
80 }
81 if err != nil {
82 return nil, err
83 }
84 return dbs.Validate()
85 }
86
87 func (fcr *fileSourcesReaderWriter) getSources(configFilePath string) (dbs Sources, err error) {
88 var yamlFile []byte
89 if yamlFile, err = os.ReadFile(configFilePath); err != nil {
90 return
91 }
92 c := make(Sources, 0)
93 if err = yaml.Unmarshal(yamlFile, &c); err != nil {
94 return
95 }
96 for _, v := range c {
97 dbs = append(dbs, fcr.expandEnvVars(v))
98 }
99 return
100 }
101
102 func (fcr *fileSourcesReaderWriter) expandEnvVars(md Source) Source {
103 if strings.HasPrefix(string(md.Kind), "$") {
104 md.Kind = Kind(os.ExpandEnv(string(md.Kind)))
105 }
106 if strings.HasPrefix(md.Name, "$") {
107 md.Name = os.ExpandEnv(md.Name)
108 }
109 if strings.HasPrefix(md.IncludePattern, "$") {
110 md.IncludePattern = os.ExpandEnv(md.IncludePattern)
111 }
112 if strings.HasPrefix(md.ExcludePattern, "$") {
113 md.ExcludePattern = os.ExpandEnv(md.ExcludePattern)
114 }
115 if strings.HasPrefix(md.PresetMetrics, "$") {
116 md.PresetMetrics = os.ExpandEnv(md.PresetMetrics)
117 }
118 if strings.HasPrefix(md.PresetMetricsStandby, "$") {
119 md.PresetMetricsStandby = os.ExpandEnv(md.PresetMetricsStandby)
120 }
121 return md
122 }
123