File: merge.go

package info (click to toggle)
golang-k8s-sigs-kustomize-kyaml 0.20.1%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,180 kB
  • sloc: makefile: 220; sh: 68
file content (86 lines) | stat: -rw-r--r-- 2,264 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

// Package merge contains libraries for merging Resources and Patches
package filters

import (
	"sigs.k8s.io/kustomize/kyaml/kio"
	"sigs.k8s.io/kustomize/kyaml/yaml"
	"sigs.k8s.io/kustomize/kyaml/yaml/merge2"
)

// MergeFilter merges Resources with the Group/Version/Kind/Namespace/Name together using
// a 2-way merge strategy.
//
// - Fields set to null in the source will be cleared from the destination
// - Fields with matching keys will be merged recursively
// - Lists with an associative key (e.g. name) will have their elements merged using the key
// - List without an associative key will have the dest list replaced by the source list
type MergeFilter struct {
	Reverse bool
}

var _ kio.Filter = MergeFilter{}

type mergeKey struct {
	apiVersion string
	kind       string
	namespace  string
	name       string
}

// MergeFilter implements kio.Filter by merging Resources with the same G/V/K/NS/N
func (c MergeFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
	// invert the merge precedence
	if c.Reverse {
		for i, j := 0, len(input)-1; i < j; i, j = i+1, j-1 {
			input[i], input[j] = input[j], input[i]
		}
	}

	// index the Resources by G/V/K/NS/N
	index := map[mergeKey][]*yaml.RNode{}
	// retain the original ordering
	var order []mergeKey
	for i := range input {
		meta, err := input[i].GetMeta()
		if err != nil {
			return nil, err
		}
		key := mergeKey{
			apiVersion: meta.APIVersion,
			kind:       meta.Kind,
			namespace:  meta.Namespace,
			name:       meta.Name,
		}
		if _, found := index[key]; !found {
			order = append(order, key)
		}
		index[key] = append(index[key], input[i])
	}

	// merge each of the G/V/K/NS/N lists
	var output []*yaml.RNode
	var err error
	for _, k := range order {
		var merged *yaml.RNode
		resources := index[k]
		for i := range resources {
			patch := resources[i]
			if merged == nil {
				// first resources, don't merge it
				merged = resources[i]
			} else {
				merged, err = merge2.Merge(patch, merged, yaml.MergeOptions{
					ListIncreaseDirection: yaml.MergeOptionsListPrepend,
				})
				if err != nil {
					return nil, err
				}
			}
		}
		output = append(output, merged)
	}
	return output, nil
}