github.com/flatt-online-training/libcompose@v0.4.0/yaml/types_yaml.go (about)

     1  package yaml
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"github.com/docker/docker/api/types/strslice"
    10  	"github.com/docker/go-units"
    11  )
    12  
    13  // StringorInt represents a string or an integer.
    14  type StringorInt int64
    15  
    16  // UnmarshalYAML implements the Unmarshaller interface.
    17  func (s *StringorInt) UnmarshalYAML(unmarshal func(interface{}) error) error {
    18  	var intType int64
    19  	if err := unmarshal(&intType); err == nil {
    20  		*s = StringorInt(intType)
    21  		return nil
    22  	}
    23  
    24  	var stringType string
    25  	if err := unmarshal(&stringType); err == nil {
    26  		intType, err := strconv.ParseInt(stringType, 10, 64)
    27  
    28  		if err != nil {
    29  			return err
    30  		}
    31  		*s = StringorInt(intType)
    32  		return nil
    33  	}
    34  
    35  	return errors.New("Failed to unmarshal StringorInt")
    36  }
    37  
    38  // MemStringorInt represents a string or an integer
    39  // the String supports notations like 10m for then Megabyte of memory
    40  type MemStringorInt int64
    41  
    42  // UnmarshalYAML implements the Unmarshaller interface.
    43  func (s *MemStringorInt) UnmarshalYAML(unmarshal func(interface{}) error) error {
    44  	var intType int64
    45  	if err := unmarshal(&intType); err == nil {
    46  		*s = MemStringorInt(intType)
    47  		return nil
    48  	}
    49  
    50  	var stringType string
    51  	if err := unmarshal(&stringType); err == nil {
    52  		intType, err := units.RAMInBytes(stringType)
    53  
    54  		if err != nil {
    55  			return err
    56  		}
    57  		*s = MemStringorInt(intType)
    58  		return nil
    59  	}
    60  
    61  	return errors.New("Failed to unmarshal MemStringorInt")
    62  }
    63  
    64  // Stringorslice represents
    65  // Using engine-api Strslice and augment it with YAML marshalling stuff. a string or an array of strings.
    66  type Stringorslice strslice.StrSlice
    67  
    68  // UnmarshalYAML implements the Unmarshaller interface.
    69  func (s *Stringorslice) UnmarshalYAML(unmarshal func(interface{}) error) error {
    70  	var stringType string
    71  	if err := unmarshal(&stringType); err == nil {
    72  		*s = []string{stringType}
    73  		return nil
    74  	}
    75  
    76  	var sliceType []interface{}
    77  	if err := unmarshal(&sliceType); err == nil {
    78  		parts, err := toStrings(sliceType)
    79  		if err != nil {
    80  			return err
    81  		}
    82  		*s = parts
    83  		return nil
    84  	}
    85  
    86  	return errors.New("Failed to unmarshal Stringorslice")
    87  }
    88  
    89  // SliceorMap represents a slice or a map of strings.
    90  type SliceorMap map[string]string
    91  
    92  // UnmarshalYAML implements the Unmarshaller interface.
    93  func (s *SliceorMap) UnmarshalYAML(unmarshal func(interface{}) error) error {
    94  
    95  	var sliceType []interface{}
    96  	if err := unmarshal(&sliceType); err == nil {
    97  		parts := map[string]string{}
    98  		for _, s := range sliceType {
    99  			if str, ok := s.(string); ok {
   100  				str := strings.TrimSpace(str)
   101  				keyValueSlice := strings.SplitN(str, "=", 2)
   102  
   103  				key := keyValueSlice[0]
   104  				val := ""
   105  				if len(keyValueSlice) == 2 {
   106  					val = keyValueSlice[1]
   107  				}
   108  				parts[key] = val
   109  			} else {
   110  				return fmt.Errorf("Cannot unmarshal '%v' of type %T into a string value", s, s)
   111  			}
   112  		}
   113  		*s = parts
   114  		return nil
   115  	}
   116  
   117  	var mapType map[interface{}]interface{}
   118  	if err := unmarshal(&mapType); err == nil {
   119  		parts := map[string]string{}
   120  		for k, v := range mapType {
   121  			if sk, ok := k.(string); ok {
   122  				if sv, ok := v.(string); ok {
   123  					parts[sk] = sv
   124  				} else {
   125  					return fmt.Errorf("Cannot unmarshal '%v' of type %T into a string value", v, v)
   126  				}
   127  			} else {
   128  				return fmt.Errorf("Cannot unmarshal '%v' of type %T into a string value", k, k)
   129  			}
   130  		}
   131  		*s = parts
   132  		return nil
   133  	}
   134  
   135  	return errors.New("Failed to unmarshal SliceorMap")
   136  }
   137  
   138  // MaporEqualSlice represents a slice of strings that gets unmarshal from a
   139  // YAML map into 'key=value' string.
   140  type MaporEqualSlice []string
   141  
   142  // UnmarshalYAML implements the Unmarshaller interface.
   143  func (s *MaporEqualSlice) UnmarshalYAML(unmarshal func(interface{}) error) error {
   144  	parts, err := unmarshalToStringOrSepMapParts(unmarshal, "=")
   145  	if err != nil {
   146  		return err
   147  	}
   148  	*s = parts
   149  	return nil
   150  }
   151  
   152  // ToMap returns the list of string as a map splitting using = the key=value
   153  func (s *MaporEqualSlice) ToMap() map[string]string {
   154  	return toMap(*s, "=")
   155  }
   156  
   157  // MaporColonSlice represents a slice of strings that gets unmarshal from a
   158  // YAML map into 'key:value' string.
   159  type MaporColonSlice []string
   160  
   161  // UnmarshalYAML implements the Unmarshaller interface.
   162  func (s *MaporColonSlice) UnmarshalYAML(unmarshal func(interface{}) error) error {
   163  	parts, err := unmarshalToStringOrSepMapParts(unmarshal, ":")
   164  	if err != nil {
   165  		return err
   166  	}
   167  	*s = parts
   168  	return nil
   169  }
   170  
   171  // ToMap returns the list of string as a map splitting using = the key=value
   172  func (s *MaporColonSlice) ToMap() map[string]string {
   173  	return toMap(*s, ":")
   174  }
   175  
   176  // MaporSpaceSlice represents a slice of strings that gets unmarshal from a
   177  // YAML map into 'key value' string.
   178  type MaporSpaceSlice []string
   179  
   180  // UnmarshalYAML implements the Unmarshaller interface.
   181  func (s *MaporSpaceSlice) UnmarshalYAML(unmarshal func(interface{}) error) error {
   182  	parts, err := unmarshalToStringOrSepMapParts(unmarshal, " ")
   183  	if err != nil {
   184  		return err
   185  	}
   186  	*s = parts
   187  	return nil
   188  }
   189  
   190  // ToMap returns the list of string as a map splitting using = the key=value
   191  func (s *MaporSpaceSlice) ToMap() map[string]string {
   192  	return toMap(*s, " ")
   193  }
   194  
   195  func unmarshalToStringOrSepMapParts(unmarshal func(interface{}) error, key string) ([]string, error) {
   196  	var sliceType []interface{}
   197  	if err := unmarshal(&sliceType); err == nil {
   198  		return toStrings(sliceType)
   199  	}
   200  	var mapType map[interface{}]interface{}
   201  	if err := unmarshal(&mapType); err == nil {
   202  		return toSepMapParts(mapType, key)
   203  	}
   204  	return nil, errors.New("Failed to unmarshal MaporSlice")
   205  }
   206  
   207  func toSepMapParts(value map[interface{}]interface{}, sep string) ([]string, error) {
   208  	if len(value) == 0 {
   209  		return nil, nil
   210  	}
   211  	parts := make([]string, 0, len(value))
   212  	for k, v := range value {
   213  		if sk, ok := k.(string); ok {
   214  			if sv, ok := v.(string); ok {
   215  				parts = append(parts, sk+sep+sv)
   216  			} else if sv, ok := v.(int); ok {
   217  				parts = append(parts, sk+sep+strconv.Itoa(sv))
   218  			} else if sv, ok := v.(int64); ok {
   219  				parts = append(parts, sk+sep+strconv.FormatInt(sv, 10))
   220  			} else if v == nil {
   221  				parts = append(parts, sk)
   222  			} else {
   223  				return nil, fmt.Errorf("Cannot unmarshal '%v' of type %T into a string value", v, v)
   224  			}
   225  		} else {
   226  			return nil, fmt.Errorf("Cannot unmarshal '%v' of type %T into a string value", k, k)
   227  		}
   228  	}
   229  	return parts, nil
   230  }
   231  
   232  func toStrings(s []interface{}) ([]string, error) {
   233  	if len(s) == 0 {
   234  		return nil, nil
   235  	}
   236  	r := make([]string, len(s))
   237  	for k, v := range s {
   238  		if sv, ok := v.(string); ok {
   239  			r[k] = sv
   240  		} else {
   241  			return nil, fmt.Errorf("Cannot unmarshal '%v' of type %T into a string value", v, v)
   242  		}
   243  	}
   244  	return r, nil
   245  }
   246  
   247  func toMap(s []string, sep string) map[string]string {
   248  	m := map[string]string{}
   249  	for _, v := range s {
   250  		values := strings.Split(v, sep)
   251  		m[values[0]] = values[1]
   252  	}
   253  	return m
   254  }