github.com/artisanhe/tools@v1.0.1-0.20210607022958-19a8fef2eb04/docker/volume.go (about) 1 package docker 2 3 import ( 4 "fmt" 5 "path" 6 "strings" 7 ) 8 9 type VolumeAccessMode string 10 11 const ( 12 VolumeAccessModeReadWrite = "rw" 13 VolumeAccessModeReadOnly = "ro" 14 ) 15 16 type Volume struct { 17 Name string 18 LocalPath string 19 MountPath string 20 AccessMode VolumeAccessMode 21 } 22 23 func (v Volume) ReadOnly() bool { 24 return v.AccessMode == VolumeAccessModeReadOnly 25 } 26 27 func (v Volume) IsMountFromStorage() bool { 28 return v.Name != "" 29 } 30 31 func (v Volume) IsMountFromLocal() bool { 32 return v.LocalPath != "" 33 } 34 35 func (v Volume) IsProvider() bool { 36 return v.LocalPath == "" && v.Name == "" 37 } 38 39 func isRel(p string) bool { 40 return len(p) > 0 && p[0] == '.' 41 } 42 43 func ParseVolumeString(s string) (*Volume, error) { 44 v := Volume{} 45 values := strings.Split(s, ":") 46 47 if values[0] == "container" { 48 values = values[1:] 49 } 50 51 accessMode := strings.ToLower(values[len(values)-1]) 52 if accessMode == VolumeAccessModeReadOnly || accessMode == VolumeAccessModeReadWrite { 53 v.AccessMode = VolumeAccessMode(accessMode) 54 values = values[0 : len(values)-1] 55 } 56 57 mouthPath := values[len(values)-1] 58 59 if path.IsAbs(mouthPath) { 60 v.MountPath = mouthPath 61 if len(values) == 2 { 62 if path.IsAbs(values[0]) || isRel(values[0]) { 63 v.LocalPath = values[0] 64 } else { 65 v.Name = values[0] 66 } 67 } 68 } else { 69 v.Name = values[0] 70 } 71 72 if v.AccessMode == "" { 73 if !v.IsProvider() { 74 v.AccessMode = VolumeAccessModeReadWrite 75 } 76 } 77 78 return &v, nil 79 } 80 81 func (v Volume) String() string { 82 if v.AccessMode == "" { 83 v.AccessMode = VolumeAccessModeReadWrite 84 } 85 86 if v.IsMountFromLocal() { 87 return fmt.Sprintf("%s:%s:%s", v.LocalPath, v.MountPath, v.AccessMode) 88 } 89 if v.IsMountFromStorage() { 90 if v.MountPath != "" { 91 return fmt.Sprintf("%s:%s:%s", v.Name, v.MountPath, v.AccessMode) 92 } 93 return fmt.Sprintf("%s:%s", v.Name, v.AccessMode) 94 } 95 return v.MountPath 96 } 97 98 func (v Volume) MarshalYAML() (interface{}, error) { 99 return v.String(), nil 100 } 101 102 func (v *Volume) UnmarshalYAML(unmarshal func(interface{}) error) error { 103 var s string 104 err := unmarshal(&s) 105 if err == nil { 106 volume, err := ParseVolumeString(s) 107 if err != nil { 108 return err 109 } 110 *v = *volume 111 } 112 return nil 113 }