...
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) CreateSource(md Source) error {
49 dbs, err := fcr.GetSources()
50 if err != nil {
51 return err
52 }
53
54 for _, db := range dbs {
55 if db.Name == md.Name {
56 return ErrSourceExists
57 }
58 }
59 dbs = append(dbs, md)
60 return fcr.WriteSources(dbs)
61 }
62
63 func (fcr *fileSourcesReaderWriter) DeleteSource(name string) error {
64 dbs, err := fcr.GetSources()
65 if err != nil {
66 return err
67 }
68 dbs = slices.DeleteFunc(dbs, func(md Source) bool { return md.Name == name })
69 return fcr.WriteSources(dbs)
70 }
71
72 func (fcr *fileSourcesReaderWriter) GetSources() (dbs Sources, err error) {
73 var fi fs.FileInfo
74 if fi, err = os.Stat(fcr.path); err != nil {
75 return
76 }
77 switch mode := fi.Mode(); {
78 case mode.IsDir():
79 err = filepath.WalkDir(fcr.path, func(path string, d fs.DirEntry, err error) error {
80 if err != nil {
81 return err
82 }
83 ext := strings.ToLower(filepath.Ext(d.Name()))
84 if d.IsDir() || ext != ".yaml" && ext != ".yml" {
85 return nil
86 }
87 var mdbs Sources
88 if mdbs, err = fcr.getSources(path); err == nil {
89 dbs = append(dbs, mdbs...)
90 }
91 return err
92 })
93 case mode.IsRegular():
94 dbs, err = fcr.getSources(fcr.path)
95 }
96 if err != nil {
97 return nil, err
98 }
99 return dbs.Validate()
100 }
101
102 func (fcr *fileSourcesReaderWriter) getSources(configFilePath string) (dbs Sources, err error) {
103 var yamlFile []byte
104 if yamlFile, err = os.ReadFile(configFilePath); err != nil {
105 return
106 }
107 c := make(Sources, 0)
108 if err = yaml.Unmarshal(yamlFile, &c); err != nil {
109 return
110 }
111 for _, v := range c {
112 dbs = append(dbs, fcr.expandEnvVars(v))
113 }
114 return
115 }
116
117 func (fcr *fileSourcesReaderWriter) expandEnvVars(md Source) Source {
118 if strings.HasPrefix(string(md.Kind), "$") {
119 md.Kind = Kind(os.ExpandEnv(string(md.Kind)))
120 }
121 if strings.HasPrefix(md.Name, "$") {
122 md.Name = os.ExpandEnv(md.Name)
123 }
124 if strings.HasPrefix(md.IncludePattern, "$") {
125 md.IncludePattern = os.ExpandEnv(md.IncludePattern)
126 }
127 if strings.HasPrefix(md.ExcludePattern, "$") {
128 md.ExcludePattern = os.ExpandEnv(md.ExcludePattern)
129 }
130 if strings.HasPrefix(md.PresetMetrics, "$") {
131 md.PresetMetrics = os.ExpandEnv(md.PresetMetrics)
132 }
133 if strings.HasPrefix(md.PresetMetricsStandby, "$") {
134 md.PresetMetricsStandby = os.ExpandEnv(md.PresetMetricsStandby)
135 }
136 return md
137 }
138