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  }