github.phpd.cn/cilium/cilium@v1.6.12/pkg/labels/array.go (about) 1 // Copyright 2016-2017 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package labels 16 17 import ( 18 "sort" 19 "strings" 20 ) 21 22 // LabelArray is an array of labels forming a set 23 type LabelArray []Label 24 25 // Sort is an internal utility to return all LabelArrays in sorted 26 // order, when the source material may be unsorted. 'ls' is sorted 27 // in-place, but also returns the sorted array for convenience. 28 func (ls LabelArray) Sort() LabelArray { 29 sort.Slice(ls, func(i, j int) bool { 30 return ls[i].Key < ls[j].Key 31 }) 32 return ls 33 } 34 35 // ParseLabelArray parses a list of labels and returns a LabelArray 36 func ParseLabelArray(labels ...string) LabelArray { 37 array := make(LabelArray, len(labels)) 38 for i := range labels { 39 array[i] = ParseLabel(labels[i]) 40 } 41 return array.Sort() 42 } 43 44 // ParseSelectLabelArray parses a list of select labels and returns a LabelArray 45 func ParseSelectLabelArray(labels ...string) LabelArray { 46 array := make(LabelArray, len(labels)) 47 for i := range labels { 48 array[i] = ParseSelectLabel(labels[i]) 49 } 50 return array.Sort() 51 } 52 53 // ParseLabelArrayFromArray converts an array of strings as labels and returns a LabelArray 54 func ParseLabelArrayFromArray(base []string) LabelArray { 55 array := make(LabelArray, len(base)) 56 for i := range base { 57 array[i] = ParseLabel(base[i]) 58 } 59 return array.Sort() 60 } 61 62 // NewLabelArrayFromSortedList returns labels based on the output of SortedList() 63 // Trailing ';' will result in an empty key that must be filtered out. 64 func NewLabelArrayFromSortedList(list string) LabelArray { 65 base := strings.Split(list, ";") 66 array := make(LabelArray, 0, len(base)) 67 for _, v := range base { 68 if lbl := ParseLabel(v); lbl.Key != "" { 69 array = append(array, lbl) 70 } 71 } 72 return array 73 } 74 75 // ParseSelectLabelArrayFromArray converts an array of strings as select labels and returns a LabelArray 76 func ParseSelectLabelArrayFromArray(base []string) LabelArray { 77 array := make(LabelArray, len(base)) 78 for i := range base { 79 array[i] = ParseSelectLabel(base[i]) 80 } 81 return array.Sort() 82 } 83 84 // Labels returns the LabelArray as Labels 85 func (ls LabelArray) Labels() Labels { 86 lbls := Labels{} 87 for _, l := range ls { 88 lbls[l.Key] = l 89 } 90 return lbls 91 } 92 93 // Contains returns true if all ls contains all the labels in needed. If 94 // needed contains no labels, Contains() will always return true 95 func (ls LabelArray) Contains(needed LabelArray) bool { 96 nextLabel: 97 for i := range needed { 98 for l := range ls { 99 if needed[i].matches(&ls[l]) { 100 continue nextLabel 101 } 102 } 103 104 return false 105 } 106 107 return true 108 } 109 110 // Lacks is identical to Contains but returns all missing labels 111 func (ls LabelArray) Lacks(needed LabelArray) LabelArray { 112 missing := LabelArray{} 113 nextLabel: 114 for i := range needed { 115 for l := range ls { 116 if needed[i].matches(&ls[l]) { 117 continue nextLabel 118 } 119 } 120 121 missing = append(missing, needed[i]) 122 } 123 124 return missing 125 } 126 127 // Has returns whether the provided key exists. 128 // Implementation of the k8s.io/apimachinery/pkg/labels.Labels interface. 129 func (ls LabelArray) Has(key string) bool { 130 // The key is submitted in the form of `source.key=value` 131 keyLabel := parseSelectLabel(key, '.') 132 if keyLabel.IsAnySource() { 133 for l := range ls { 134 if ls[l].Key == keyLabel.Key { 135 return true 136 } 137 } 138 } else { 139 for _, lsl := range ls { 140 // Note that if '=value' is part of 'key' it is ignored here 141 if lsl.Source == keyLabel.Source && lsl.Key == keyLabel.Key { 142 return true 143 } 144 } 145 } 146 return false 147 } 148 149 // Get returns the value for the provided key. 150 // Implementation of the k8s.io/apimachinery/pkg/labels.Labels interface. 151 func (ls LabelArray) Get(key string) string { 152 keyLabel := parseSelectLabel(key, '.') 153 if keyLabel.IsAnySource() { 154 for l := range ls { 155 if ls[l].Key == keyLabel.Key { 156 return ls[l].Value 157 } 158 } 159 } else { 160 for _, lsl := range ls { 161 if lsl.Source == keyLabel.Source && lsl.Key == keyLabel.Key { 162 return lsl.Value 163 } 164 } 165 } 166 return "" 167 } 168 169 // DeepCopy returns a deep copy of the labels. 170 func (ls LabelArray) DeepCopy() LabelArray { 171 if ls == nil { 172 return nil 173 } 174 175 o := make(LabelArray, len(ls)) 176 copy(o, ls) 177 return o 178 } 179 180 // GetModel returns the LabelArray as a string array with fully-qualified labels. 181 // The output is parseable by ParseLabelArrayFromArray 182 func (ls LabelArray) GetModel() []string { 183 res := []string{} 184 for l := range ls { 185 res = append(res, ls[l].String()) 186 } 187 return res 188 } 189 190 func (ls LabelArray) String() string { 191 res := "[" 192 for l := range ls { 193 if l > 0 { 194 res += " " 195 } 196 res += ls[l].String() 197 } 198 res += "]" 199 return res 200 } 201 202 // StringMap converts LabelArray into map[string]string 203 // Note: The source is included in the keys with a ':' separator. 204 // Note: LabelArray does not deduplicate entries, as it is an array. It is 205 // possible for the output to contain fewer entries when the source and key are 206 // repeated in a LabelArray, as that is the key of the output. This scenario is 207 // not expected. 208 func (ls LabelArray) StringMap() map[string]string { 209 o := map[string]string{} 210 for _, v := range ls { 211 o[v.Source+":"+v.Key] = v.Value 212 } 213 return o 214 } 215 216 // Same returns true if the label arrays are the same, i.e., have the same labels in the same order. 217 func (ls LabelArray) Same(b LabelArray) bool { 218 if len(ls) != len(b) { 219 return false 220 } 221 for l := range ls { 222 if !ls[l].Equals(&b[l]) { 223 return false 224 } 225 } 226 return true 227 }