github.com/damirazo/docker@v1.9.0/pkg/parsers/filters/parse.go (about) 1 // Package filters provides helper function to parse and handle command line 2 // filter, used for example in docker ps or docker images commands. 3 package filters 4 5 import ( 6 "encoding/json" 7 "errors" 8 "regexp" 9 "strings" 10 ) 11 12 // Args stores filter arguments as map key:{array of values}. 13 // It contains a aggregation of the list of arguments (which are in the form 14 // of -f 'key=value') based on the key, and store values for the same key 15 // in an slice. 16 // e.g given -f 'label=label1=1' -f 'label=label2=2' -f 'image.name=ubuntu' 17 // the args will be {'label': {'label1=1','label2=2'}, 'image.name', {'ubuntu'}} 18 type Args map[string][]string 19 20 // ParseFlag parses the argument to the filter flag. Like 21 // 22 // `docker ps -f 'created=today' -f 'image.name=ubuntu*'` 23 // 24 // If prev map is provided, then it is appended to, and returned. By default a new 25 // map is created. 26 func ParseFlag(arg string, prev Args) (Args, error) { 27 filters := prev 28 if prev == nil { 29 filters = Args{} 30 } 31 if len(arg) == 0 { 32 return filters, nil 33 } 34 35 if !strings.Contains(arg, "=") { 36 return filters, ErrBadFormat 37 } 38 39 f := strings.SplitN(arg, "=", 2) 40 name := strings.ToLower(strings.TrimSpace(f[0])) 41 value := strings.TrimSpace(f[1]) 42 filters[name] = append(filters[name], value) 43 44 return filters, nil 45 } 46 47 // ErrBadFormat is an error returned in case of bad format for a filter. 48 var ErrBadFormat = errors.New("bad format of filter (expected name=value)") 49 50 // ToParam packs the Args into an string for easy transport from client to server. 51 func ToParam(a Args) (string, error) { 52 // this way we don't URL encode {}, just empty space 53 if len(a) == 0 { 54 return "", nil 55 } 56 57 buf, err := json.Marshal(a) 58 if err != nil { 59 return "", err 60 } 61 return string(buf), nil 62 } 63 64 // FromParam unpacks the filter Args. 65 func FromParam(p string) (Args, error) { 66 args := Args{} 67 if len(p) == 0 { 68 return args, nil 69 } 70 if err := json.NewDecoder(strings.NewReader(p)).Decode(&args); err != nil { 71 return nil, err 72 } 73 return args, nil 74 } 75 76 // MatchKVList returns true if the values for the specified field maches the ones 77 // from the sources. 78 // e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}}, 79 // field is 'label' and sources are {'label':{'label1=1','label2=2','label3=3'}} 80 // it returns true. 81 func (filters Args) MatchKVList(field string, sources map[string]string) bool { 82 fieldValues := filters[field] 83 84 //do not filter if there is no filter set or cannot determine filter 85 if len(fieldValues) == 0 { 86 return true 87 } 88 89 if sources == nil || len(sources) == 0 { 90 return false 91 } 92 93 outer: 94 for _, name2match := range fieldValues { 95 testKV := strings.SplitN(name2match, "=", 2) 96 97 for k, v := range sources { 98 if len(testKV) == 1 { 99 if k == testKV[0] { 100 continue outer 101 } 102 } else if k == testKV[0] && v == testKV[1] { 103 continue outer 104 } 105 } 106 107 return false 108 } 109 110 return true 111 } 112 113 // Match returns true if the values for the specified field matches the source string 114 // e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}}, 115 // field is 'image.name' and source is 'ubuntu' 116 // it returns true. 117 func (filters Args) Match(field, source string) bool { 118 fieldValues := filters[field] 119 120 //do not filter if there is no filter set or cannot determine filter 121 if len(fieldValues) == 0 { 122 return true 123 } 124 for _, name2match := range fieldValues { 125 match, err := regexp.MatchString(name2match, source) 126 if err != nil { 127 continue 128 } 129 if match { 130 return true 131 } 132 } 133 return false 134 }