Skip to content

Commit 5da92bc

Browse files
committed
refactor: make variable resolving easier
1 parent c763054 commit 5da92bc

File tree

11 files changed

+115
-103
lines changed

11 files changed

+115
-103
lines changed

cmd/set/var.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"github.com/loft-sh/devspace/pkg/devspace/config/loader/variable"
88
"github.com/loft-sh/devspace/pkg/devspace/config/versions/latest"
99

10-
"github.com/loft-sh/devspace/pkg/devspace/config/loader"
1110
"github.com/loft-sh/devspace/pkg/util/factory"
1211
"github.com/loft-sh/devspace/pkg/util/log"
1312
"github.com/loft-sh/devspace/pkg/util/message"
@@ -125,7 +124,7 @@ type variableParser struct {
125124
Used map[string]bool
126125
}
127126

128-
func (v *variableParser) Parse(configPath string, originalRawConfig map[interface{}]interface{}, rawConfig map[interface{}]interface{}, vars []*latest.Variable, resolver variable.Resolver, options *loader.ConfigOptions, log log.Logger) (*latest.Config, error) {
127+
func (v *variableParser) Parse(originalRawConfig map[interface{}]interface{}, rawConfig map[interface{}]interface{}, vars []*latest.Variable, resolver variable.Resolver, log log.Logger) (*latest.Config, error) {
129128
// Find out what vars are really used
130129
varsUsed, err := resolver.FindVariables(rawConfig, vars)
131130
if err != nil {

pkg/devspace/config/loader/expression/expression.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func ResolveAllExpressions(preparedConfig interface{}, dir string) (interface{},
2525
case string:
2626
return ResolveExpressions(t, dir)
2727
case map[interface{}]interface{}:
28-
err := walk.Walk(t, expressionMatchFn, func(value string) (interface{}, error) {
28+
err := walk.Walk(t, expressionMatchFn, func(_, value string) (interface{}, error) {
2929
return ResolveExpressions(value, dir)
3030
})
3131
if err != nil {

pkg/devspace/config/loader/loader.go

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -274,16 +274,16 @@ func (l *configLoader) parseConfig(absPath string, rawConfig map[interface{}]int
274274
}
275275

276276
// create a new variable resolver
277-
resolver := l.newVariableResolver(generatedConfig, options, log)
277+
resolver := l.newVariableResolver(generatedConfig, absPath, options, log)
278278

279-
// copy raw config
280-
copiedRawConfig, err := copyRaw(rawConfig)
279+
// parse cli --var's, the resolver will cache them for us
280+
_, err = resolver.ConvertFlags(options.Vars)
281281
if err != nil {
282282
return nil, nil, nil, err
283283
}
284284

285-
// parse cli --var's, the resolver will cache them for us
286-
_, err = resolver.ConvertFlags(options.Vars)
285+
// copy raw config
286+
copiedRawConfig, err := copyRaw(rawConfig)
287287
if err != nil {
288288
return nil, nil, nil, err
289289
}
@@ -294,6 +294,12 @@ func (l *configLoader) parseConfig(absPath string, rawConfig map[interface{}]int
294294
return nil, nil, nil, err
295295
}
296296

297+
// validate variables
298+
err = validateVars(vars)
299+
if err != nil {
300+
return nil, nil, nil, err
301+
}
302+
297303
// prepare profiles
298304
copiedRawConfig, err = prepareProfiles(copiedRawConfig, resolver, filepath.Dir(absPath), vars)
299305
if err != nil {
@@ -306,7 +312,7 @@ func (l *configLoader) parseConfig(absPath string, rawConfig map[interface{}]int
306312
return nil, nil, nil, err
307313
}
308314

309-
// Load defined variables
315+
// Load defined variables again (might be changed through profiles)
310316
vars, err = versions.ParseVariables(copiedRawConfig, log)
311317
if err != nil {
312318
return nil, nil, nil, err
@@ -322,7 +328,7 @@ func (l *configLoader) parseConfig(absPath string, rawConfig map[interface{}]int
322328
delete(copiedRawConfig, "vars")
323329

324330
// parse the config
325-
latestConfig, err := parser.Parse(absPath, rawConfig, copiedRawConfig, vars, resolver, options, log)
331+
latestConfig, err := parser.Parse(rawConfig, copiedRawConfig, vars, resolver, log)
326332
if err != nil {
327333
return nil, nil, nil, err
328334
}
@@ -440,7 +446,7 @@ func prepareProfiles(config map[interface{}]interface{}, resolver variable.Resol
440446
return config, nil
441447
}
442448

443-
resolved, err := resolve(rawProfiles, resolver, dir, vars)
449+
resolved, err := resolve(rawProfiles, resolver, vars)
444450
if err != nil {
445451
return nil, err
446452
}
@@ -451,7 +457,7 @@ func prepareProfiles(config map[interface{}]interface{}, resolver variable.Resol
451457
}
452458

453459
for idx, profile := range profiles {
454-
resolvedProfile, err := resolve(profile, resolver, dir, vars)
460+
resolvedProfile, err := resolve(profile, resolver, vars)
455461
if err != nil {
456462
return nil, err
457463
}
@@ -463,7 +469,7 @@ func prepareProfiles(config map[interface{}]interface{}, resolver variable.Resol
463469

464470
// Resolve merge field
465471
if profileMap["merge"] != nil {
466-
merge, err := resolve(profileMap["merge"], resolver, dir, vars)
472+
merge, err := resolve(profileMap["merge"], resolver, vars)
467473
if err != nil {
468474
return nil, err
469475
}
@@ -472,7 +478,7 @@ func prepareProfiles(config map[interface{}]interface{}, resolver variable.Resol
472478

473479
// Resolve patches field
474480
if profileMap["patches"] != nil {
475-
patches, err := resolve(profileMap["patches"], resolver, dir, vars)
481+
patches, err := resolve(profileMap["patches"], resolver, vars)
476482
if err != nil {
477483
return nil, err
478484
}
@@ -481,7 +487,7 @@ func prepareProfiles(config map[interface{}]interface{}, resolver variable.Resol
481487

482488
// Resolve replace field
483489
if profileMap["replace"] != nil {
484-
replace, err := resolve(profileMap["replace"], resolver, dir, vars)
490+
replace, err := resolve(profileMap["replace"], resolver, vars)
485491
if err != nil {
486492
return nil, err
487493
}
@@ -490,7 +496,7 @@ func prepareProfiles(config map[interface{}]interface{}, resolver variable.Resol
490496

491497
// Resolve strategicMerge field
492498
if profileMap["strategicMerge"] != nil {
493-
strategicMerge, err := resolve(profileMap["strategicMerge"], resolver, dir, vars)
499+
strategicMerge, err := resolve(profileMap["strategicMerge"], resolver, vars)
494500
if err != nil {
495501
return nil, err
496502
}
@@ -511,20 +517,14 @@ func prepareProfiles(config map[interface{}]interface{}, resolver variable.Resol
511517
return config, nil
512518
}
513519

514-
func resolve(data interface{}, resolver variable.Resolver, dir string, vars []*latest.Variable) (interface{}, error) {
520+
func resolve(data interface{}, resolver variable.Resolver, vars []*latest.Variable) (interface{}, error) {
515521
_, ok := data.(string)
516522
if !ok {
517523
return data, nil
518524
}
519525

520-
// first resolve variables
521-
data, err := resolver.FindAndFillVariables(data, vars)
522-
if err != nil {
523-
return nil, err
524-
}
525-
526-
// evaluate expressions
527-
return expression.ResolveAllExpressions(data, dir)
526+
// find and fill variables
527+
return resolver.FillVariables(data, vars)
528528
}
529529

530530
func (l *configLoader) applyProfiles(data map[interface{}]interface{}, options *ConfigOptions, resolver variable.Resolver, vars []*latest.Variable, log log.Logger) (map[interface{}]interface{}, error) {
@@ -567,10 +567,10 @@ func (l *configLoader) applyProfiles(data map[interface{}]interface{}, options *
567567
return data, nil
568568
}
569569

570-
func (l *configLoader) newVariableResolver(generatedConfig *generated.Config, options *ConfigOptions, log log.Logger) variable.Resolver {
570+
func (l *configLoader) newVariableResolver(generatedConfig *generated.Config, absPath string, options *ConfigOptions, log log.Logger) variable.Resolver {
571571
return variable.NewResolver(generatedConfig.Vars, &variable.PredefinedVariableOptions{
572572
BasePath: options.BasePath,
573-
ConfigPath: ConfigPath(l.configPath),
573+
ConfigPath: absPath,
574574
KubeContextFlag: options.KubeContext,
575575
NamespaceFlag: options.Namespace,
576576
KubeConfigLoader: l.kubeConfigLoader,

pkg/devspace/config/loader/parser.go

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
package loader
22

33
import (
4-
"github.com/loft-sh/devspace/pkg/devspace/config/loader/expression"
54
"github.com/loft-sh/devspace/pkg/devspace/config/loader/variable"
65
"github.com/loft-sh/devspace/pkg/devspace/config/versions"
76
"github.com/loft-sh/devspace/pkg/devspace/config/versions/latest"
87
"github.com/loft-sh/devspace/pkg/util/log"
98
"github.com/pkg/errors"
109
"gopkg.in/yaml.v2"
11-
"path/filepath"
1210
)
1311

1412
type Parser interface {
15-
Parse(configPath string, originalRawConfig map[interface{}]interface{}, rawConfig map[interface{}]interface{}, vars []*latest.Variable, resolver variable.Resolver, options *ConfigOptions, log log.Logger) (*latest.Config, error)
13+
Parse(originalRawConfig map[interface{}]interface{}, rawConfig map[interface{}]interface{}, vars []*latest.Variable, resolver variable.Resolver, log log.Logger) (*latest.Config, error)
1614
}
1715

1816
func NewDefaultParser() Parser {
@@ -21,11 +19,11 @@ func NewDefaultParser() Parser {
2119

2220
type defaultParser struct{}
2321

24-
func (d *defaultParser) Parse(configPath string, originalRawConfig map[interface{}]interface{}, rawConfig map[interface{}]interface{}, vars []*latest.Variable, resolver variable.Resolver, options *ConfigOptions, log log.Logger) (*latest.Config, error) {
22+
func (d *defaultParser) Parse(originalRawConfig map[interface{}]interface{}, rawConfig map[interface{}]interface{}, vars []*latest.Variable, resolver variable.Resolver, log log.Logger) (*latest.Config, error) {
2523
// delete the commands, since we don't need it in a normal scenario
2624
delete(rawConfig, "commands")
2725

28-
return fillVariablesAndParse(configPath, rawConfig, vars, resolver, options, log)
26+
return fillVariablesAndParse(resolver, rawConfig, vars, log)
2927
}
3028

3129
func NewWithCommandsParser() Parser {
@@ -34,8 +32,8 @@ func NewWithCommandsParser() Parser {
3432

3533
type withCommandsParser struct{}
3634

37-
func (d *withCommandsParser) Parse(configPath string, originalRawConfig map[interface{}]interface{}, rawConfig map[interface{}]interface{}, vars []*latest.Variable, resolver variable.Resolver, options *ConfigOptions, log log.Logger) (*latest.Config, error) {
38-
return fillVariablesAndParse(configPath, rawConfig, vars, resolver, options, log)
35+
func (d *withCommandsParser) Parse(originalRawConfig map[interface{}]interface{}, rawConfig map[interface{}]interface{}, vars []*latest.Variable, resolver variable.Resolver, log log.Logger) (*latest.Config, error) {
36+
return fillVariablesAndParse(resolver, rawConfig, vars, log)
3937
}
4038

4139
func NewCommandsParser() Parser {
@@ -44,14 +42,14 @@ func NewCommandsParser() Parser {
4442

4543
type commandsParser struct{}
4644

47-
func (c *commandsParser) Parse(configPath string, originalRawConfig map[interface{}]interface{}, rawConfig map[interface{}]interface{}, vars []*latest.Variable, resolver variable.Resolver, options *ConfigOptions, log log.Logger) (*latest.Config, error) {
45+
func (c *commandsParser) Parse(originalRawConfig map[interface{}]interface{}, rawConfig map[interface{}]interface{}, vars []*latest.Variable, resolver variable.Resolver, log log.Logger) (*latest.Config, error) {
4846
// modify the config
4947
preparedConfig, err := versions.ParseCommands(rawConfig)
5048
if err != nil {
5149
return nil, err
5250
}
5351

54-
return fillVariablesAndParse(configPath, preparedConfig, vars, resolver, options, log)
52+
return fillVariablesAndParse(resolver, preparedConfig, vars, log)
5553
}
5654

5755
func NewProfilesParser() Parser {
@@ -60,7 +58,7 @@ func NewProfilesParser() Parser {
6058

6159
type profilesParser struct{}
6260

63-
func (p *profilesParser) Parse(configPath string, originalRawConfig map[interface{}]interface{}, rawConfig map[interface{}]interface{}, vars []*latest.Variable, resolver variable.Resolver, options *ConfigOptions, log log.Logger) (*latest.Config, error) {
61+
func (p *profilesParser) Parse(originalRawConfig map[interface{}]interface{}, rawConfig map[interface{}]interface{}, vars []*latest.Variable, resolver variable.Resolver, log log.Logger) (*latest.Config, error) {
6462
rawMap, err := copyRaw(originalRawConfig)
6563
if err != nil {
6664
return nil, err
@@ -96,21 +94,9 @@ func (p *profilesParser) Parse(configPath string, originalRawConfig map[interfac
9694
return retConfig, nil
9795
}
9896

99-
func fillVariablesAndParse(configPath string, preparedConfig map[interface{}]interface{}, vars []*latest.Variable, resolver variable.Resolver, options *ConfigOptions, log log.Logger) (*latest.Config, error) {
100-
// fill in variables
101-
preparedConfigInterface, err := resolver.FindAndFillVariables(preparedConfig, vars)
102-
if err != nil {
103-
return nil, err
104-
}
105-
106-
// execute expressions
107-
preparedConfigInterface, err = expression.ResolveAllExpressions(preparedConfigInterface, filepath.Dir(configPath))
108-
if err != nil {
109-
return nil, err
110-
}
111-
97+
func fillVariablesAndParse(resolver variable.Resolver, preparedConfig map[interface{}]interface{}, vars []*latest.Variable, log log.Logger) (*latest.Config, error) {
11298
// fill in variables again
113-
preparedConfigInterface, err = resolver.FindAndFillVariables(preparedConfigInterface, vars)
99+
preparedConfigInterface, err := resolver.FillVariables(preparedConfig, vars)
114100
if err != nil {
115101
return nil, err
116102
}

pkg/devspace/config/loader/validate.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package loader
33
import (
44
"fmt"
55
"path/filepath"
6+
"regexp"
67
"strings"
78

89
jsonyaml "github.com/ghodss/yaml"
@@ -78,10 +79,14 @@ func validate(config *latest.Config, log log.Logger) error {
7879
return nil
7980
}
8081

82+
var nameRegEx = regexp.MustCompile(`^[a-zA-Z0-9_\-]+$`)
83+
8184
func validateVars(vars []*latest.Variable) error {
8285
for i, v := range vars {
8386
if v.Name == "" {
8487
return fmt.Errorf("vars[*].name has to be specified")
88+
} else if !nameRegEx.MatchString(v.Name) {
89+
return fmt.Errorf("vars[*].name %s must match regex: %v", v.Name, nameRegEx.String())
8590
}
8691

8792
// make sure is unique

pkg/devspace/config/loader/variable/predefined_variable.go

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,26 +38,26 @@ type PredefinedVariableFunction func(options *PredefinedVariableOptions) (interf
3838

3939
// predefinedVars holds all predefined variables that can be used in the config
4040
var predefinedVars = map[string]PredefinedVariableFunction{
41-
"DEVSPACE_VERSION": func(options *PredefinedVariableOptions) (interface{}, error) {
41+
"devspace.version": func(options *PredefinedVariableOptions) (interface{}, error) {
4242
return upgrade.GetVersion(), nil
4343
},
44-
"DEVSPACE_RANDOM": func(options *PredefinedVariableOptions) (interface{}, error) {
44+
"devspace.random": func(options *PredefinedVariableOptions) (interface{}, error) {
4545
return randutil.GenerateRandomString(6), nil
4646
},
47-
"DEVSPACE_PROFILE": func(options *PredefinedVariableOptions) (interface{}, error) {
47+
"devspace.profile": func(options *PredefinedVariableOptions) (interface{}, error) {
4848
return options.Profile, nil
4949
},
50-
"DEVSPACE_USER_HOME": func(options *PredefinedVariableOptions) (interface{}, error) {
50+
"devspace.userHome": func(options *PredefinedVariableOptions) (interface{}, error) {
5151
homeDir, err := homedir.Dir()
5252
if err != nil {
5353
return nil, err
5454
}
5555
return homeDir, nil
5656
},
57-
"DEVSPACE_TIMESTAMP": func(options *PredefinedVariableOptions) (interface{}, error) {
57+
"devspace.timestamp": func(options *PredefinedVariableOptions) (interface{}, error) {
5858
return strconv.FormatInt(time.Now().Unix(), 10), nil
5959
},
60-
"DEVSPACE_GIT_BRANCH": func(options *PredefinedVariableOptions) (interface{}, error) {
60+
"devspace.git.branch": func(options *PredefinedVariableOptions) (interface{}, error) {
6161
configPath := options.BasePath
6262
if configPath == "" {
6363
configPath = options.ConfigPath
@@ -70,7 +70,7 @@ var predefinedVars = map[string]PredefinedVariableFunction{
7070

7171
return branch, nil
7272
},
73-
"DEVSPACE_GIT_COMMIT": func(options *PredefinedVariableOptions) (interface{}, error) {
73+
"devspace.git.commit": func(options *PredefinedVariableOptions) (interface{}, error) {
7474
configPath := options.BasePath
7575
if configPath == "" {
7676
configPath = options.ConfigPath
@@ -83,15 +83,15 @@ var predefinedVars = map[string]PredefinedVariableFunction{
8383

8484
return hash[:8], nil
8585
},
86-
"DEVSPACE_CONTEXT": func(options *PredefinedVariableOptions) (interface{}, error) {
86+
"devspace.context": func(options *PredefinedVariableOptions) (interface{}, error) {
8787
_, activeContext, _, _, err := util.NewClientByContext(options.KubeContextFlag, options.NamespaceFlag, false, options.KubeConfigLoader)
8888
if err != nil {
8989
return "", err
9090
}
9191

9292
return activeContext, nil
9393
},
94-
"DEVSPACE_NAMESPACE": func(options *PredefinedVariableOptions) (interface{}, error) {
94+
"devspace.namespace": func(options *PredefinedVariableOptions) (interface{}, error) {
9595
_, _, activeNamespace, _, err := util.NewClientByContext(options.KubeContextFlag, options.NamespaceFlag, false, options.KubeConfigLoader)
9696
if err != nil {
9797
return "", err
@@ -101,6 +101,19 @@ var predefinedVars = map[string]PredefinedVariableFunction{
101101
},
102102
}
103103

104+
func init() {
105+
// migrate old names
106+
predefinedVars["DEVSPACE_VERSION"] = predefinedVars["devspace.version"]
107+
predefinedVars["DEVSPACE_RANDOM"] = predefinedVars["devspace.random"]
108+
predefinedVars["DEVSPACE_PROFILE"] = predefinedVars["devspace.profile"]
109+
predefinedVars["DEVSPACE_USER_HOME"] = predefinedVars["devspace.userHome"]
110+
predefinedVars["DEVSPACE_TIMESTAMP"] = predefinedVars["devspace.timestamp"]
111+
predefinedVars["DEVSPACE_GIT_BRANCH"] = predefinedVars["devspace.git.branch"]
112+
predefinedVars["DEVSPACE_GIT_COMMIT"] = predefinedVars["devspace.git.commit"]
113+
predefinedVars["DEVSPACE_CONTEXT"] = predefinedVars["devspace.context"]
114+
predefinedVars["DEVSPACE_NAMESPACE"] = predefinedVars["devspace.namespace"]
115+
}
116+
104117
func IsPredefinedVariable(name string) bool {
105118
name = strings.ToUpper(name)
106119
_, ok := predefinedVars[name]

0 commit comments

Comments
 (0)