Skip to content

Commit 33c89c9

Browse files
authored
Merge pull request #342 from justinsb/version_independent
Create abstraction layer over controller-runtime/client-go versions
2 parents f988556 + 1eff23c commit 33c89c9

File tree

19 files changed

+514
-42
lines changed

19 files changed

+514
-42
lines changed

applylib/third_party/forked/github.com/kubernetes/kubectl/pkg/cmd/apply/applyset.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ import (
2929
"k8s.io/apimachinery/pkg/runtime"
3030
"k8s.io/apimachinery/pkg/runtime/schema"
3131
utilerrors "k8s.io/apimachinery/pkg/util/errors"
32-
"k8s.io/apimachinery/pkg/util/sets"
3332
"k8s.io/client-go/dynamic"
33+
"sigs.k8s.io/kubebuilder-declarative-pattern/applylib/third_party/forked/k8s.io/apimachinery/pkg/util/sets"
3434
)
3535

3636
// Label and annotation keys from the ApplySet specification.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
Copyright 2022 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package sets
18+
19+
// Empty is public since it is used by some internal API objects for conversions between external
20+
// string arrays and internal sets, and conversion logic requires public types today.
21+
type Empty struct{}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
Copyright 2022 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package sets
18+
19+
// ordered is a constraint that permits any ordered type: any type
20+
// that supports the operators < <= >= >.
21+
// If future releases of Go add new ordered types,
22+
// this constraint will be modified to include them.
23+
type ordered interface {
24+
integer | float | ~string
25+
}
26+
27+
// integer is a constraint that permits any integer type.
28+
// If future releases of Go add new predeclared integer types,
29+
// this constraint will be modified to include them.
30+
type integer interface {
31+
signed | unsigned
32+
}
33+
34+
// float is a constraint that permits any floating-point type.
35+
// If future releases of Go add new predeclared floating-point types,
36+
// this constraint will be modified to include them.
37+
type float interface {
38+
~float32 | ~float64
39+
}
40+
41+
// signed is a constraint that permits any signed integer type.
42+
// If future releases of Go add new predeclared signed integer types,
43+
// this constraint will be modified to include them.
44+
type signed interface {
45+
~int | ~int8 | ~int16 | ~int32 | ~int64
46+
}
47+
48+
// unsigned is a constraint that permits any unsigned integer type.
49+
// If future releases of Go add new predeclared unsigned integer types,
50+
// this constraint will be modified to include them.
51+
type unsigned interface {
52+
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
53+
}
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
/*
2+
Copyright 2022 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package sets
18+
19+
import (
20+
"sort"
21+
)
22+
23+
// Set is a set of the same type elements, implemented via map[comparable]struct{} for minimal memory consumption.
24+
type Set[T comparable] map[T]Empty
25+
26+
// cast transforms specified set to generic Set[T].
27+
func cast[T comparable](s map[T]Empty) Set[T] { return s }
28+
29+
// New creates a Set from a list of values.
30+
// NOTE: type param must be explicitly instantiated if given items are empty.
31+
func New[T comparable](items ...T) Set[T] {
32+
ss := make(Set[T], len(items))
33+
ss.Insert(items...)
34+
return ss
35+
}
36+
37+
// KeySet creates a Set from a keys of a map[comparable](? extends interface{}).
38+
// If the value passed in is not actually a map, this will panic.
39+
func KeySet[T comparable, V any](theMap map[T]V) Set[T] {
40+
ret := Set[T]{}
41+
for keyValue := range theMap {
42+
ret.Insert(keyValue)
43+
}
44+
return ret
45+
}
46+
47+
// Insert adds items to the set.
48+
func (s Set[T]) Insert(items ...T) Set[T] {
49+
for _, item := range items {
50+
s[item] = Empty{}
51+
}
52+
return s
53+
}
54+
55+
func Insert[T comparable](set Set[T], items ...T) Set[T] {
56+
return set.Insert(items...)
57+
}
58+
59+
// Delete removes all items from the set.
60+
func (s Set[T]) Delete(items ...T) Set[T] {
61+
for _, item := range items {
62+
delete(s, item)
63+
}
64+
return s
65+
}
66+
67+
// Clear empties the set.
68+
// It is preferable to replace the set with a newly constructed set,
69+
// but not all callers can do that (when there are other references to the map).
70+
// In some cases the set *won't* be fully cleared, e.g. a Set[float32] containing NaN
71+
// can't be cleared because NaN can't be removed.
72+
// For sets containing items of a type that is reflexive for ==,
73+
// this is optimized to a single call to runtime.mapclear().
74+
func (s Set[T]) Clear() Set[T] {
75+
for key := range s {
76+
delete(s, key)
77+
}
78+
return s
79+
}
80+
81+
// Has returns true if and only if item is contained in the set.
82+
func (s Set[T]) Has(item T) bool {
83+
_, contained := s[item]
84+
return contained
85+
}
86+
87+
// HasAll returns true if and only if all items are contained in the set.
88+
func (s Set[T]) HasAll(items ...T) bool {
89+
for _, item := range items {
90+
if !s.Has(item) {
91+
return false
92+
}
93+
}
94+
return true
95+
}
96+
97+
// HasAny returns true if any items are contained in the set.
98+
func (s Set[T]) HasAny(items ...T) bool {
99+
for _, item := range items {
100+
if s.Has(item) {
101+
return true
102+
}
103+
}
104+
return false
105+
}
106+
107+
// Clone returns a new set which is a copy of the current set.
108+
func (s Set[T]) Clone() Set[T] {
109+
result := make(Set[T], len(s))
110+
for key := range s {
111+
result.Insert(key)
112+
}
113+
return result
114+
}
115+
116+
// Difference returns a set of objects that are not in s2.
117+
// For example:
118+
// s1 = {a1, a2, a3}
119+
// s2 = {a1, a2, a4, a5}
120+
// s1.Difference(s2) = {a3}
121+
// s2.Difference(s1) = {a4, a5}
122+
func (s1 Set[T]) Difference(s2 Set[T]) Set[T] {
123+
result := New[T]()
124+
for key := range s1 {
125+
if !s2.Has(key) {
126+
result.Insert(key)
127+
}
128+
}
129+
return result
130+
}
131+
132+
// SymmetricDifference returns a set of elements which are in either of the sets, but not in their intersection.
133+
// For example:
134+
// s1 = {a1, a2, a3}
135+
// s2 = {a1, a2, a4, a5}
136+
// s1.SymmetricDifference(s2) = {a3, a4, a5}
137+
// s2.SymmetricDifference(s1) = {a3, a4, a5}
138+
func (s1 Set[T]) SymmetricDifference(s2 Set[T]) Set[T] {
139+
return s1.Difference(s2).Union(s2.Difference(s1))
140+
}
141+
142+
// Union returns a new set which includes items in either s1 or s2.
143+
// For example:
144+
// s1 = {a1, a2}
145+
// s2 = {a3, a4}
146+
// s1.Union(s2) = {a1, a2, a3, a4}
147+
// s2.Union(s1) = {a1, a2, a3, a4}
148+
func (s1 Set[T]) Union(s2 Set[T]) Set[T] {
149+
result := s1.Clone()
150+
for key := range s2 {
151+
result.Insert(key)
152+
}
153+
return result
154+
}
155+
156+
// Intersection returns a new set which includes the item in BOTH s1 and s2
157+
// For example:
158+
// s1 = {a1, a2}
159+
// s2 = {a2, a3}
160+
// s1.Intersection(s2) = {a2}
161+
func (s1 Set[T]) Intersection(s2 Set[T]) Set[T] {
162+
var walk, other Set[T]
163+
result := New[T]()
164+
if s1.Len() < s2.Len() {
165+
walk = s1
166+
other = s2
167+
} else {
168+
walk = s2
169+
other = s1
170+
}
171+
for key := range walk {
172+
if other.Has(key) {
173+
result.Insert(key)
174+
}
175+
}
176+
return result
177+
}
178+
179+
// IsSuperset returns true if and only if s1 is a superset of s2.
180+
func (s1 Set[T]) IsSuperset(s2 Set[T]) bool {
181+
for item := range s2 {
182+
if !s1.Has(item) {
183+
return false
184+
}
185+
}
186+
return true
187+
}
188+
189+
// Equal returns true if and only if s1 is equal (as a set) to s2.
190+
// Two sets are equal if their membership is identical.
191+
// (In practice, this means same elements, order doesn't matter)
192+
func (s1 Set[T]) Equal(s2 Set[T]) bool {
193+
return len(s1) == len(s2) && s1.IsSuperset(s2)
194+
}
195+
196+
type sortableSliceOfGeneric[T ordered] []T
197+
198+
func (g sortableSliceOfGeneric[T]) Len() int { return len(g) }
199+
func (g sortableSliceOfGeneric[T]) Less(i, j int) bool { return less[T](g[i], g[j]) }
200+
func (g sortableSliceOfGeneric[T]) Swap(i, j int) { g[i], g[j] = g[j], g[i] }
201+
202+
// List returns the contents as a sorted T slice.
203+
//
204+
// This is a separate function and not a method because not all types supported
205+
// by Generic are ordered and only those can be sorted.
206+
func List[T ordered](s Set[T]) []T {
207+
res := make(sortableSliceOfGeneric[T], 0, len(s))
208+
for key := range s {
209+
res = append(res, key)
210+
}
211+
sort.Sort(res)
212+
return res
213+
}
214+
215+
// UnsortedList returns the slice with contents in random order.
216+
func (s Set[T]) UnsortedList() []T {
217+
res := make([]T, 0, len(s))
218+
for key := range s {
219+
res = append(res, key)
220+
}
221+
return res
222+
}
223+
224+
// PopAny returns a single element from the set.
225+
func (s Set[T]) PopAny() (T, bool) {
226+
for key := range s {
227+
s.Delete(key)
228+
return key, true
229+
}
230+
var zeroValue T
231+
return zeroValue, false
232+
}
233+
234+
// Len returns the size of the set.
235+
func (s Set[T]) Len() int {
236+
return len(s)
237+
}
238+
239+
func less[T ordered](lhs, rhs T) bool {
240+
return lhs < rhs
241+
}

commonclient/doc.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Package commonclient provides version-independent wrappers over controller-runtime and client-go.
2+
// This enables one codebase to work with multiple versions of controller-runtime.
3+
package commonclient

commonclient/factory_cr11.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//go:build controllerruntime_11 || controllerruntime_12 || controllerruntime_13 || controllerruntime_14
2+
3+
package commonclient
4+
5+
import (
6+
"context"
7+
8+
"k8s.io/client-go/util/workqueue"
9+
"sigs.k8s.io/controller-runtime/pkg/cache"
10+
"sigs.k8s.io/controller-runtime/pkg/client"
11+
"sigs.k8s.io/controller-runtime/pkg/event"
12+
"sigs.k8s.io/controller-runtime/pkg/handler"
13+
"sigs.k8s.io/controller-runtime/pkg/source"
14+
)
15+
16+
// SourceKind is a version-indendenent abstraction over calling source.Kind
17+
func SourceKind(cache cache.Cache, obj client.Object) source.SyncingSource {
18+
return source.NewKindWithCache(obj, cache)
19+
}
20+
21+
// WrapEventHandler is a version-indendenent abstraction over handler.EventHandler
22+
func WrapEventHandler(h EventHandler) handler.EventHandler {
23+
return &eventHandlerWithoutContext{h: h}
24+
}
25+
26+
type eventHandlerWithoutContext struct {
27+
h EventHandler
28+
}
29+
30+
func (h *eventHandlerWithoutContext) Create(ev event.CreateEvent, q workqueue.RateLimitingInterface) {
31+
h.h.Create(context.TODO(), ev, q)
32+
}
33+
func (h *eventHandlerWithoutContext) Update(ev event.UpdateEvent, q workqueue.RateLimitingInterface) {
34+
h.h.Update(context.TODO(), ev, q)
35+
}
36+
func (h *eventHandlerWithoutContext) Delete(ev event.DeleteEvent, q workqueue.RateLimitingInterface) {
37+
h.h.Delete(context.TODO(), ev, q)
38+
}
39+
func (h *eventHandlerWithoutContext) Generic(ev event.GenericEvent, q workqueue.RateLimitingInterface) {
40+
h.h.Generic(context.TODO(), ev, q)
41+
}
42+
43+
// EventHandler is the controller-runtime 0.15 version of EventHandler (with a context argument)
44+
type EventHandler interface {
45+
// Create is called in response to an create event - e.g. Pod Creation.
46+
Create(context.Context, event.CreateEvent, workqueue.RateLimitingInterface)
47+
48+
// Update is called in response to an update event - e.g. Pod Updated.
49+
Update(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface)
50+
51+
// Delete is called in response to a delete event - e.g. Pod Deleted.
52+
Delete(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface)
53+
54+
// Generic is called in response to an event of an unknown type or a synthetic event triggered as a cron or
55+
// external trigger request - e.g. reconcile Autoscaling, or a Webhook.
56+
Generic(context.Context, event.GenericEvent, workqueue.RateLimitingInterface)
57+
}

0 commit comments

Comments
 (0)