1/*
2Copyright 2018 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package config
18
19import (
20	"strings"
21
22	"sigs.k8s.io/kustomize/pkg/gvk"
23)
24
25// NameBackReferences is an association between a gvk.GVK and a list
26// of FieldSpec instances that could refer to it.
27//
28// It is used to handle name changes, and can be thought of as a
29// a contact list.  If you change your own contact info (name,
30// phone number, etc.), you must tell your contacts or they won't
31// know about the change.
32//
33// For example, ConfigMaps can be used by Pods and everything that
34// contains a Pod; Deployment, Job, StatefulSet, etc.  To change
35// the name of a ConfigMap instance from 'alice' to 'bob', one
36// must visit all objects that could refer to the ConfigMap, see if
37// they mention 'alice', and if so, change the reference to 'bob'.
38//
39// The NameBackReferences instance to aid in this could look like
40//   {
41//     kind: ConfigMap
42//     version: v1
43//     FieldSpecs:
44//     - kind: Pod
45//       version: v1
46//       path: spec/volumes/configMap/name
47//     - kind: Deployment
48//       path: spec/template/spec/volumes/configMap/name
49//     - kind: Job
50//       path: spec/template/spec/volumes/configMap/name
51//       (etc.)
52//   }
53type NameBackReferences struct {
54	gvk.Gvk    `json:",inline,omitempty" yaml:",inline,omitempty"`
55	FieldSpecs fsSlice `json:"FieldSpecs,omitempty" yaml:"FieldSpecs,omitempty"`
56}
57
58func (n NameBackReferences) String() string {
59	var r []string
60	for _, f := range n.FieldSpecs {
61		r = append(r, f.String())
62	}
63	return n.Gvk.String() + ":  (\n" +
64		strings.Join(r, "\n") + "\n)"
65}
66
67type nbrSlice []NameBackReferences
68
69func (s nbrSlice) Len() int      { return len(s) }
70func (s nbrSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
71func (s nbrSlice) Less(i, j int) bool {
72	return s[i].Gvk.IsLessThan(s[j].Gvk)
73}
74
75func (s nbrSlice) mergeAll(o nbrSlice) (result nbrSlice, err error) {
76	result = s
77	for _, r := range o {
78		result, err = result.mergeOne(r)
79		if err != nil {
80			return nil, err
81		}
82	}
83	return result, nil
84}
85
86func (s nbrSlice) mergeOne(other NameBackReferences) (nbrSlice, error) {
87	var result nbrSlice
88	var err error
89	found := false
90	for _, c := range s {
91		if c.Gvk.Equals(other.Gvk) {
92			c.FieldSpecs, err = c.FieldSpecs.mergeAll(other.FieldSpecs)
93			if err != nil {
94				return nil, err
95			}
96			found = true
97		}
98		result = append(result, c)
99	}
100
101	if !found {
102		result = append(result, other)
103	}
104	return result, nil
105}
106