github.com/docker/libcompose@v0.4.1-0.20210616120443-2a046c0bdbf2/yaml/volume.go (about)

     1  package yaml
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"sort"
     7  	"strings"
     8  )
     9  
    10  // Volumes represents a list of service volumes in compose file.
    11  // It has several representation, hence this specific struct.
    12  type Volumes struct {
    13  	Volumes []*Volume
    14  }
    15  
    16  // Volume represent a service volume
    17  type Volume struct {
    18  	Source      string `yaml:"-"`
    19  	Destination string `yaml:"-"`
    20  	AccessMode  string `yaml:"-"`
    21  }
    22  
    23  // Generate a hash string to detect service volume config changes
    24  func (v *Volumes) HashString() string {
    25  	if v == nil {
    26  		return ""
    27  	}
    28  	result := []string{}
    29  	for _, vol := range v.Volumes {
    30  		result = append(result, vol.String())
    31  	}
    32  	sort.Strings(result)
    33  	return strings.Join(result, ",")
    34  }
    35  
    36  // String implements the Stringer interface.
    37  func (v *Volume) String() string {
    38  	var paths []string
    39  	if v.Source != "" {
    40  		paths = []string{v.Source, v.Destination}
    41  	} else {
    42  		paths = []string{v.Destination}
    43  	}
    44  	if v.AccessMode != "" {
    45  		paths = append(paths, v.AccessMode)
    46  	}
    47  	return strings.Join(paths, ":")
    48  }
    49  
    50  // MarshalYAML implements the Marshaller interface.
    51  func (v Volumes) MarshalYAML() (interface{}, error) {
    52  	vs := []string{}
    53  	for _, volume := range v.Volumes {
    54  		vs = append(vs, volume.String())
    55  	}
    56  	return vs, nil
    57  }
    58  
    59  // UnmarshalYAML implements the Unmarshaller interface.
    60  func (v *Volumes) UnmarshalYAML(unmarshal func(interface{}) error) error {
    61  	var sliceType []interface{}
    62  	if err := unmarshal(&sliceType); err == nil {
    63  		v.Volumes = []*Volume{}
    64  		for _, volume := range sliceType {
    65  			name, ok := volume.(string)
    66  			if !ok {
    67  				return fmt.Errorf("Cannot unmarshal '%v' to type %T into a string value", name, name)
    68  			}
    69  			elts := strings.SplitN(name, ":", 3)
    70  			var vol *Volume
    71  			switch {
    72  			case len(elts) == 1:
    73  				vol = &Volume{
    74  					Destination: elts[0],
    75  				}
    76  			case len(elts) == 2:
    77  				vol = &Volume{
    78  					Source:      elts[0],
    79  					Destination: elts[1],
    80  				}
    81  			case len(elts) == 3:
    82  				vol = &Volume{
    83  					Source:      elts[0],
    84  					Destination: elts[1],
    85  					AccessMode:  elts[2],
    86  				}
    87  			default:
    88  				// FIXME
    89  				return fmt.Errorf("")
    90  			}
    91  			v.Volumes = append(v.Volumes, vol)
    92  		}
    93  		return nil
    94  	}
    95  
    96  	return errors.New("Failed to unmarshal Volumes")
    97  }