github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/k8s.io/kubernetes/pkg/fields/selector.go (about) 1 /* 2 Copyright 2015 The Kubernetes Authors All rights reserved. 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 fields 18 19 import ( 20 "fmt" 21 "sort" 22 "strings" 23 ) 24 25 // Selector represents a field selector. 26 type Selector interface { 27 // Matches returns true if this selector matches the given set of fields. 28 Matches(Fields) bool 29 30 // Empty returns true if this selector does not restrict the selection space. 31 Empty() bool 32 33 // RequiresExactMatch allows a caller to introspect whether a given selector 34 // requires a single specific field to be set, and if so returns the value it 35 // requires. 36 RequiresExactMatch(field string) (value string, found bool) 37 38 // Transform returns a new copy of the selector after TransformFunc has been 39 // applied to the entire selector, or an error if fn returns an error. 40 Transform(fn TransformFunc) (Selector, error) 41 42 // String returns a human readable string that represents this selector. 43 String() string 44 } 45 46 // Everything returns a selector that matches all fields. 47 func Everything() Selector { 48 return andTerm{} 49 } 50 51 type hasTerm struct { 52 field, value string 53 } 54 55 func (t *hasTerm) Matches(ls Fields) bool { 56 return ls.Get(t.field) == t.value 57 } 58 59 func (t *hasTerm) Empty() bool { 60 return false 61 } 62 63 func (t *hasTerm) RequiresExactMatch(field string) (value string, found bool) { 64 if t.field == field { 65 return t.value, true 66 } 67 return "", false 68 } 69 70 func (t *hasTerm) Transform(fn TransformFunc) (Selector, error) { 71 field, value, err := fn(t.field, t.value) 72 if err != nil { 73 return nil, err 74 } 75 return &hasTerm{field, value}, nil 76 } 77 78 func (t *hasTerm) String() string { 79 return fmt.Sprintf("%v=%v", t.field, t.value) 80 } 81 82 type notHasTerm struct { 83 field, value string 84 } 85 86 func (t *notHasTerm) Matches(ls Fields) bool { 87 return ls.Get(t.field) != t.value 88 } 89 90 func (t *notHasTerm) Empty() bool { 91 return false 92 } 93 94 func (t *notHasTerm) RequiresExactMatch(field string) (value string, found bool) { 95 return "", false 96 } 97 98 func (t *notHasTerm) Transform(fn TransformFunc) (Selector, error) { 99 field, value, err := fn(t.field, t.value) 100 if err != nil { 101 return nil, err 102 } 103 return ¬HasTerm{field, value}, nil 104 } 105 106 func (t *notHasTerm) String() string { 107 return fmt.Sprintf("%v!=%v", t.field, t.value) 108 } 109 110 type andTerm []Selector 111 112 func (t andTerm) Matches(ls Fields) bool { 113 for _, q := range t { 114 if !q.Matches(ls) { 115 return false 116 } 117 } 118 return true 119 } 120 121 func (t andTerm) Empty() bool { 122 if t == nil { 123 return true 124 } 125 if len([]Selector(t)) == 0 { 126 return true 127 } 128 for i := range t { 129 if !t[i].Empty() { 130 return false 131 } 132 } 133 return true 134 } 135 136 func (t andTerm) RequiresExactMatch(field string) (string, bool) { 137 if t == nil || len([]Selector(t)) == 0 { 138 return "", false 139 } 140 for i := range t { 141 if value, found := t[i].RequiresExactMatch(field); found { 142 return value, found 143 } 144 } 145 return "", false 146 } 147 148 func (t andTerm) Transform(fn TransformFunc) (Selector, error) { 149 next := make([]Selector, len([]Selector(t))) 150 for i, s := range []Selector(t) { 151 n, err := s.Transform(fn) 152 if err != nil { 153 return nil, err 154 } 155 next[i] = n 156 } 157 return andTerm(next), nil 158 } 159 160 func (t andTerm) String() string { 161 var terms []string 162 for _, q := range t { 163 terms = append(terms, q.String()) 164 } 165 return strings.Join(terms, ",") 166 } 167 168 // SelectorFromSet returns a Selector which will match exactly the given Set. A 169 // nil Set is considered equivalent to Everything(). 170 func SelectorFromSet(ls Set) Selector { 171 if ls == nil { 172 return Everything() 173 } 174 items := make([]Selector, 0, len(ls)) 175 for field, value := range ls { 176 items = append(items, &hasTerm{field: field, value: value}) 177 } 178 if len(items) == 1 { 179 return items[0] 180 } 181 return andTerm(items) 182 } 183 184 // ParseSelector takes a string representing a selector and returns an 185 // object suitable for matching, or an error. 186 func ParseSelector(selector string) (Selector, error) { 187 return parseSelector(selector, 188 func(lhs, rhs string) (newLhs, newRhs string, err error) { 189 return lhs, rhs, nil 190 }) 191 } 192 193 // Parses the selector and runs them through the given TransformFunc. 194 func ParseAndTransformSelector(selector string, fn TransformFunc) (Selector, error) { 195 return parseSelector(selector, fn) 196 } 197 198 // Function to transform selectors. 199 type TransformFunc func(field, value string) (newField, newValue string, err error) 200 201 func try(selectorPiece, op string) (lhs, rhs string, ok bool) { 202 pieces := strings.Split(selectorPiece, op) 203 if len(pieces) == 2 { 204 return pieces[0], pieces[1], true 205 } 206 return "", "", false 207 } 208 209 func parseSelector(selector string, fn TransformFunc) (Selector, error) { 210 parts := strings.Split(selector, ",") 211 sort.StringSlice(parts).Sort() 212 var items []Selector 213 for _, part := range parts { 214 if part == "" { 215 continue 216 } 217 if lhs, rhs, ok := try(part, "!="); ok { 218 items = append(items, ¬HasTerm{field: lhs, value: rhs}) 219 } else if lhs, rhs, ok := try(part, "=="); ok { 220 items = append(items, &hasTerm{field: lhs, value: rhs}) 221 } else if lhs, rhs, ok := try(part, "="); ok { 222 items = append(items, &hasTerm{field: lhs, value: rhs}) 223 } else { 224 return nil, fmt.Errorf("invalid selector: '%s'; can't understand '%s'", selector, part) 225 } 226 } 227 if len(items) == 1 { 228 return items[0].Transform(fn) 229 } 230 return andTerm(items).Transform(fn) 231 } 232 233 // OneTermEqualSelector returns an object that matches objects where one field/field equals one value. 234 // Cannot return an error. 235 func OneTermEqualSelector(k, v string) Selector { 236 return &hasTerm{field: k, value: v} 237 }