Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / k8s.io / apimachinery / pkg / runtime / schema / group_version.go
1 /*
2 Copyright 2015 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 schema
18
19 import (
20         "fmt"
21         "strings"
22 )
23
24 // ParseResourceArg takes the common style of string which may be either `resource.group.com` or `resource.version.group.com`
25 // and parses it out into both possibilities.  This code takes no responsibility for knowing which representation was intended
26 // but with a knowledge of all GroupVersions, calling code can take a very good guess.  If there are only two segments, then
27 // `*GroupVersionResource` is nil.
28 // `resource.group.com` -> `group=com, version=group, resource=resource` and `group=group.com, resource=resource`
29 func ParseResourceArg(arg string) (*GroupVersionResource, GroupResource) {
30         var gvr *GroupVersionResource
31         if strings.Count(arg, ".") >= 2 {
32                 s := strings.SplitN(arg, ".", 3)
33                 gvr = &GroupVersionResource{Group: s[2], Version: s[1], Resource: s[0]}
34         }
35
36         return gvr, ParseGroupResource(arg)
37 }
38
39 // ParseKindArg takes the common style of string which may be either `Kind.group.com` or `Kind.version.group.com`
40 // and parses it out into both possibilities. This code takes no responsibility for knowing which representation was intended
41 // but with a knowledge of all GroupKinds, calling code can take a very good guess. If there are only two segments, then
42 // `*GroupVersionResource` is nil.
43 // `Kind.group.com` -> `group=com, version=group, kind=Kind` and `group=group.com, kind=Kind`
44 func ParseKindArg(arg string) (*GroupVersionKind, GroupKind) {
45         var gvk *GroupVersionKind
46         if strings.Count(arg, ".") >= 2 {
47                 s := strings.SplitN(arg, ".", 3)
48                 gvk = &GroupVersionKind{Group: s[2], Version: s[1], Kind: s[0]}
49         }
50
51         return gvk, ParseGroupKind(arg)
52 }
53
54 // GroupResource specifies a Group and a Resource, but does not force a version.  This is useful for identifying
55 // concepts during lookup stages without having partially valid types
56 type GroupResource struct {
57         Group    string
58         Resource string
59 }
60
61 func (gr GroupResource) WithVersion(version string) GroupVersionResource {
62         return GroupVersionResource{Group: gr.Group, Version: version, Resource: gr.Resource}
63 }
64
65 func (gr GroupResource) Empty() bool {
66         return len(gr.Group) == 0 && len(gr.Resource) == 0
67 }
68
69 func (gr GroupResource) String() string {
70         if len(gr.Group) == 0 {
71                 return gr.Resource
72         }
73         return gr.Resource + "." + gr.Group
74 }
75
76 func ParseGroupKind(gk string) GroupKind {
77         i := strings.Index(gk, ".")
78         if i == -1 {
79                 return GroupKind{Kind: gk}
80         }
81
82         return GroupKind{Group: gk[i+1:], Kind: gk[:i]}
83 }
84
85 // ParseGroupResource turns "resource.group" string into a GroupResource struct.  Empty strings are allowed
86 // for each field.
87 func ParseGroupResource(gr string) GroupResource {
88         if i := strings.Index(gr, "."); i >= 0 {
89                 return GroupResource{Group: gr[i+1:], Resource: gr[:i]}
90         }
91         return GroupResource{Resource: gr}
92 }
93
94 // GroupVersionResource unambiguously identifies a resource.  It doesn't anonymously include GroupVersion
95 // to avoid automatic coercion.  It doesn't use a GroupVersion to avoid custom marshalling
96 type GroupVersionResource struct {
97         Group    string
98         Version  string
99         Resource string
100 }
101
102 func (gvr GroupVersionResource) Empty() bool {
103         return len(gvr.Group) == 0 && len(gvr.Version) == 0 && len(gvr.Resource) == 0
104 }
105
106 func (gvr GroupVersionResource) GroupResource() GroupResource {
107         return GroupResource{Group: gvr.Group, Resource: gvr.Resource}
108 }
109
110 func (gvr GroupVersionResource) GroupVersion() GroupVersion {
111         return GroupVersion{Group: gvr.Group, Version: gvr.Version}
112 }
113
114 func (gvr GroupVersionResource) String() string {
115         return strings.Join([]string{gvr.Group, "/", gvr.Version, ", Resource=", gvr.Resource}, "")
116 }
117
118 // GroupKind specifies a Group and a Kind, but does not force a version.  This is useful for identifying
119 // concepts during lookup stages without having partially valid types
120 type GroupKind struct {
121         Group string
122         Kind  string
123 }
124
125 func (gk GroupKind) Empty() bool {
126         return len(gk.Group) == 0 && len(gk.Kind) == 0
127 }
128
129 func (gk GroupKind) WithVersion(version string) GroupVersionKind {
130         return GroupVersionKind{Group: gk.Group, Version: version, Kind: gk.Kind}
131 }
132
133 func (gk GroupKind) String() string {
134         if len(gk.Group) == 0 {
135                 return gk.Kind
136         }
137         return gk.Kind + "." + gk.Group
138 }
139
140 // GroupVersionKind unambiguously identifies a kind.  It doesn't anonymously include GroupVersion
141 // to avoid automatic coercion.  It doesn't use a GroupVersion to avoid custom marshalling
142 type GroupVersionKind struct {
143         Group   string
144         Version string
145         Kind    string
146 }
147
148 // Empty returns true if group, version, and kind are empty
149 func (gvk GroupVersionKind) Empty() bool {
150         return len(gvk.Group) == 0 && len(gvk.Version) == 0 && len(gvk.Kind) == 0
151 }
152
153 func (gvk GroupVersionKind) GroupKind() GroupKind {
154         return GroupKind{Group: gvk.Group, Kind: gvk.Kind}
155 }
156
157 func (gvk GroupVersionKind) GroupVersion() GroupVersion {
158         return GroupVersion{Group: gvk.Group, Version: gvk.Version}
159 }
160
161 func (gvk GroupVersionKind) String() string {
162         return gvk.Group + "/" + gvk.Version + ", Kind=" + gvk.Kind
163 }
164
165 // GroupVersion contains the "group" and the "version", which uniquely identifies the API.
166 type GroupVersion struct {
167         Group   string
168         Version string
169 }
170
171 // Empty returns true if group and version are empty
172 func (gv GroupVersion) Empty() bool {
173         return len(gv.Group) == 0 && len(gv.Version) == 0
174 }
175
176 // String puts "group" and "version" into a single "group/version" string. For the legacy v1
177 // it returns "v1".
178 func (gv GroupVersion) String() string {
179         // special case the internal apiVersion for the legacy kube types
180         if gv.Empty() {
181                 return ""
182         }
183
184         // special case of "v1" for backward compatibility
185         if len(gv.Group) == 0 && gv.Version == "v1" {
186                 return gv.Version
187         }
188         if len(gv.Group) > 0 {
189                 return gv.Group + "/" + gv.Version
190         }
191         return gv.Version
192 }
193
194 // KindForGroupVersionKinds identifies the preferred GroupVersionKind out of a list. It returns ok false
195 // if none of the options match the group. It prefers a match to group and version over just group.
196 // TODO: Move GroupVersion to a package under pkg/runtime, since it's used by scheme.
197 // TODO: Introduce an adapter type between GroupVersion and runtime.GroupVersioner, and use LegacyCodec(GroupVersion)
198 //   in fewer places.
199 func (gv GroupVersion) KindForGroupVersionKinds(kinds []GroupVersionKind) (target GroupVersionKind, ok bool) {
200         for _, gvk := range kinds {
201                 if gvk.Group == gv.Group && gvk.Version == gv.Version {
202                         return gvk, true
203                 }
204         }
205         for _, gvk := range kinds {
206                 if gvk.Group == gv.Group {
207                         return gv.WithKind(gvk.Kind), true
208                 }
209         }
210         return GroupVersionKind{}, false
211 }
212
213 // ParseGroupVersion turns "group/version" string into a GroupVersion struct. It reports error
214 // if it cannot parse the string.
215 func ParseGroupVersion(gv string) (GroupVersion, error) {
216         // this can be the internal version for the legacy kube types
217         // TODO once we've cleared the last uses as strings, this special case should be removed.
218         if (len(gv) == 0) || (gv == "/") {
219                 return GroupVersion{}, nil
220         }
221
222         switch strings.Count(gv, "/") {
223         case 0:
224                 return GroupVersion{"", gv}, nil
225         case 1:
226                 i := strings.Index(gv, "/")
227                 return GroupVersion{gv[:i], gv[i+1:]}, nil
228         default:
229                 return GroupVersion{}, fmt.Errorf("unexpected GroupVersion string: %v", gv)
230         }
231 }
232
233 // WithKind creates a GroupVersionKind based on the method receiver's GroupVersion and the passed Kind.
234 func (gv GroupVersion) WithKind(kind string) GroupVersionKind {
235         return GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: kind}
236 }
237
238 // WithResource creates a GroupVersionResource based on the method receiver's GroupVersion and the passed Resource.
239 func (gv GroupVersion) WithResource(resource string) GroupVersionResource {
240         return GroupVersionResource{Group: gv.Group, Version: gv.Version, Resource: resource}
241 }
242
243 // GroupVersions can be used to represent a set of desired group versions.
244 // TODO: Move GroupVersions to a package under pkg/runtime, since it's used by scheme.
245 // TODO: Introduce an adapter type between GroupVersions and runtime.GroupVersioner, and use LegacyCodec(GroupVersion)
246 //   in fewer places.
247 type GroupVersions []GroupVersion
248
249 // KindForGroupVersionKinds identifies the preferred GroupVersionKind out of a list. It returns ok false
250 // if none of the options match the group.
251 func (gvs GroupVersions) KindForGroupVersionKinds(kinds []GroupVersionKind) (GroupVersionKind, bool) {
252         var targets []GroupVersionKind
253         for _, gv := range gvs {
254                 target, ok := gv.KindForGroupVersionKinds(kinds)
255                 if !ok {
256                         continue
257                 }
258                 targets = append(targets, target)
259         }
260         if len(targets) == 1 {
261                 return targets[0], true
262         }
263         if len(targets) > 1 {
264                 return bestMatch(kinds, targets), true
265         }
266         return GroupVersionKind{}, false
267 }
268
269 // bestMatch tries to pick best matching GroupVersionKind and falls back to the first
270 // found if no exact match exists.
271 func bestMatch(kinds []GroupVersionKind, targets []GroupVersionKind) GroupVersionKind {
272         for _, gvk := range targets {
273                 for _, k := range kinds {
274                         if k == gvk {
275                                 return k
276                         }
277                 }
278         }
279         return targets[0]
280 }
281
282 // ToAPIVersionAndKind is a convenience method for satisfying runtime.Object on types that
283 // do not use TypeMeta.
284 func (gvk GroupVersionKind) ToAPIVersionAndKind() (string, string) {
285         if gvk.Empty() {
286                 return "", ""
287         }
288         return gvk.GroupVersion().String(), gvk.Kind
289 }
290
291 // FromAPIVersionAndKind returns a GVK representing the provided fields for types that
292 // do not use TypeMeta. This method exists to support test types and legacy serializations
293 // that have a distinct group and kind.
294 // TODO: further reduce usage of this method.
295 func FromAPIVersionAndKind(apiVersion, kind string) GroupVersionKind {
296         if gv, err := ParseGroupVersion(apiVersion); err == nil {
297                 return GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: kind}
298         }
299         return GroupVersionKind{Kind: kind}
300 }