@@ -26,8 +26,9 @@ type Config struct {
26
26
configFile string
27
27
includeFiles []string
28
28
viper * viper.Viper
29
- groups map [string ][] string
29
+ groups map [string ]Group
30
30
sourceTemplates * template.Template
31
+ version ConfigVersion
31
32
}
32
33
33
34
// This is where things are getting hairy:
@@ -106,10 +107,10 @@ func LoadFile(configFile, format string) (*Config, error) {
106
107
for _ , include := range includes {
107
108
format := formatFromExtension (include )
108
109
109
- if format == "hcl" && c .format != "hcl" {
110
+ if format == FormatHCL && c .format != FormatHCL {
110
111
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 )
113
114
} else {
114
115
err = readAndAdd (include , false )
115
116
if err == nil {
@@ -244,10 +245,11 @@ func (c *Config) reloadTemplates(data TemplateData) error {
244
245
return err
245
246
}
246
247
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 "."
248
249
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
251
253
}
252
254
return c .viper .IsSet (key )
253
255
}
@@ -264,24 +266,28 @@ func (c *Config) Get(key string) interface{} {
264
266
265
267
// HasProfile returns true if the profile exists in the configuration
266
268
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 ))
273
270
}
274
271
275
272
// GetProfileSections returns a list of profiles with all the sections defined inside each
276
273
func (c * Config ) GetProfileSections () map [string ]ProfileInfo {
277
274
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 ()
279
285
for sectionKey , sectionRawValue := range allSettings {
280
286
if sectionKey == constants .SectionConfigurationGlobal || sectionKey == constants .SectionConfigurationGroups {
281
287
continue
282
288
}
283
289
var profileInfo ProfileInfo
284
- if c .format == "hcl" {
290
+ if c .format == FormatHCL {
285
291
profileInfo = c .getProfileInfoHCL (sectionRawValue )
286
292
} else {
287
293
profileInfo = c .getProfileInfo (sectionRawValue )
@@ -334,13 +340,13 @@ func (c *Config) getProfileInfoHCL(sectionRawValue interface{}) ProfileInfo {
334
340
}
335
341
336
342
// 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
338
344
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
342
347
}
343
- return ParseVersion (version )
348
+ c .version = ParseVersion (c .viper .GetString (constants .ParameterVersion ))
349
+ return c .version
344
350
}
345
351
346
352
// GetGlobalSection returns the global configuration
@@ -379,7 +385,7 @@ func (c *Config) HasProfileGroup(groupKey string) bool {
379
385
}
380
386
381
387
// 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 ) {
383
389
err := c .loadGroups ()
384
390
if err != nil {
385
391
return nil , err
@@ -389,13 +395,13 @@ func (c *Config) GetProfileGroup(groupKey string) ([]string, error) {
389
395
if ! ok {
390
396
return nil , fmt .Errorf ("group '%s' not found" , groupKey )
391
397
}
392
- return group , nil
398
+ return & group , nil
393
399
}
394
400
395
401
// GetProfileGroups returns all groups from the configuration
396
402
//
397
403
// 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 {
399
405
err := c .loadGroups ()
400
406
if err != nil {
401
407
return nil
@@ -405,11 +411,28 @@ func (c *Config) GetProfileGroups() map[string][]string {
405
411
406
412
func (c * Config ) loadGroups () error {
407
413
if ! c .IsSet (constants .SectionConfigurationGroups ) {
408
- c .groups = map [string ][] string {}
414
+ c .groups = map [string ]Group {}
409
415
return nil
410
416
}
417
+ // load groups only once
411
418
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 {}
413
436
err := c .unmarshalKey (constants .SectionConfigurationGroups , & groups )
414
437
if err != nil {
415
438
return err
@@ -449,13 +472,13 @@ func (c *Config) getProfile(profileKey string) (*Profile, error) {
449
472
var err error
450
473
var profile * Profile
451
474
452
- if ! c .IsSet (profileKey ) {
475
+ if ! c .IsSet (c . getProfilePath ( profileKey ) ) {
453
476
// key not found => returns a nil profile
454
477
return nil , nil
455
478
}
456
479
457
480
profile = NewProfile (c , profileKey )
458
- err = c .unmarshalKey (profileKey , profile )
481
+ err = c .unmarshalKey (c . getProfilePath ( profileKey ) , profile )
459
482
if err != nil {
460
483
return nil , err
461
484
}
@@ -471,7 +494,7 @@ func (c *Config) getProfile(profileKey string) (*Profile, error) {
471
494
return nil , fmt .Errorf ("error in profile '%s': parent profile '%s' not found" , profileKey , inherit )
472
495
}
473
496
// and reload this profile onto the inherited one
474
- err = c .unmarshalKey (profileKey , profile )
497
+ err = c .unmarshalKey (c . getProfilePath ( profileKey ) , profile )
475
498
if err != nil {
476
499
return nil , err
477
500
}
@@ -485,6 +508,14 @@ func (c *Config) getProfile(profileKey string) (*Profile, error) {
485
508
return profile , nil
486
509
}
487
510
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
+
488
519
// unmarshalKey is a wrapper around viper.UnmarshalKey with the right decoder config options
489
520
func (c * Config ) unmarshalKey (key string , rawVal interface {}) error {
490
521
if c .format == "hcl" {
0 commit comments