Skip to content

Commit 6bc7cb4

Browse files
authored
Refactor seesing (#183)
1 parent 14d51e6 commit 6bc7cb4

File tree

1 file changed

+203
-124
lines changed

1 file changed

+203
-124
lines changed

seed/seed.go

Lines changed: 203 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -46,151 +46,230 @@ func New(pp ...Param) *Seeder {
4646
return &Seeder{getters: gg}
4747
}
4848

49+
type fieldMap map[*config.Field]bool
50+
51+
type flagInfo struct {
52+
key string
53+
field *config.Field
54+
value *string
55+
}
56+
4957
// Seed the provided config with values for their sources.
5058
func (s *Seeder) Seed(cfg *config.Config) error {
51-
seedMap := make(map[*config.Field]bool, len(cfg.Fields))
59+
seeded := make(fieldMap, len(cfg.Fields))
5260
flagSet := flag.NewFlagSet("Harvester flags", flag.ContinueOnError)
53-
type flagInfo struct {
54-
key string
55-
field *config.Field
56-
value *string
57-
}
61+
5862
var flagInfos []*flagInfo
5963
for _, f := range cfg.Fields {
60-
seedMap[f] = false
61-
ss := f.Sources()
62-
val, ok := ss[config.SourceSeed]
63-
if ok {
64-
err := f.Set(val, 0)
65-
if err != nil {
66-
return err
67-
}
68-
slog.Debug("seed applied", "value", f, "name", f.Name())
69-
seedMap[f] = true
64+
seeded[f] = false
65+
66+
err := processSeedField(f, seeded)
67+
if err != nil {
68+
return err
7069
}
71-
key, ok := ss[config.SourceEnv]
72-
if ok { //nolint:nestif
73-
val, ok := os.LookupEnv(key)
74-
if ok {
75-
err := f.Set(val, 0)
76-
if err != nil {
77-
return err
78-
}
79-
slog.Debug("env var applied", "value", f, "name", f.Name())
80-
seedMap[f] = true
81-
} else {
82-
if seedMap[f] {
83-
slog.Debug("env var did not exist", "key", key, "name", f.Name())
84-
} else {
85-
slog.Debug("env var did not exist and no seed value provided", "key", key, "name", f.Name())
86-
}
87-
}
70+
71+
err = processEnvField(f, seeded)
72+
if err != nil {
73+
return err
8874
}
89-
key, ok = ss[config.SourceFlag]
75+
76+
fi, ok := processFlagField(f, flagSet)
9077
if ok {
91-
var val string
92-
flagSet.StringVar(&val, key, "", "")
93-
flagInfos = append(flagInfos, &flagInfo{key, f, &val})
78+
flagInfos = append(flagInfos, fi)
9479
}
95-
key, ok = ss[config.SourceFile]
96-
if ok {
97-
body, err := os.ReadFile(key)
98-
if err != nil {
99-
slog.Error("failed to read file", "file", key, "name", f.Name(), "err", err)
100-
} else {
101-
err := f.Set(string(body), 0)
102-
if err != nil {
103-
return err
104-
}
105-
106-
slog.Debug("file based var applied", "value", f, "field", f.Name())
107-
seedMap[f] = true
108-
}
80+
81+
err = processFileField(f, seeded)
82+
if err != nil {
83+
return err
10984
}
110-
key, ok = ss[config.SourceConsul]
111-
if ok {
112-
gtr, ok := s.getters[config.SourceConsul]
113-
if !ok {
114-
return errors.New("consul getter required")
115-
}
116-
value, version, err := gtr.Get(key)
117-
if err != nil {
118-
slog.Error("failed to get consul", "key", key, "field", f.Name(), "err", err)
119-
continue
120-
}
121-
if value == nil {
122-
slog.Error("consul key does not exist", "key", key, "field", f.Name())
123-
continue
124-
}
125-
err = f.Set(*value, version)
126-
if err != nil {
127-
return err
128-
}
129-
slog.Debug("consul value applied", "value", f, "field", f.Name())
130-
seedMap[f] = true
85+
86+
err = s.processConsulField(f, seeded)
87+
if err != nil {
88+
return err
13189
}
13290

133-
key, ok = ss[config.SourceRedis]
134-
if ok {
135-
gtr, ok := s.getters[config.SourceRedis]
136-
if !ok {
137-
return errors.New("redis getter required")
138-
}
139-
value, version, err := gtr.Get(key)
140-
if err != nil {
141-
slog.Error("failed to get redis", "key", key, "field", f.Name(), "err", err)
142-
continue
143-
}
144-
if value == nil {
145-
slog.Error("redis key does not exist", "key", key, "field", f.Name())
146-
continue
147-
}
148-
err = f.Set(*value, version)
149-
if err != nil {
150-
return err
151-
}
152-
slog.Debug("redis value applied", "value", f, "field", f.Name())
153-
seedMap[f] = true
91+
err = s.processRedisField(f, seeded)
92+
if err != nil {
93+
return err
15494
}
15595
}
15696

157-
if len(flagInfos) > 0 { //nolint:nestif
158-
if !flagSet.Parsed() {
159-
// Set the flagSet output to something that will not be displayed, otherwise in case of an error
160-
// it will display the usage, which we don't want.
161-
flagSet.SetOutput(io.Discard)
162-
163-
// Try to parse each flag independently so that if we encounter any unexpected flag (maybe used elsewhere),
164-
// the parsing won't stop, and we make sure we try to parse every flag passed when running the command.
165-
for _, arg := range os.Args[1:] {
166-
if err := flagSet.Parse([]string{arg}); err != nil {
167-
// Simply log errors that can happen, such as parsing unexpected flags. We want this to be silent,
168-
// and we won't want to stop the execution.
169-
slog.Error("could not parse flagSet", "err", err)
170-
}
97+
err := processFlags(flagInfos, flagSet, seeded)
98+
if err != nil {
99+
return err
100+
}
101+
102+
return evaluateSeedMap(seeded)
103+
}
104+
105+
func processSeedField(f *config.Field, seedMap fieldMap) error {
106+
val, ok := f.Sources()[config.SourceSeed]
107+
if !ok {
108+
return nil
109+
}
110+
err := f.Set(val, 0)
111+
if err != nil {
112+
return err
113+
}
114+
slog.Debug("seed applied", "value", f, "name", f.Name())
115+
seedMap[f] = true
116+
return nil
117+
}
118+
119+
func processEnvField(f *config.Field, seedMap fieldMap) error {
120+
key, ok := f.Sources()[config.SourceEnv]
121+
if !ok {
122+
return nil
123+
}
124+
val, ok := os.LookupEnv(key)
125+
if !ok {
126+
if seedMap[f] {
127+
slog.Debug("env var did not exist", "key", key, "name", f.Name())
128+
} else {
129+
slog.Debug("env var did not exist and no seed value provided", "key", key, "name", f.Name())
130+
}
131+
return nil
132+
}
133+
134+
err := f.Set(val, 0)
135+
if err != nil {
136+
return err
137+
}
138+
slog.Debug("env var applied", "value", f, "name", f.Name())
139+
seedMap[f] = true
140+
return nil
141+
}
142+
143+
func processFileField(f *config.Field, seedMap fieldMap) error {
144+
key, ok := f.Sources()[config.SourceFile]
145+
if !ok {
146+
return nil
147+
}
148+
149+
body, err := os.ReadFile(key)
150+
if err != nil {
151+
slog.Error("failed to read file", "file", key, "name", f.Name(), "err", err)
152+
return nil
153+
}
154+
155+
err = f.Set(string(body), 0)
156+
if err != nil {
157+
return err
158+
}
159+
160+
slog.Debug("file based var applied", "value", f, "field", f.Name())
161+
seedMap[f] = true
162+
return nil
163+
}
164+
165+
func (s *Seeder) processConsulField(f *config.Field, seedMap fieldMap) error {
166+
key, ok := f.Sources()[config.SourceConsul]
167+
if !ok {
168+
return nil
169+
}
170+
gtr, ok := s.getters[config.SourceConsul]
171+
if !ok {
172+
return errors.New("consul getter required")
173+
}
174+
value, version, err := gtr.Get(key)
175+
if err != nil {
176+
slog.Error("failed to get consul", "key", key, "field", f.Name(), "err", err)
177+
return nil
178+
}
179+
if value == nil {
180+
slog.Error("consul key does not exist", "key", key, "field", f.Name())
181+
return nil
182+
}
183+
err = f.Set(*value, version)
184+
if err != nil {
185+
return err
186+
}
187+
slog.Debug("consul value applied", "value", f, "field", f.Name())
188+
seedMap[f] = true
189+
return nil
190+
}
191+
192+
func (s *Seeder) processRedisField(f *config.Field, seedMap fieldMap) error {
193+
key, ok := f.Sources()[config.SourceRedis]
194+
if !ok {
195+
return nil
196+
}
197+
gtr, ok := s.getters[config.SourceRedis]
198+
if !ok {
199+
return errors.New("redis getter required")
200+
}
201+
value, version, err := gtr.Get(key)
202+
if err != nil {
203+
slog.Error("failed to get redis", "key", key, "field", f.Name(), "err", err)
204+
return nil
205+
}
206+
if value == nil {
207+
slog.Error("redis key does not exist", "key", key, "field", f.Name())
208+
return nil
209+
}
210+
err = f.Set(*value, version)
211+
if err != nil {
212+
return err
213+
}
214+
slog.Debug("redis value applied", "value", f, "field", f.Name())
215+
seedMap[f] = true
216+
return nil
217+
}
218+
219+
func processFlagField(f *config.Field, flagSet *flag.FlagSet) (*flagInfo, bool) {
220+
key, ok := f.Sources()[config.SourceFlag]
221+
if !ok {
222+
return nil, false
223+
}
224+
var val string
225+
flagSet.StringVar(&val, key, "", "")
226+
return &flagInfo{key, f, &val}, true
227+
}
228+
229+
func processFlags(infos []*flagInfo, flagSet *flag.FlagSet, seedMap fieldMap) error {
230+
if len(infos) == 0 {
231+
return nil
232+
}
233+
234+
if !flagSet.Parsed() {
235+
// Set the flagSet output to something that will not be displayed, otherwise in case of an error
236+
// it will display the usage, which we don't want.
237+
flagSet.SetOutput(io.Discard)
238+
239+
// Try to parse each flag independently so that if we encounter any unexpected flag (maybe used elsewhere),
240+
// the parsing won't stop, and we make sure we try to parse every flag passed when running the command.
241+
for _, arg := range os.Args[1:] {
242+
if err := flagSet.Parse([]string{arg}); err != nil {
243+
// Simply log errors that can happen, such as parsing unexpected flags. We want this to be silent,
244+
// and we won't want to stop the execution.
245+
slog.Error("could not parse flagSet", "err", err)
171246
}
172247
}
173-
for _, flagInfo := range flagInfos {
174-
hasFlag := false
175-
flagSet.Visit(func(f *flag.Flag) {
176-
if f.Name == flagInfo.key {
177-
hasFlag = true
178-
return
179-
}
180-
})
181-
if hasFlag && flagInfo.value != nil {
182-
err := flagInfo.field.Set(*flagInfo.value, 0)
183-
if err != nil {
184-
return err
185-
}
186-
slog.Debug("flag value applied", "value", flagInfo.field, "field", flagInfo.field.Name())
187-
seedMap[flagInfo.field] = true
188-
} else {
189-
slog.Debug("flag var did not exist", "key", flagInfo.key, "field", flagInfo.field.Name())
248+
}
249+
250+
for _, info := range infos {
251+
hasFlag := false
252+
flagSet.Visit(func(f *flag.Flag) {
253+
if f.Name == info.key {
254+
hasFlag = true
255+
return
190256
}
257+
})
258+
if hasFlag && info.value != nil {
259+
err := info.field.Set(*info.value, 0)
260+
if err != nil {
261+
return err
262+
}
263+
slog.Debug("flag value applied", "value", info.field, "field", info.field.Name())
264+
seedMap[info.field] = true
265+
} else {
266+
slog.Debug("flag var did not exist", "key", info.key, "field", info.field.Name())
191267
}
192268
}
269+
return nil
270+
}
193271

272+
func evaluateSeedMap(seedMap fieldMap) error {
194273
sb := strings.Builder{}
195274
for f, seeded := range seedMap {
196275
if !seeded {

0 commit comments

Comments
 (0)