github.com/splunk/dan1-qbec@v0.7.3/internal/commands/filter.go (about) 1 /* 2 Copyright 2019 Splunk Inc. 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 commands 18 19 import ( 20 "fmt" 21 22 "github.com/spf13/cobra" 23 "github.com/splunk/qbec/internal/eval" 24 "github.com/splunk/qbec/internal/model" 25 "github.com/splunk/qbec/internal/sio" 26 ) 27 28 type filterParams struct { 29 includes []string 30 excludes []string 31 kindFilter model.Filter 32 componentFilter model.Filter 33 } 34 35 func (f filterParams) Includes(o model.K8sQbecMeta) bool { 36 if !(f.kindFilter == nil || f.kindFilter.ShouldInclude(o.GetKind())) { 37 return false 38 } 39 if !(f.componentFilter == nil || f.componentFilter.ShouldInclude(o.Component())) { 40 return false 41 } 42 return true 43 } 44 45 func addFilterParams(cmd *cobra.Command, includeKindFilters bool) func() (filterParams, error) { 46 var includes, excludes, kindIncludes, kindExcludes []string 47 48 cmd.Flags().StringArrayVarP(&includes, "component", "c", nil, "include just this component") 49 cmd.Flags().StringArrayVarP(&excludes, "exclude-component", "C", nil, "exclude this component") 50 if includeKindFilters { 51 cmd.Flags().StringArrayVarP(&kindIncludes, "kind", "k", nil, "include objects with this kind") 52 cmd.Flags().StringArrayVarP(&kindExcludes, "exclude-kind", "K", nil, "exclude objects with this kind") 53 } 54 return func() (filterParams, error) { 55 of, err := model.NewKindFilter(kindIncludes, kindExcludes) 56 if err != nil { 57 return filterParams{}, newUsageError(err.Error()) 58 } 59 cf, err := model.NewComponentFilter(includes, excludes) 60 if err != nil { 61 return filterParams{}, newUsageError(err.Error()) 62 } 63 return filterParams{ 64 includes: includes, 65 excludes: excludes, 66 kindFilter: of, 67 componentFilter: cf, 68 }, nil 69 } 70 } 71 72 // keyFunc is a function that provides a string key for an object 73 type keyFunc func(object model.K8sMeta) string 74 75 func allObjects(cfg *Config, env string) ([]model.K8sLocalObject, error) { 76 return filteredObjects(cfg, env, nil, filterParams{kindFilter: nil}) 77 } 78 79 func displayName(obj model.K8sLocalObject) string { 80 group := obj.GroupVersionKind().Group 81 if group != "" { 82 group += "/" 83 } 84 ns := obj.GetNamespace() 85 if ns != "" { 86 ns += "/" 87 } 88 return fmt.Sprintf("%s%s %s%s (component: %s)", group, obj.GetKind(), ns, obj.GetName(), obj.Component()) 89 } 90 91 func checkDuplicates(objects []model.K8sLocalObject, kf keyFunc) error { 92 if kf == nil { 93 return nil 94 } 95 objectsByKey := map[string]model.K8sLocalObject{} 96 for _, o := range objects { 97 if o.GetName() == "" { // generated name 98 continue 99 } 100 key := kf(o) 101 if prev, ok := objectsByKey[key]; ok { 102 return fmt.Errorf("duplicate objects %s and %s", displayName(prev), displayName(o)) 103 } 104 objectsByKey[key] = o 105 } 106 return nil 107 } 108 109 func filteredObjects(cfg *Config, env string, kf keyFunc, fp filterParams) ([]model.K8sLocalObject, error) { 110 components, err := cfg.App().ComponentsForEnvironment(env, fp.includes, fp.excludes) 111 if err != nil { 112 return nil, err 113 } 114 output, err := eval.Components(components, cfg.EvalContext(env)) 115 if err != nil { 116 return nil, err 117 } 118 if err := checkDuplicates(output, kf); err != nil { 119 return nil, err 120 } 121 of := fp.kindFilter 122 if of == nil || !of.HasFilters() { 123 return output, nil 124 } 125 var ret []model.K8sLocalObject 126 for _, o := range output { 127 if of.ShouldInclude(o.GetKind()) { 128 ret = append(ret, o) 129 } 130 } 131 if len(output) > 0 && len(ret) == 0 { 132 sio.Warnf("0 of %d matches for kind filter, check for typos and abbreviations\n", len(output)) 133 } 134 return ret, nil 135 }