github.com/jk-he/cni@v0.8.1/pkg/types/args.go (about) 1 // Copyright 2015 CNI authors 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 types 16 17 import ( 18 "encoding" 19 "fmt" 20 "reflect" 21 "strings" 22 ) 23 24 // UnmarshallableBool typedef for builtin bool 25 // because builtin type's methods can't be declared 26 type UnmarshallableBool bool 27 28 // UnmarshalText implements the encoding.TextUnmarshaler interface. 29 // Returns boolean true if the string is "1" or "[Tt]rue" 30 // Returns boolean false if the string is "0" or "[Ff]alse" 31 func (b *UnmarshallableBool) UnmarshalText(data []byte) error { 32 s := strings.ToLower(string(data)) 33 switch s { 34 case "1", "true": 35 *b = true 36 case "0", "false": 37 *b = false 38 default: 39 return fmt.Errorf("boolean unmarshal error: invalid input %s", s) 40 } 41 return nil 42 } 43 44 // UnmarshallableString typedef for builtin string 45 type UnmarshallableString string 46 47 // UnmarshalText implements the encoding.TextUnmarshaler interface. 48 // Returns the string 49 func (s *UnmarshallableString) UnmarshalText(data []byte) error { 50 *s = UnmarshallableString(data) 51 return nil 52 } 53 54 // CommonArgs contains the IgnoreUnknown argument 55 // and must be embedded by all Arg structs 56 type CommonArgs struct { 57 IgnoreUnknown UnmarshallableBool `json:"ignoreunknown,omitempty"` 58 } 59 60 // GetKeyField is a helper function to receive Values 61 // Values that represent a pointer to a struct 62 func GetKeyField(keyString string, v reflect.Value) reflect.Value { 63 return v.Elem().FieldByName(keyString) 64 } 65 66 // UnmarshalableArgsError is used to indicate error unmarshalling args 67 // from the args-string in the form "K=V;K2=V2;..." 68 type UnmarshalableArgsError struct { 69 error 70 } 71 72 // LoadArgs parses args from a string in the form "K=V;K2=V2;..." 73 func LoadArgs(args string, container interface{}) error { 74 if args == "" { 75 return nil 76 } 77 78 containerValue := reflect.ValueOf(container) 79 80 pairs := strings.Split(args, ";") 81 unknownArgs := []string{} 82 for _, pair := range pairs { 83 kv := strings.Split(pair, "=") 84 if len(kv) != 2 { 85 return fmt.Errorf("ARGS: invalid pair %q", pair) 86 } 87 keyString := kv[0] 88 valueString := kv[1] 89 keyField := GetKeyField(keyString, containerValue) 90 if !keyField.IsValid() { 91 unknownArgs = append(unknownArgs, pair) 92 continue 93 } 94 keyFieldIface := keyField.Addr().Interface() 95 u, ok := keyFieldIface.(encoding.TextUnmarshaler) 96 if !ok { 97 return UnmarshalableArgsError{fmt.Errorf( 98 "ARGS: cannot unmarshal into field '%s' - type '%s' does not implement encoding.TextUnmarshaler", 99 keyString, reflect.TypeOf(keyFieldIface))} 100 } 101 err := u.UnmarshalText([]byte(valueString)) 102 if err != nil { 103 return fmt.Errorf("ARGS: error parsing value of pair %q: %v)", pair, err) 104 } 105 } 106 107 isIgnoreUnknown := GetKeyField("IgnoreUnknown", containerValue).Bool() 108 if len(unknownArgs) > 0 && !isIgnoreUnknown { 109 return fmt.Errorf("ARGS: unknown args %q", unknownArgs) 110 } 111 return nil 112 }