Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Left-side overlay positions #341

Merged
merged 8 commits into from
Apr 14, 2021
Merged
Show file tree
Hide file tree
Changes from 6 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
1 change: 1 addition & 0 deletions pkg/yamlmeta/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

type Node interface {
GetPosition() *filepos.Position
SetPosition(*filepos.Position)

GetValues() []interface{} // ie children
SetValue(interface{}) error
Expand Down
7 changes: 7 additions & 0 deletions pkg/yamlmeta/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ func (a *Array) GetPosition() *filepos.Position { return a.Position }
func (ai *ArrayItem) GetPosition() *filepos.Position { return ai.Position }
func (s *Scalar) GetPosition() *filepos.Position { return s.Position }

func (ds *DocumentSet) SetPosition(position *filepos.Position) { ds.Position = position }
func (d *Document) SetPosition(position *filepos.Position) { d.Position = position }
func (m *Map) SetPosition(position *filepos.Position) { m.Position = position }
func (mi *MapItem) SetPosition(position *filepos.Position) { mi.Position = position }
func (a *Array) SetPosition(position *filepos.Position) { a.Position = position }
func (ai *ArrayItem) SetPosition(position *filepos.Position) { ai.Position = position }

func (ds *DocumentSet) ValueTypeAsString() string { return "documentSet" }
func (d *Document) ValueTypeAsString() string { return typeToString(d.Value) }
func (m *Map) ValueTypeAsString() string { return "map" }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#@ load("@ytt:overlay", "overlay")
#@ load("@ytt:template", "template")

#@ def/end test1_left():
---
clients:
- needsSecret: true

#@ def/end test1_right():
#@overlay/match by=overlay.all
---
clients:
#@overlay/match by=overlay.subset({"needsSecret": True})
- needsSecret: false

#@ def/end test2_left():
---
clients:
- needsSecret: true

#@ def/end test2_right():
#@overlay/match by=overlay.all
---
clients:
#@overlay/match by=overlay.subset({"needsSecret": True})
#@overlay/replace
- secret: foo

#@ def/end test3_left():
---
clients:
- needsSecret: true

#@ def return_something():
#@ return "something"
#@ end

#@ def/end test3_right():
#@overlay/match by=overlay.all
---
clients:
#@overlay/match by=overlay.subset({"needsSecret": True})
- #@ return_something()

---
test1
--- #@ template.replace(overlay.apply(test1_left(), test1_right()))
---
test2
--- #@ template.replace(overlay.apply(test2_left(), test2_right()))
---
test3
--- #@ template.replace(overlay.apply(test3_left(), test3_right()))
---

+++

OUTPUT POSITION: stdin:45 | [doc]
| test1
stdin:5 | [doc]
stdin:6 | clients:
stdin:7 | [0]
stdin:14 | needsSecret: false
stdin:48 | [doc]
| test2
stdin:17 | [doc]
stdin:18 | clients:
stdin:27 | [0]
stdin:27 | secret: foo
stdin:51 | [doc]
| test3
stdin:30 | [doc]
stdin:31 | clients:
stdin:43 | [0] something
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#@ load("@ytt:overlay", "overlay")
#@ load("@ytt:template", "template")

#@ def/end test1_left():
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-ingress1
annotations:
key: 1

#@ def/end test1_right():
#@overlay/match by=overlay.all
---
metadata:
annotations:
key: 2

#@ def/end test2_left():
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-ingress1
annotations:
key: 1

#@ def/end test2_right():
#@overlay/match by=overlay.all
---
metadata:
#@overlay/replace
annotations:
keya: 2

#@ def/end test3_left():
---
foo: 1

#@ def return_something():
#@ return "something"
#@ end

#@ def/end test3_right():
#@overlay/match by=overlay.all
---
foo: #@ return_something()

---
test1
--- #@ template.replace(overlay.apply(test1_left(), test1_right()))
---
test2
--- #@ template.replace(overlay.apply(test2_left(), test2_right()))
---
test3
--- #@ template.replace(overlay.apply(test3_left(), test3_right()))
---

+++

OUTPUT POSITION: stdin:50 | [doc]
| test1
stdin:5 | [doc]
stdin:6 | apiVersion: extensions/v1beta1
stdin:7 | kind: Ingress
stdin:8 | metadata:
stdin:9 | name: example-ingress1
stdin:10 | annotations:
stdin:18 | key: 2
stdin:53 | [doc]
| test2
stdin:21 | [doc]
stdin:22 | apiVersion: extensions/v1beta1
stdin:23 | kind: Ingress
stdin:24 | metadata:
stdin:25 | name: example-ingress1
stdin:34 | annotations:
stdin:35 | keya: 2
stdin:56 | [doc]
| test3
stdin:38 | [doc]
stdin:48 | foo: something
62 changes: 47 additions & 15 deletions pkg/yamltemplate/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package yamltemplate_test

import (
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
Expand Down Expand Up @@ -67,10 +68,10 @@ func TestYAMLTemplate(t *testing.T) {
if len(pieces) != 2 {
t.Fatalf("expected file %s to include +++ separator", filePath)
}

resultStr, testErr := evalTemplate(t, pieces[0])
expectedStr := pieces[1]

result, testErr := evalTemplate(t, pieces[0])

if strings.HasPrefix(expectedStr, "ERR: ") {
if testErr == nil {
err = fmt.Errorf("expected eval error, but did not receive it")
Expand All @@ -79,9 +80,25 @@ func TestYAMLTemplate(t *testing.T) {
resultStr = regexp.MustCompile("__ytt_tpl\\d+_").ReplaceAllString(resultStr, "__ytt_tplXXX_")
err = expectEquals(t, resultStr, strings.ReplaceAll(strings.TrimPrefix(expectedStr, "ERR: "), "__YTT_VERSION__", version.Version))
}
} else if strings.HasPrefix(expectedStr, "OUTPUT POSITION:") {
if testErr == nil {
resultStr, strErr := asFilePositionsStr(result)
if strErr != nil {
err = strErr
} else {
err = expectEquals(t, resultStr, strings.ReplaceAll(strings.TrimPrefix(expectedStr, "OUTPUT POSITION:"), "__YTT_VERSION__", version.Version))
}
} else {
err = testErr.TestErr()
}
} else {
if testErr == nil {
err = expectEquals(t, resultStr, expectedStr)
resultStr, strErr := asString(result)
if strErr != nil {
err = strErr
} else {
err = expectEquals(t, resultStr, expectedStr)
}
} else {
err = testErr.TestErr()
}
Expand All @@ -108,6 +125,27 @@ func TestYAMLTemplate(t *testing.T) {
}
}

func asFilePositionsStr(result interface{ AsBytes() ([]byte, error) }) (string, error) {
printerFunc := func(w io.Writer) yamlmeta.DocumentPrinter {
return yamlmeta.WrappedFilePositionPrinter{yamlmeta.NewFilePositionPrinter(w)}
}
docSet := result.(*yamlmeta.DocumentSet)
combinedDocBytes, err := docSet.AsBytesWithPrinter(printerFunc)
if err != nil {
return "", fmt.Errorf("expected result docSet to be printable: %v", err)
}
return string(combinedDocBytes), nil
}

func asString(result interface{ AsBytes() ([]byte, error) }) (string, error) {
resultBytes, err := result.AsBytes()
if err != nil {
return "", fmt.Errorf("marshal error: %v", err)
}

return string(resultBytes), nil
}

type testErr struct {
realErr error // error returned to the user
testErr error // error wrapped with helpful test context
Expand All @@ -116,15 +154,15 @@ type testErr struct {
func (e testErr) UserErr() error { return e.realErr }
func (e testErr) TestErr() error { return e.testErr }

func evalTemplate(t *testing.T, data string) (string, *testErr) {
func evalTemplate(t *testing.T, data string) (interface{ AsBytes() ([]byte, error) }, *testErr) {
docSet, err := yamlmeta.NewDocumentSetFromBytes([]byte(data), yamlmeta.DocSetOpts{AssociatedName: "stdin"})
if err != nil {
return "", &testErr{err, fmt.Errorf("unmarshal error: %v", err)}
return nil, &testErr{err, fmt.Errorf("unmarshal error: %v", err)}
}

compiledTemplate, err := yamltemplate.NewTemplate("stdin", yamltemplate.TemplateOpts{}).Compile(docSet)
if err != nil {
return "", &testErr{err, fmt.Errorf("build error: %v", err)}
return nil, &testErr{err, fmt.Errorf("build error: %v", err)}
}

if showTemplateCode == "t" {
Expand All @@ -139,25 +177,19 @@ func evalTemplate(t *testing.T, data string) (string, *testErr) {

_, newVal, err := compiledTemplate.Eval(thread, loader)
if err != nil {
return "", &testErr{err, fmt.Errorf("eval error: %v\ncode:\n%s", err, compiledTemplate.DebugCodeAsString())}
return nil, &testErr{err, fmt.Errorf("eval error: %v\ncode:\n%s", err, compiledTemplate.DebugCodeAsString())}
}

typedNewVal, ok := newVal.(interface{ AsBytes() ([]byte, error) })
if !ok {
return "", &testErr{err, fmt.Errorf("expected eval result to be marshalable")}
return nil, &testErr{err, fmt.Errorf("expected eval result to be marshalable")}
}

if showTemplateCode == "t" {
fmt.Printf("### result ast:\n")
typedNewVal.(*yamlmeta.DocumentSet).Print(os.Stdout)
}

resultBytes, err := typedNewVal.AsBytes()
if err != nil {
return "", &testErr{err, fmt.Errorf("marshal error: %v", err)}
}

return string(resultBytes), nil
return typedNewVal, nil
}

func expectEquals(t *testing.T, resultStr, expectedStr string) error {
Expand Down
8 changes: 5 additions & 3 deletions pkg/yttlibrary/overlay/array.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,11 @@ func (o Op) mergeArrayItem(
}
}
if replace {
leftArray.Items[leftIdx].Value = newItem.Value
//todo: should we be setting the position elsewhere?
leftArray.Items[leftIdx].Position = newItem.Position
err := leftArray.Items[leftIdx].SetValue(newItem.Value)
if err != nil {
return err
}
leftArray.Items[leftIdx].SetPosition(newItem.Position)
}
}

Expand Down
8 changes: 5 additions & 3 deletions pkg/yttlibrary/overlay/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@ func (o Op) mergeMapItem(leftMap *yamlmeta.Map, newItem *yamlmeta.MapItem,
}
}
if replace {
leftMap.Items[leftIdx].Value = newItem.Value
//todo: should we be setting the position elsewhere? What about annotations?
leftMap.Items[leftIdx].Position = newItem.Position
err := leftMap.Items[leftIdx].SetValue(newItem.Value)
if err != nil {
return err
}
leftMap.Items[leftIdx].SetPosition(newItem.Position)
}
}

Expand Down