Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions e2e/tests/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,28 @@ var _ = DevSpaceDescribe("config", func() {
framework.ExpectEqual(config.Config().Dev["sync-0"].Terminal.Command, "test")
})

ginkgo.It("should patch correctly", func() {
tempDir, err := framework.CopyToTempDir("tests/config/testdata/profile-patches")
framework.ExpectNoError(err)
defer framework.CleanupTempDir(initialDir, tempDir)

// reload it
config, _, err := framework.LoadConfigWithOptions(f, kubeClient.Client(), "var-patch.yaml", &loader.ConfigOptions{})
framework.ExpectNoError(err)

framework.ExpectEqual(len(config.Config().Images), 1)
framework.ExpectEqual(config.Config().Images["test"].Image, "sample")
framework.ExpectEqual(config.Config().Images["test"].Kaniko.Labels, map[string]string{"app": "sample"})

// with profile
config, _, err = framework.LoadConfigWithOptions(f, kubeClient.Client(), "var-patch.yaml", &loader.ConfigOptions{Profiles: []string{"alt"}})
framework.ExpectNoError(err)

framework.ExpectEqual(len(config.Config().Images), 1)
framework.ExpectEqual(config.Config().Images["test"].Image, "sample-alt")
framework.ExpectEqual(config.Config().Images["test"].Kaniko.Labels, map[string]string{"app": "sample-alt"})
})

