Skip to content

Commit 358a5db

Browse files
simple implementation of a config file v2
1 parent 16ad4b1 commit 358a5db

File tree

15 files changed

+747
-162
lines changed

15 files changed

+747
-162
lines changed

commands.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,10 @@ func displayGroups(output io.Writer, configuration *config.Config) {
212212
if len(groups) == 0 {
213213
return
214214
}
215-
fmt.Fprintln(output, "Groups available (name, profiles):")
215+
fmt.Fprintln(output, "Groups available (name, profiles, description):")
216216
w := tabwriter.NewWriter(output, 0, 0, 2, ' ', 0)
217217
for name, groupList := range groups {
218-
_, _ = fmt.Fprintf(w, "\t%s:\t%s\n", name, strings.Join(groupList, ", "))
218+
_, _ = fmt.Fprintf(w, "\t%s:\t[%s]\t%s\n", name, strings.Join(groupList.Profiles, ", "), groupList.Description)
219219
}
220220
_ = w.Flush()
221221
fmt.Fprintln(output, "")
@@ -262,15 +262,18 @@ func containsString(args []string, arg string) bool {
262262
}
263263

264264
func showProfile(output io.Writer, c *config.Config, flags commandLineFlags, args []string) error {
265-
// Show global section first
265+
// 1. Show version
266+
fmt.Fprintf(os.Stdout, "version: %d\n\n", c.GetVersion())
267+
268+
// 2. Show global section first
266269
global, err := c.GetGlobalSection()
267270
if err != nil {
268271
return fmt.Errorf("cannot show global: %w", err)
269272
}
270273
config.ShowStruct(os.Stdout, global, constants.SectionConfigurationGlobal)
271-
fmt.Println("")
274+
fmt.Fprintln(os.Stdout, "")
272275

273-
// Then show profile
276+
// 3. Show profile
274277
profile, err := c.GetProfile(flags.name)
275278
if err != nil {
276279
return fmt.Errorf("cannot show profile '%s': %w", flags.name, err)
@@ -282,7 +285,7 @@ func showProfile(output io.Writer, c *config.Config, flags commandLineFlags, arg
282285
displayProfileDeprecationNotices(profile)
283286

284287
config.ShowStruct(os.Stdout, profile, flags.name)
285-
fmt.Println("")
288+
fmt.Fprintln(os.Stdout, "")
286289
return nil
287290
}
288291

@@ -327,7 +330,7 @@ func selectProfiles(c *config.Config, flags commandLineFlags, args []string) []s
327330

328331
} else if !c.HasProfile(flags.name) {
329332
if names, err := c.GetProfileGroup(flags.name); err == nil && names != nil {
330-
profiles = names
333+
profiles = names.Profiles
331334
}
332335
}
333336

config/config.go

Lines changed: 59 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ type Config struct {
2626
configFile string
2727
includeFiles []string
2828
viper *viper.Viper
29-
groups map[string][]string
29+
groups map[string]Group
3030
sourceTemplates *template.Template
31+
version ConfigVersion
3132
}
3233

3334
// This is where things are getting hairy:
@@ -106,10 +107,10 @@ func LoadFile(configFile, format string) (*Config, error) {
106107
for _, include := range includes {
107108
format := formatFromExtension(include)
108109

109-
if format == "hcl" && c.format != "hcl" {
110+
if format == FormatHCL && c.format != FormatHCL {
110111
err = fmt.Errorf("hcl format (%s) cannot be used in includes from %s: %s", include, c.format, c.configFile)
111-
} else if c.format == "hcl" && format != "hcl" {
112-
err = fmt.Errorf("%s is in hcl format, includes must use the same format. Cannot load %s", c.configFile, include)
112+
} else if c.format == FormatHCL && format != FormatHCL {
113+
err = fmt.Errorf("%s is in hcl format, includes must use the same format: cannot load %s", c.configFile, include)
113114
} else {
114115
err = readAndAdd(include, false)
115116
if err == nil {
@@ -244,10 +245,11 @@ func (c *Config) reloadTemplates(data TemplateData) error {
244245
return err
245246
}
246247

247-
// IsSet checks if the key contains a value
248+
// IsSet checks if the key contains a value. Keys and subkeys can be separated by a "."
248249
func (c *Config) IsSet(key string) bool {
249-
if strings.Contains(key, ".") {
250-
clog.Warningf("it should not search for a subkey: %s", key)
250+
if strings.Contains(key, ".") && c.format == FormatHCL {
251+
clog.Error("HCL format is not supported in version 1, please use version 0 or another file format")
252+
return false
251253
}
252254
return c.viper.IsSet(key)
253255
}
@@ -264,24 +266,28 @@ func (c *Config) Get(key string) interface{} {
264266

265267
// HasProfile returns true if the profile exists in the configuration
266268
func (c *Config) HasProfile(profileKey string) bool {
267-
return c.IsSet(profileKey)
268-
}
269-
270-
// AllSettings merges all settings and returns them as a map[string]interface{}.
271-
func (c *Config) AllSettings() map[string]interface{} {
272-
return c.viper.AllSettings()
269+
return c.IsSet(c.getProfilePath(profileKey))
273270
}
274271

275272
// GetProfileSections returns a list of profiles with all the sections defined inside each
276273
func (c *Config) GetProfileSections() map[string]ProfileInfo {
277274
profiles := map[string]ProfileInfo{}
278-
allSettings := c.AllSettings()
275+
viper := c.viper
276+
if c.GetVersion() >= Version02 {
277+
// move to the profiles subsection
278+
viper = viper.Sub(constants.SectionConfigurationProfiles)
279+
if viper == nil {
280+
// there's no such subsection, so return the empty map
281+
return profiles
282+
}
283+
}
284+
allSettings := viper.AllSettings()
279285
for sectionKey, sectionRawValue := range allSettings {
280286
if sectionKey == constants.SectionConfigurationGlobal || sectionKey == constants.SectionConfigurationGroups {
281287
continue
282288
}
283289
var profileInfo ProfileInfo
284-
if c.format == "hcl" {
290+
if c.format == FormatHCL {
285291
profileInfo = c.getProfileInfoHCL(sectionRawValue)
286292
} else {
287293
profileInfo = c.getProfileInfo(sectionRawValue)
@@ -334,13 +340,13 @@ func (c *Config) getProfileInfoHCL(sectionRawValue interface{}) ProfileInfo {
334340
}
335341

336342
// GetVersion returns the version of the configuration file.
337-
// Default is Version00 if not specified or invalid
343+
// Default is Version01 if not specified or invalid
338344
func (c *Config) GetVersion() ConfigVersion {
339-
version := c.viper.GetString(constants.ParameterVersion)
340-
if version == "" {
341-
return Version00
345+
if c.version > VersionUnknown {
346+
return c.version
342347
}
343-
return ParseVersion(version)
348+
c.version = ParseVersion(c.viper.GetString(constants.ParameterVersion))
349+
return c.version
344350
}
345351

346352
// GetGlobalSection returns the global configuration
@@ -379,7 +385,7 @@ func (c *Config) HasProfileGroup(groupKey string) bool {
379385
}
380386

381387
// GetProfileGroup returns the list of profiles in a group
382-
func (c *Config) GetProfileGroup(groupKey string) ([]string, error) {
388+
func (c *Config) GetProfileGroup(groupKey string) (*Group, error) {
383389
err := c.loadGroups()
384390
if err != nil {
385391
return nil, err
@@ -389,13 +395,13 @@ func (c *Config) GetProfileGroup(groupKey string) ([]string, error) {
389395
if !ok {
390396
return nil, fmt.Errorf("group '%s' not found", groupKey)
391397
}
392-
return group, nil
398+
return &group, nil
393399
}
394400

395401
// GetProfileGroups returns all groups from the configuration
396402
//
397403
// If the groups section does not exist, it returns an empty map
398-
func (c *Config) GetProfileGroups() map[string][]string {
404+
func (c *Config) GetProfileGroups() map[string]Group {
399405
err := c.loadGroups()
400406
if err != nil {
401407
return nil
@@ -405,11 +411,28 @@ func (c *Config) GetProfileGroups() map[string][]string {
405411

406412
func (c *Config) loadGroups() error {
407413
if !c.IsSet(constants.SectionConfigurationGroups) {
408-
c.groups = map[string][]string{}
414+
c.groups = map[string]Group{}
409415
return nil
410416
}
417+
// load groups only once
411418
if c.groups == nil {
412-
groups := map[string][]string{}
419+
if c.GetVersion() == Version01 {
420+
c.groups = map[string]Group{}
421+
groups := map[string][]string{}
422+
err := c.unmarshalKey(constants.SectionConfigurationGroups, &groups)
423+
if err != nil {
424+
return err
425+
}
426+
// fits previous version into new structure
427+
for groupName, group := range groups {
428+
c.groups[groupName] = Group{
429+
Profiles: group,
430+
}
431+
}
432+
return nil
433+
}
434+
// Version 2 onwards
435+
groups := map[string]Group{}
413436
err := c.unmarshalKey(constants.SectionConfigurationGroups, &groups)
414437
if err != nil {
415438
return err
@@ -449,13 +472,13 @@ func (c *Config) getProfile(profileKey string) (*Profile, error) {
449472
var err error
450473
var profile *Profile
451474

452-
if !c.IsSet(profileKey) {
475+
if !c.IsSet(c.getProfilePath(profileKey)) {
453476
// key not found => returns a nil profile
454477
return nil, nil
455478
}
456479

457480
profile = NewProfile(c, profileKey)
458-
err = c.unmarshalKey(profileKey, profile)
481+
err = c.unmarshalKey(c.getProfilePath(profileKey), profile)
459482
if err != nil {
460483
return nil, err
461484
}
@@ -471,7 +494,7 @@ func (c *Config) getProfile(profileKey string) (*Profile, error) {
471494
return nil, fmt.Errorf("error in profile '%s': parent profile '%s' not found", profileKey, inherit)
472495
}
473496
// and reload this profile onto the inherited one
474-
err = c.unmarshalKey(profileKey, profile)
497+
err = c.unmarshalKey(c.getProfilePath(profileKey), profile)
475498
if err != nil {
476499
return nil, err
477500
}
@@ -485,6 +508,14 @@ func (c *Config) getProfile(profileKey string) (*Profile, error) {
485508
return profile, nil
486509
}
487510

511+
// getProfilePath returns the key prefixed with "profiles" if the configuration file version is >= 2
512+
func (c *Config) getProfilePath(key string) string {
513+
if c.GetVersion() == Version01 {
514+
return key
515+
}
516+
return constants.SectionConfigurationProfiles + "." + key
517+
}
518+
488519
// unmarshalKey is a wrapper around viper.UnmarshalKey with the right decoder config options
489520
func (c *Config) unmarshalKey(key string, rawVal interface{}) error {
490521
if c.format == "hcl" {

0 commit comments

Comments
 (0)