mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-14 10:30:59 +00:00
Add AnchorsAweigh option to ByteReader to toggle YAML alias/anchor expansion
This commit is contained in:
@@ -143,7 +143,7 @@ func (rf *Factory) resourcesFromRNodes(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rf *Factory) RNodesFromBytes(b []byte) (result []*yaml.RNode, err error) {
|
func (rf *Factory) RNodesFromBytes(b []byte) ([]*yaml.RNode, error) {
|
||||||
nodes, err := kio.FromBytes(b)
|
nodes, err := kio.FromBytes(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -152,9 +152,17 @@ func (rf *Factory) RNodesFromBytes(b []byte) (result []*yaml.RNode, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return rf.inlineAnyEmbeddedLists(nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inlineAnyEmbeddedLists scans the RNode slice for nodes named FooList.
|
||||||
|
// Such nodes are expected to be lists of resources, each of type Foo.
|
||||||
|
// These lists are replaced in the result by their inlined resources.
|
||||||
|
func (rf *Factory) inlineAnyEmbeddedLists(
|
||||||
|
nodes []*yaml.RNode) (result []*yaml.RNode, err error) {
|
||||||
|
var n0 *yaml.RNode
|
||||||
for len(nodes) > 0 {
|
for len(nodes) > 0 {
|
||||||
n0 := nodes[0]
|
n0, nodes = nodes[0], nodes[1:]
|
||||||
nodes = nodes[1:]
|
|
||||||
kind := n0.GetKind()
|
kind := n0.GetKind()
|
||||||
if !strings.HasSuffix(kind, "List") {
|
if !strings.HasSuffix(kind, "List") {
|
||||||
result = append(result, n0)
|
result = append(result, n0)
|
||||||
@@ -164,7 +172,7 @@ func (rf *Factory) RNodesFromBytes(b []byte) (result []*yaml.RNode, err error) {
|
|||||||
var m map[string]interface{}
|
var m map[string]interface{}
|
||||||
m, err = n0.Map()
|
m, err = n0.Map()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("trouble expanding list of %s; %w", kind, err)
|
||||||
}
|
}
|
||||||
items, ok := m["items"]
|
items, ok := m["items"]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|||||||
@@ -639,17 +639,14 @@ data:
|
|||||||
feeling: *color-used
|
feeling: *color-used
|
||||||
`),
|
`),
|
||||||
exp: expected{
|
exp: expected{
|
||||||
// TODO(#3675) : the anchor should be replaced.
|
|
||||||
// Anchors are replaced in the List above due to a different code path
|
|
||||||
// (when the list is inlined).
|
|
||||||
out: []string{`
|
out: []string{`
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
name: wildcard
|
name: wildcard
|
||||||
data:
|
data:
|
||||||
color: &color-used blue
|
color: blue
|
||||||
feeling: *color-used
|
feeling: blue
|
||||||
`},
|
`},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ func ParseAll(inputs ...string) ([]*yaml.RNode, error) {
|
|||||||
func FromBytes(bs []byte) ([]*yaml.RNode, error) {
|
func FromBytes(bs []byte) ([]*yaml.RNode, error) {
|
||||||
return (&ByteReader{
|
return (&ByteReader{
|
||||||
OmitReaderAnnotations: true,
|
OmitReaderAnnotations: true,
|
||||||
|
AnchorsAweigh: true,
|
||||||
Reader: bytes.NewBuffer(bs),
|
Reader: bytes.NewBuffer(bs),
|
||||||
}).Read()
|
}).Read()
|
||||||
}
|
}
|
||||||
@@ -152,6 +153,10 @@ type ByteReader struct {
|
|||||||
// sequence nodes into map node with key yaml.BareSeqNodeWrappingKey
|
// sequence nodes into map node with key yaml.BareSeqNodeWrappingKey
|
||||||
// note that this wrapping is different and not related to ResourceList wrapping
|
// note that this wrapping is different and not related to ResourceList wrapping
|
||||||
WrapBareSeqNode bool
|
WrapBareSeqNode bool
|
||||||
|
|
||||||
|
// AnchorsAweigh set to true attempts to replace all YAML anchor aliases
|
||||||
|
// with their definitions (anchor values) immediately after the read.
|
||||||
|
AnchorsAweigh bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Reader = &ByteReader{}
|
var _ Reader = &ByteReader{}
|
||||||
@@ -269,6 +274,13 @@ func (r *ByteReader) Read() ([]*yaml.RNode, error) {
|
|||||||
// increment the index annotation value
|
// increment the index annotation value
|
||||||
index++
|
index++
|
||||||
}
|
}
|
||||||
|
if r.AnchorsAweigh {
|
||||||
|
for _, n := range output {
|
||||||
|
if err = n.DeAnchor(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return output, nil
|
return output, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -758,7 +758,7 @@ items:
|
|||||||
metadata:
|
metadata:
|
||||||
name: deployment-b
|
name: deployment-b
|
||||||
spec:
|
spec:
|
||||||
<<: *hostAliases
|
*hostAliases
|
||||||
`),
|
`),
|
||||||
exp: expected{
|
exp: expected{
|
||||||
sOut: []string{`
|
sOut: []string{`
|
||||||
@@ -769,7 +769,7 @@ items:
|
|||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: deployment-a
|
name: deployment-a
|
||||||
spec: &hostAliases
|
spec:
|
||||||
template:
|
template:
|
||||||
spec:
|
spec:
|
||||||
hostAliases:
|
hostAliases:
|
||||||
@@ -781,7 +781,12 @@ items:
|
|||||||
metadata:
|
metadata:
|
||||||
name: deployment-b
|
name: deployment-b
|
||||||
spec:
|
spec:
|
||||||
!!merge <<: *hostAliases
|
template:
|
||||||
|
spec:
|
||||||
|
hostAliases:
|
||||||
|
- hostnames:
|
||||||
|
- a.example.com
|
||||||
|
ip: 8.8.8.8
|
||||||
`},
|
`},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -808,27 +813,21 @@ items:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This test shows the lower level (go-yaml) representation of a small doc
|
// Show the low level (go-yaml) representation of a small doc with a
|
||||||
// with an anchor. The anchor structure is there, in the sense that an
|
// YAML anchor and alias after reading it with anchor expansion on or off.
|
||||||
// alias pointer is readily available when a node's kind is an AliasNode.
|
func TestByteReader_AnchorsAweigh(t *testing.T) {
|
||||||
// I.e. the anchor mapping name -> object was noted during unmarshalling.
|
|
||||||
// However, at the time of writing github.com/go-yaml/yaml/encoder.go
|
|
||||||
// doesn't appear to have an option to perform anchor replacements when
|
|
||||||
// encoding. It emits anchor definitions and references (aliases) intact.
|
|
||||||
func TestByteReader_AnchorBehavior(t *testing.T) {
|
|
||||||
const input = `
|
const input = `
|
||||||
data:
|
data:
|
||||||
color: &color-used blue
|
color: &color-used blue
|
||||||
feeling: *color-used
|
feeling: *color-used
|
||||||
`
|
`
|
||||||
expected := strings.TrimSpace(`
|
|
||||||
data:
|
|
||||||
color: &color-used blue
|
|
||||||
feeling: *color-used
|
|
||||||
`)
|
|
||||||
var rNode *yaml.RNode
|
var rNode *yaml.RNode
|
||||||
{
|
{
|
||||||
rNodes, err := FromBytes([]byte(input))
|
rNodes, err := (&ByteReader{
|
||||||
|
OmitReaderAnnotations: true,
|
||||||
|
AnchorsAweigh: false,
|
||||||
|
Reader: bytes.NewBuffer([]byte(input)),
|
||||||
|
}).Read()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 1, len(rNodes))
|
assert.Equal(t, 1, len(rNodes))
|
||||||
rNode = rNodes[0]
|
rNode = rNodes[0]
|
||||||
@@ -857,7 +856,7 @@ data:
|
|||||||
assert.Equal(t, yaml.ScalarNode, yNodes[0].Kind)
|
assert.Equal(t, yaml.ScalarNode, yNodes[0].Kind)
|
||||||
assert.Equal(t, yaml.NodeTagString, yNodes[0].Tag)
|
assert.Equal(t, yaml.NodeTagString, yNodes[0].Tag)
|
||||||
assert.Equal(t, "color", yNodes[0].Value)
|
assert.Equal(t, "color", yNodes[0].Value)
|
||||||
assert.Equal(t, "", yNodes[0].Anchor)
|
assert.Empty(t, yNodes[0].Anchor)
|
||||||
assert.Nil(t, yNodes[0].Alias)
|
assert.Nil(t, yNodes[0].Alias)
|
||||||
|
|
||||||
assert.Equal(t, yaml.ScalarNode, yNodes[1].Kind)
|
assert.Equal(t, yaml.ScalarNode, yNodes[1].Kind)
|
||||||
@@ -869,19 +868,82 @@ data:
|
|||||||
assert.Equal(t, yaml.ScalarNode, yNodes[2].Kind)
|
assert.Equal(t, yaml.ScalarNode, yNodes[2].Kind)
|
||||||
assert.Equal(t, yaml.NodeTagString, yNodes[2].Tag)
|
assert.Equal(t, yaml.NodeTagString, yNodes[2].Tag)
|
||||||
assert.Equal(t, "feeling", yNodes[2].Value)
|
assert.Equal(t, "feeling", yNodes[2].Value)
|
||||||
assert.Equal(t, "", yNodes[2].Anchor)
|
assert.Empty(t, yNodes[2].Anchor)
|
||||||
assert.Nil(t, yNodes[2].Alias)
|
assert.Nil(t, yNodes[2].Alias)
|
||||||
|
|
||||||
assert.Equal(t, yaml.AliasNode, yNodes[3].Kind)
|
assert.Equal(t, yaml.AliasNode, yNodes[3].Kind)
|
||||||
assert.Equal(t, "", yNodes[3].Tag)
|
assert.Empty(t, yNodes[3].Tag)
|
||||||
assert.Equal(t, "color-used", yNodes[3].Value)
|
assert.Equal(t, "color-used", yNodes[3].Value)
|
||||||
assert.Equal(t, "", yNodes[3].Anchor)
|
assert.Empty(t, yNodes[3].Anchor)
|
||||||
assert.NotNil(t, yNodes[3].Alias)
|
assert.NotNil(t, yNodes[3].Alias)
|
||||||
}
|
}
|
||||||
|
|
||||||
yaml, err := rNode.String()
|
str, err := rNode.String()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, expected, strings.TrimSpace(yaml))
|
// The string version matches the input (it still has anchors and aliases).
|
||||||
|
assert.Equal(t, strings.TrimSpace(input), strings.TrimSpace(str))
|
||||||
|
|
||||||
|
// Now do same thing again, but this time set AnchorsAweigh = true.
|
||||||
|
{
|
||||||
|
rNodes, err := (&ByteReader{
|
||||||
|
OmitReaderAnnotations: true,
|
||||||
|
AnchorsAweigh: true,
|
||||||
|
Reader: bytes.NewBuffer([]byte(input)),
|
||||||
|
}).Read()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, len(rNodes))
|
||||||
|
rNode = rNodes[0]
|
||||||
|
}
|
||||||
|
// Again make assertions on the internals.
|
||||||
|
{
|
||||||
|
yNode := rNode.YNode()
|
||||||
|
|
||||||
|
assert.Equal(t, yaml.NodeTagMap, yNode.Tag)
|
||||||
|
|
||||||
|
yNodes := yNode.Content
|
||||||
|
assert.Equal(t, 2, len(yNodes))
|
||||||
|
|
||||||
|
assert.Equal(t, yaml.NodeTagString, yNodes[0].Tag)
|
||||||
|
assert.Equal(t, "data", yNodes[0].Value)
|
||||||
|
|
||||||
|
assert.Equal(t, yaml.NodeTagMap, yNodes[1].Tag)
|
||||||
|
|
||||||
|
yNodes = yNodes[1].Content
|
||||||
|
assert.Equal(t, 4, len(yNodes))
|
||||||
|
|
||||||
|
assert.Equal(t, yaml.ScalarNode, yNodes[0].Kind)
|
||||||
|
assert.Equal(t, yaml.NodeTagString, yNodes[0].Tag)
|
||||||
|
assert.Equal(t, "color", yNodes[0].Value)
|
||||||
|
assert.Empty(t, yNodes[0].Anchor)
|
||||||
|
assert.Nil(t, yNodes[0].Alias)
|
||||||
|
|
||||||
|
assert.Equal(t, yaml.ScalarNode, yNodes[1].Kind)
|
||||||
|
assert.Equal(t, yaml.NodeTagString, yNodes[1].Tag)
|
||||||
|
assert.Equal(t, "blue", yNodes[1].Value)
|
||||||
|
assert.Empty(t, yNodes[1].Anchor)
|
||||||
|
assert.Nil(t, yNodes[1].Alias)
|
||||||
|
|
||||||
|
assert.Equal(t, yaml.ScalarNode, yNodes[2].Kind)
|
||||||
|
assert.Equal(t, yaml.NodeTagString, yNodes[2].Tag)
|
||||||
|
assert.Equal(t, "feeling", yNodes[2].Value)
|
||||||
|
assert.Empty(t, yNodes[2].Anchor)
|
||||||
|
assert.Nil(t, yNodes[2].Alias)
|
||||||
|
|
||||||
|
assert.Equal(t, yaml.ScalarNode, yNodes[3].Kind)
|
||||||
|
assert.Equal(t, yaml.NodeTagString, yNodes[3].Tag)
|
||||||
|
assert.Equal(t, "blue", yNodes[3].Value)
|
||||||
|
assert.Empty(t, yNodes[3].Anchor)
|
||||||
|
assert.Nil(t, yNodes[3].Alias)
|
||||||
|
}
|
||||||
|
|
||||||
|
str, err = rNode.String()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
// This time, the alias has been replaced with the anchor definition.
|
||||||
|
assert.Equal(t, strings.TrimSpace(`
|
||||||
|
data:
|
||||||
|
color: blue
|
||||||
|
feeling: blue
|
||||||
|
`), strings.TrimSpace(str))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestByteReader_AddSeqIndentAnnotation tests if the internal.config.kubernetes.io/seqindent
|
// TestByteReader_AddSeqIndentAnnotation tests if the internal.config.kubernetes.io/seqindent
|
||||||
|
|||||||
Reference in New Issue
Block a user