ginkgo.It("should resolve runtime environment variables correctly", func() {
tempDir, err := framework.CopyToTempDir("tests/config/testdata/runtime-variables")
framework.ExpectNoError(err)
Expand Down Expand Up @@ -1737,8 +1759,7 @@ var _ = DevSpaceDescribe("config", func() {
framework.ExpectNoError(err)

// check if variables were loaded correctly
fmt.Println(config.Variables())
framework.ExpectEqual(len(config.Variables()), 4+len(variable.AlwaysResolvePredefinedVars))
framework.ExpectEqual(len(config.Variables()), 3+len(variable.AlwaysResolvePredefinedVars))
framework.ExpectEqual(len(config.LocalCache().ListVars()), 1)
test1, _ := config.LocalCache().GetVar("TEST_1")
framework.ExpectEqual(test1, "test")
Expand Down Expand Up @@ -1767,7 +1788,7 @@ var _ = DevSpaceDescribe("config", func() {
framework.ExpectNoError(err)

// config
framework.ExpectEqual(len(config.Variables()), 4+len(variable.AlwaysResolvePredefinedVars))
framework.ExpectEqual(len(config.Variables()), 3+len(variable.AlwaysResolvePredefinedVars))
framework.ExpectEqual(len(config.LocalCache().ListVars()), 2)
notUsed, _ = config.LocalCache().GetVar("NOT_USED2")
framework.ExpectEqual(notUsed, "test")
Expand All @@ -1792,7 +1813,7 @@ var _ = DevSpaceDescribe("config", func() {
framework.ExpectNoError(err)

// check if default config variables were loaded correctly
framework.ExpectEqual(len(config.Variables()), 3+len(variable.AlwaysResolvePredefinedVars))
framework.ExpectEqual(len(config.Variables()), 2+len(variable.AlwaysResolvePredefinedVars))
framework.ExpectEqual(len(config.LocalCache().ListVars()), 1)
value, _ := config.LocalCache().GetVar("NAME")
framework.ExpectEqual(value, "default")
Expand All @@ -1808,7 +1829,7 @@ var _ = DevSpaceDescribe("config", func() {
framework.ExpectNoError(err)

// check if custom config variables were loaded correctly
framework.ExpectEqual(len(customConfig.Variables()), 3+len(variable.AlwaysResolvePredefinedVars))
framework.ExpectEqual(len(customConfig.Variables()), 2+len(variable.AlwaysResolvePredefinedVars))
framework.ExpectEqual(len(customConfig.LocalCache().ListVars()), 1)
value, _ = customConfig.LocalCache().GetVar("NAME")
framework.ExpectEqual(value, "custom")
Expand Down
26 changes: 26 additions & 0 deletions e2e/tests/config/testdata/profile-patches/var-patch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
version: v1beta11

vars:
- name: LABELS
value:
app: sample
- name: BIN
value: sample

images:
test:
image: ${BIN}
build:
kaniko:
labels: ${LABELS}

profiles:
- name: alt
patches:
- op: replace
path: vars.name=LABELS.value
value:
app: sample-alt
- op: replace
path: vars.name=BIN.value
value: sample-alt
16 changes: 12 additions & 4 deletions pkg/devspace/config/loader/variable/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func (r *resolver) replaceString(ctx context.Context, str string) (interface{},
})
}

func (r *resolver) FindVariables(haystack interface{}) ([]*latest.Variable, error) {
func (r *resolver) findVariablesInclude(haystack interface{}, include []*regexp.Regexp) ([]*latest.Variable, error) {
// find out what vars are really used
varsUsed := map[string]bool{}
switch t := haystack.(type) {
Expand All @@ -124,7 +124,11 @@ func (r *resolver) FindVariables(haystack interface{}) ([]*latest.Variable, erro
return "", nil
})
case map[string]interface{}:
err := walk.Walk(t, varMatchFn, func(_, value string) (interface{}, error) {
err := walk.Walk(t, varMatchFn, func(path, value string) (interface{}, error) {
if expression.ExcludedPath(path, nil, include) {
return value, nil
}

_, _ = varspkg.ParseString(value, func(v string) (interface{}, error) {
varsUsed[v] = true
return "", nil
Expand All @@ -139,7 +143,7 @@ func (r *resolver) FindVariables(haystack interface{}) ([]*latest.Variable, erro

// add always resolve variables
for _, v := range r.vars {
if v.AlwaysResolve || v.Value != nil {
if v.AlwaysResolve {
varsUsed[v.Name] = true
}
}
Expand All @@ -154,6 +158,10 @@ func (r *resolver) FindVariables(haystack interface{}) ([]*latest.Variable, erro
return r.orderVariables(varsUsed)
}

func (r *resolver) FindVariables(haystack interface{}) ([]*latest.Variable, error) {
return r.findVariablesInclude(haystack, nil)
}

func (r *resolver) orderVariables(vars map[string]bool) ([]*latest.Variable, error) {
root := graph.NewNode("root", nil)
g := graph.NewGraphOf(root, "variable")
Expand Down Expand Up @@ -295,7 +303,7 @@ func (r *resolver) FillVariables(ctx context.Context, haystack interface{}) (int
}

func (r *resolver) findAndFillVariables(ctx context.Context, haystack interface{}, exclude, include []*regexp.Regexp) (interface{}, error) {
varsUsed, err := r.FindVariables(haystack)
varsUsed, err := r.findVariablesInclude(haystack, include)
if err != nil {
return nil, err
}
Expand Down
56 changes: 54 additions & 2 deletions pkg/devspace/services/sync/controller.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sync

import (
"bufio"
"bytes"
"context"
"fmt"
Expand All @@ -26,7 +27,6 @@ import (
"github.com/loft-sh/devspace/pkg/devspace/sync"
logpkg "github.com/loft-sh/devspace/pkg/util/log"
"github.com/loft-sh/devspace/pkg/util/scanner"
"github.com/moby/buildkit/frontend/dockerfile/dockerignore"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
)
Expand Down Expand Up @@ -541,14 +541,66 @@ func parseExcludeFile(path string) ([]string, error) {
}
defer reader.Close()

paths, err := dockerignore.ReadAll(reader)
paths, err := readAll(reader)
if err != nil {
return nil, errors.Wrap(err, "read exclude file")
}

return paths, nil
}

// Taken from Dockerignore
// ReadAll reads a .dockerignore file and returns the list of file patterns
// to ignore. Note this will trim whitespace from each line as well
// as use GO's "clean" func to get the shortest/cleanest path for each.
func readAll(reader io.Reader) ([]string, error) {
if reader == nil {
return nil, nil
}

scanner := bufio.NewScanner(reader)
var excludes []string
currentLine := 0

utf8bom := []byte{0xEF, 0xBB, 0xBF}
for scanner.Scan() {
scannedBytes := scanner.Bytes()
// We trim UTF8 BOM
if currentLine == 0 {
scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom)
}
pattern := string(scannedBytes)
currentLine++
// Lines starting with # (comments) are ignored before processing
if strings.HasPrefix(pattern, "#") {
continue
}
pattern = strings.TrimSpace(pattern)
if pattern == "" {
continue
}
// normalize absolute paths to paths relative to the context
// (taking care of '!' prefix)
invert := pattern[0] == '!'
if invert {
pattern = strings.TrimSpace(pattern[1:])
}
if len(pattern) > 0 {
pattern = filepath.Clean(pattern)
pattern = filepath.ToSlash(pattern)
}
if invert {
pattern = "!" + pattern
}

excludes = append(excludes, pattern)
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("error reading .dockerignore: %v", err)
}
return excludes, nil
}

func StartStream(ctx context.Context, client kubectl.Client, pod *v1.Pod, container string, command []string, reader io.Reader, stdoutWriter io.Writer, buffer bool, log logpkg.Logger) error {
stderrBuffer := &bytes.Buffer{}
stderrReader, stderrWriter := io.Pipe()
Expand Down