Skip to content

Commit cf5e5ad

Browse files
committed
refactor: refactor image selector creation
1 parent bd0e6ff commit cf5e5ad

File tree

27 files changed

+402
-55
lines changed

27 files changed

+402
-55
lines changed

cmd/dev.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package cmd
22

33
import (
44
"fmt"
5+
runtimevar "github.com/loft-sh/devspace/pkg/devspace/config/loader/variable/runtime"
6+
"github.com/loft-sh/devspace/pkg/devspace/imageselector"
57
"io"
68
"os"
79
"strings"
@@ -11,11 +13,9 @@ import (
1113
"github.com/loft-sh/devspace/pkg/devspace/config"
1214
"github.com/loft-sh/devspace/pkg/devspace/config/legacy"
1315
"github.com/loft-sh/devspace/pkg/devspace/dependency/types"
14-
"github.com/loft-sh/devspace/pkg/devspace/deploy/deployer/util"
1516
"github.com/loft-sh/devspace/pkg/devspace/dev"
1617
"github.com/loft-sh/devspace/pkg/devspace/docker"
1718
"github.com/loft-sh/devspace/pkg/devspace/hook"
18-
"github.com/loft-sh/devspace/pkg/util/imageselector"
1919
"github.com/loft-sh/devspace/pkg/util/interrupt"
2020
"github.com/loft-sh/devspace/pkg/util/survey"
2121

@@ -607,7 +607,7 @@ func (cmd *DevCmd) startOutput(configInterface config.Config, dependencies []typ
607607

608608
var imageSelectors []imageselector.ImageSelector
609609
if config.Dev.Terminal != nil && config.Dev.Terminal.ImageSelector != "" {
610-
imageSelector, err := util.ResolveImageAsImageSelector(config.Dev.Terminal.ImageSelector, configInterface, dependencies)
610+
imageSelector, err := runtimevar.NewRuntimeResolver(true).FillRuntimeVariablesAsImageSelector(config.Dev.Terminal.ImageSelector, configInterface, dependencies)
611611
if err != nil {
612612
return 0, err
613613
}

cmd/init.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cmd
22

33
import (
44
"fmt"
5+
"github.com/loft-sh/devspace/pkg/devspace/imageselector"
56
"io/ioutil"
67
"net/http"
78
"os"
@@ -23,7 +24,6 @@ import (
2324
"github.com/loft-sh/devspace/pkg/util/dockerfile"
2425
"github.com/loft-sh/devspace/pkg/util/factory"
2526
"github.com/loft-sh/devspace/pkg/util/fsutil"
26-
"github.com/loft-sh/devspace/pkg/util/imageselector"
2727
"github.com/loft-sh/devspace/pkg/util/log"
2828
"github.com/loft-sh/devspace/pkg/util/survey"
2929
"github.com/mgutz/ansi"

cmd/logs.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@ package cmd
22

33
import (
44
"fmt"
5+
runtimevar "github.com/loft-sh/devspace/pkg/devspace/config/loader/variable/runtime"
6+
"github.com/loft-sh/devspace/pkg/devspace/imageselector"
57

68
"github.com/loft-sh/devspace/cmd/flags"
79
config2 "github.com/loft-sh/devspace/pkg/devspace/config"
810
"github.com/loft-sh/devspace/pkg/devspace/config/generated"
911
"github.com/loft-sh/devspace/pkg/devspace/config/loader"
1012
"github.com/loft-sh/devspace/pkg/devspace/dependency"
1113
"github.com/loft-sh/devspace/pkg/devspace/dependency/types"
12-
"github.com/loft-sh/devspace/pkg/devspace/deploy/deployer/util"
1314
"github.com/loft-sh/devspace/pkg/devspace/hook"
1415
"github.com/loft-sh/devspace/pkg/devspace/kubectl"
1516
"github.com/loft-sh/devspace/pkg/devspace/plugin"
1617
"github.com/loft-sh/devspace/pkg/devspace/services/targetselector"
1718
"github.com/loft-sh/devspace/pkg/util/factory"
18-
"github.com/loft-sh/devspace/pkg/util/imageselector"
1919
"github.com/loft-sh/devspace/pkg/util/log"
2020
"github.com/loft-sh/devspace/pkg/util/message"
2121
"github.com/pkg/errors"
@@ -161,7 +161,7 @@ func getImageSelector(client kubectl.Client, configLoader loader.ConfigLoader, c
161161
}
162162
}
163163

164-
resolved, err := util.ResolveImageAsImageSelector(imageSelector, config, dependencies)
164+
resolved, err := runtimevar.NewRuntimeResolver(true).FillRuntimeVariablesAsImageSelector(imageSelector, config, dependencies)
165165
if err != nil {
166166
return nil, err
167167
}

cmd/restart.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ package cmd
33
import (
44
"context"
55
"fmt"
6+
runtimevar "github.com/loft-sh/devspace/pkg/devspace/config/loader/variable/runtime"
7+
"github.com/loft-sh/devspace/pkg/devspace/imageselector"
68

79
"github.com/loft-sh/devspace/pkg/devspace/dependency"
8-
"github.com/loft-sh/devspace/pkg/devspace/deploy/deployer/util"
910
"github.com/loft-sh/devspace/pkg/devspace/hook"
1011
"github.com/loft-sh/devspace/pkg/devspace/kubectl"
1112
"github.com/loft-sh/devspace/pkg/devspace/plugin"
1213
"github.com/loft-sh/devspace/pkg/devspace/services/inject"
1314
"github.com/loft-sh/devspace/pkg/devspace/services/targetselector"
1415
"github.com/loft-sh/devspace/pkg/util/factory"
15-
"github.com/loft-sh/devspace/pkg/util/imageselector"
1616
"github.com/loft-sh/devspace/pkg/util/ptr"
1717

1818
"github.com/loft-sh/devspace/cmd/flags"
@@ -152,7 +152,7 @@ func (cmd *RestartCmd) Run(f factory.Factory) error {
152152
options := targetselector.NewOptionsFromFlags("", "", cmd.Namespace, "", cmd.Pick).ApplyConfigParameter(syncPath.LabelSelector, syncPath.Namespace, syncPath.ContainerName, "")
153153
options.ImageSelector = []imageselector.ImageSelector{}
154154
if syncPath.ImageSelector != "" {
155-
imageSelector, err := util.ResolveImageAsImageSelector(syncPath.ImageSelector, configInterface, dep)
155+
imageSelector, err := runtimevar.NewRuntimeResolver(true).FillRuntimeVariablesAsImageSelector(syncPath.ImageSelector, configInterface, dep)
156156
if err != nil {
157157
return err
158158
}

pkg/devspace/config/config.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package config
33
import (
44
"github.com/loft-sh/devspace/pkg/devspace/config/generated"
55
"github.com/loft-sh/devspace/pkg/devspace/config/versions/latest"
6+
"sync"
67
)
78

89
type Config interface {
@@ -20,6 +21,12 @@ type Config interface {
2021
// loading the config
2122
Variables() map[string]interface{}
2223

24+
// RuntimeVariables returns the runtime variables
25+
RuntimeVariables() map[string]interface{}
26+
27+
// SetRuntimeVariable allows to set a runtime variable
28+
SetRuntimeVariable(key string, value interface{})
29+
2330
// Path returns the absolute path from which the config was loaded
2431
Path() string
2532
}
@@ -31,6 +38,8 @@ func NewConfig(raw map[interface{}]interface{}, parsed *latest.Config, generated
3138
generatedConfig: generatedConfig,
3239
resolvedVariables: resolvedVariables,
3340
path: path,
41+
42+
runtimeVariables: map[string]interface{}{},
3443
}
3544
}
3645

@@ -40,6 +49,28 @@ type config struct {
4049
generatedConfig *generated.Config
4150
resolvedVariables map[string]interface{}
4251
path string
52+
53+
runtimeVariablesMutex sync.Mutex
54+
runtimeVariables map[string]interface{}
55+
}
56+
57+
func (c *config) SetRuntimeVariable(key string, value interface{}) {
58+
c.runtimeVariablesMutex.Lock()
59+
defer c.runtimeVariablesMutex.Unlock()
60+
61+
c.runtimeVariables[key] = value
62+
}
63+
64+
func (c *config) RuntimeVariables() map[string]interface{} {
65+
c.runtimeVariablesMutex.Lock()
66+
defer c.runtimeVariablesMutex.Unlock()
67+
68+
retVars := map[string]interface{}{}
69+
for k, v := range c.runtimeVariables {
70+
retVars[k] = v
71+
}
72+
73+
return retVars
4374
}
4475

4576
func (c *config) Config() *latest.Config {

pkg/devspace/config/loader/validate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ package loader
22

33
import (
44
"fmt"
5+
"github.com/loft-sh/devspace/pkg/devspace/imageselector"
56
"path/filepath"
67
"regexp"
78
"strings"
89

910
jsonyaml "github.com/ghodss/yaml"
1011
"github.com/loft-sh/devspace/pkg/devspace/config/versions/latest"
1112
"github.com/loft-sh/devspace/pkg/devspace/deploy/deployer/helm/merge"
12-
"github.com/loft-sh/devspace/pkg/util/imageselector"
1313
"github.com/loft-sh/devspace/pkg/util/log"
1414
"github.com/loft-sh/devspace/pkg/util/yamlutil"
1515
"github.com/pkg/errors"

pkg/devspace/deploy/deployer/util/replace.go renamed to pkg/devspace/config/loader/variable/legacy/replace.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
package util
1+
package legacy
22

33
import (
44
"fmt"
5+
"github.com/loft-sh/devspace/pkg/devspace/imageselector"
56
"regexp"
67
"strings"
78

@@ -10,7 +11,6 @@ import (
1011
"github.com/loft-sh/devspace/pkg/devspace/config/versions/latest"
1112
"github.com/loft-sh/devspace/pkg/devspace/dependency/types"
1213
"github.com/loft-sh/devspace/pkg/devspace/deploy/deployer/kubectl/walk"
13-
"github.com/loft-sh/devspace/pkg/util/imageselector"
1414
)
1515

1616
var (

pkg/devspace/deploy/deployer/util/replace_test.go renamed to pkg/devspace/config/loader/variable/legacy/replace_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package util
1+
package legacy
22

33
import (
44
"testing"

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,6 @@ func (r *resolver) fillVariables(haystack interface{}, exclude []*regexp.Regexp)
5555
return value, nil
5656
}
5757

58-
fmt.Println(path)
59-
6058
return r.replaceString(value)
6159
})
6260
return t, err
@@ -385,6 +383,11 @@ func (r *resolver) fillVariable(name string, definition *latest.Variable) (inter
385383
return variable.Load(definition)
386384
}
387385

386+
// is runtime variable
387+
if strings.HasPrefix(name, "runtime.") {
388+
return nil, fmt.Errorf("cannot resolve %s in this config area as this config region is loaded on startup. Please check the DevSpace docs in which config regions you can use runtime variables", name)
389+
}
390+
388391
// fill variable without definition
389392
if definition == nil {
390393
return NewUndefinedVariable(name, r.persistentCache, r.log).Load(definition)
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package runtime
2+
3+
import (
4+
"fmt"
5+
"github.com/loft-sh/devspace/pkg/devspace/config"
6+
"github.com/loft-sh/devspace/pkg/devspace/config/loader/variable/expression"
7+
"github.com/loft-sh/devspace/pkg/devspace/config/loader/variable/legacy"
8+
"github.com/loft-sh/devspace/pkg/devspace/dependency/types"
9+
"github.com/loft-sh/devspace/pkg/devspace/deploy/deployer/kubectl/walk"
10+
"github.com/loft-sh/devspace/pkg/devspace/imageselector"
11+
varspkg "github.com/loft-sh/devspace/pkg/util/vars"
12+
"path/filepath"
13+
"strings"
14+
)
15+
16+
func varMatchFn(key, value string) bool {
17+
return true
18+
}
19+
20+
// NewRuntimeResolver creates a new resolver that caches resolved variables in memory and in the provided cache
21+
func NewRuntimeResolver(enableLegacyHelpers bool) RuntimeResolver {
22+
return &runtimeResolver{
23+
enableLegacyHelpers: enableLegacyHelpers,
24+
}
25+
}
26+
27+
type runtimeResolver struct {
28+
enableLegacyHelpers bool
29+
}
30+
31+
func (r *runtimeResolver) FillRuntimeVariablesAsString(haystack interface{}, config config.Config, dependencies []types.Dependency) (string, error) {
32+
out, err := r.FillRuntimeVariables(haystack, config, dependencies)
33+
if err != nil {
34+
return "", err
35+
}
36+
37+
return fmt.Sprintf("%v", out), nil
38+
}
39+
40+
func (r *runtimeResolver) FillRuntimeVariablesAsImageSelector(haystack interface{}, config config.Config, dependencies []types.Dependency) (*imageselector.ImageSelector, error) {
41+
out, err := r.FillRuntimeVariablesAsString(haystack, config, dependencies)
42+
if err != nil {
43+
return nil, err
44+
}
45+
46+
return &imageselector.ImageSelector{
47+
Image: out,
48+
}, nil
49+
}
50+
51+
func (r *runtimeResolver) FillRuntimeVariablesWithRebuild(haystack interface{}, config config.Config, dependencies []types.Dependency, builtImages map[string]string) (bool, interface{}, error) {
52+
shouldRebuild, haystack, err := r.fillVariables(haystack, config, dependencies, builtImages)
53+
if err != nil {
54+
return false, nil, err
55+
}
56+
57+
// resolve expressions
58+
haystack, err = expression.ResolveAllExpressions(haystack, filepath.Dir(config.Path()), nil)
59+
if err != nil {
60+
return false, nil, err
61+
}
62+
63+
return shouldRebuild, haystack, nil
64+
}
65+
66+
func (r *runtimeResolver) FillRuntimeVariables(haystack interface{}, config config.Config, dependencies []types.Dependency) (interface{}, error) {
67+
_, out, err := r.FillRuntimeVariablesWithRebuild(haystack, config, dependencies, map[string]string{})
68+
return out, err
69+
}
70+
71+
func (r *runtimeResolver) fillVariables(haystack interface{}, config config.Config, dependencies []types.Dependency, builtImages map[string]string) (bool, interface{}, error) {
72+
switch t := haystack.(type) {
73+
case string:
74+
return r.replaceString(t, config, dependencies, builtImages)
75+
case map[interface{}]interface{}:
76+
shouldRebuild := false
77+
err := walk.Walk(t, varMatchFn, func(path, value string) (interface{}, error) {
78+
rebuild, val, err := r.replaceString(value, config, dependencies, builtImages)
79+
shouldRebuild = shouldRebuild || rebuild
80+
return val, err
81+
})
82+
return shouldRebuild, t, err
83+
}
84+
85+
return false, nil, fmt.Errorf("unrecognized haystack type: %#v", haystack)
86+
}
87+
88+
func (r *runtimeResolver) replaceString(str string, config config.Config, dependencies []types.Dependency, builtImages map[string]string) (bool, interface{}, error) {
89+
shouldRebuild := false
90+
if r.enableLegacyHelpers {
91+
rebuild, val, err := legacy.Replace(str, config, dependencies, map[string]string{})
92+
if err != nil {
93+
return false, "", err
94+
}
95+
96+
shouldRebuild = shouldRebuild || rebuild
97+
str = fmt.Sprintf("%v", val)
98+
}
99+
100+
value, err := varspkg.ParseString(str, func(v string) (interface{}, error) {
101+
rebuild, val, err := r.resolve(v, config, dependencies, builtImages)
102+
if err != nil {
103+
return "", err
104+
}
105+
106+
shouldRebuild = shouldRebuild || rebuild
107+
return val, nil
108+
})
109+
return shouldRebuild, value, err
110+
}
111+
112+
func (r *runtimeResolver) resolve(name string, config config.Config, dependencies []types.Dependency, builtImages map[string]string) (bool, interface{}, error) {
113+
name = strings.TrimSpace(name)
114+
115+
// check if in vars already
116+
v, ok := config.Variables()[name]
117+
if ok {
118+
return false, v, nil
119+
}
120+
121+
// fill the variable if not found
122+
shouldRebuild, value, err := r.fillRuntimeVariable(name, config, dependencies, builtImages)
123+
if err != nil {
124+
return false, nil, err
125+
}
126+
127+
return shouldRebuild, value, nil
128+
}
129+
130+
func (r *runtimeResolver) fillRuntimeVariable(name string, config config.Config, dependencies []types.Dependency, builtImages map[string]string) (bool, interface{}, error) {
131+
// is runtime variable
132+
if strings.HasPrefix(name, "runtime.") {
133+
return NewRuntimeVariable(name, config, dependencies, builtImages).Load()
134+
}
135+
136+
return false, nil, fmt.Errorf("cannot resolve variable %s as it is not a runtime variable and apparently wasn't resolved earlier")
137+
}

0 commit comments

Comments
 (0)