github.com/panekj/cli@v0.0.0-20230304125325-467dd2f3797e/cli/command/formatter/volume.go (about) 1 package formatter 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 8 "github.com/docker/docker/api/types/volume" 9 units "github.com/docker/go-units" 10 ) 11 12 const ( 13 defaultVolumeQuietFormat = "{{.Name}}" 14 defaultVolumeTableFormat = "table {{.Driver}}\t{{.Name}}" 15 16 idHeader = "ID" 17 volumeNameHeader = "VOLUME NAME" 18 mountpointHeader = "MOUNTPOINT" 19 linksHeader = "LINKS" 20 groupHeader = "GROUP" 21 availabilityHeader = "AVAILABILITY" 22 statusHeader = "STATUS" 23 ) 24 25 // NewVolumeFormat returns a format for use with a volume Context 26 func NewVolumeFormat(source string, quiet bool) Format { 27 switch source { 28 case TableFormatKey: 29 if quiet { 30 return defaultVolumeQuietFormat 31 } 32 return defaultVolumeTableFormat 33 case RawFormatKey: 34 if quiet { 35 return `name: {{.Name}}` 36 } 37 return `name: {{.Name}}\ndriver: {{.Driver}}\n` 38 } 39 return Format(source) 40 } 41 42 // VolumeWrite writes formatted volumes using the Context 43 func VolumeWrite(ctx Context, volumes []*volume.Volume) error { 44 render := func(format func(subContext SubContext) error) error { 45 for _, vol := range volumes { 46 if err := format(&volumeContext{v: *vol}); err != nil { 47 return err 48 } 49 } 50 return nil 51 } 52 return ctx.Write(newVolumeContext(), render) 53 } 54 55 type volumeContext struct { 56 HeaderContext 57 v volume.Volume 58 } 59 60 func newVolumeContext() *volumeContext { 61 volumeCtx := volumeContext{} 62 volumeCtx.Header = SubHeaderContext{ 63 "ID": idHeader, 64 "Name": volumeNameHeader, 65 "Group": groupHeader, 66 "Driver": DriverHeader, 67 "Scope": ScopeHeader, 68 "Availability": availabilityHeader, 69 "Mountpoint": mountpointHeader, 70 "Labels": LabelsHeader, 71 "Links": linksHeader, 72 "Size": SizeHeader, 73 "Status": statusHeader, 74 } 75 return &volumeCtx 76 } 77 78 func (c *volumeContext) MarshalJSON() ([]byte, error) { 79 return MarshalJSON(c) 80 } 81 82 func (c *volumeContext) Name() string { 83 return c.v.Name 84 } 85 86 func (c *volumeContext) Driver() string { 87 return c.v.Driver 88 } 89 90 func (c *volumeContext) Scope() string { 91 return c.v.Scope 92 } 93 94 func (c *volumeContext) Mountpoint() string { 95 return c.v.Mountpoint 96 } 97 98 func (c *volumeContext) Labels() string { 99 if c.v.Labels == nil { 100 return "" 101 } 102 103 var joinLabels []string 104 for k, v := range c.v.Labels { 105 joinLabels = append(joinLabels, k+"="+v) 106 } 107 return strings.Join(joinLabels, ",") 108 } 109 110 func (c *volumeContext) Label(name string) string { 111 if c.v.Labels == nil { 112 return "" 113 } 114 return c.v.Labels[name] 115 } 116 117 func (c *volumeContext) Links() string { 118 if c.v.UsageData == nil { 119 return "N/A" 120 } 121 return strconv.FormatInt(c.v.UsageData.RefCount, 10) 122 } 123 124 func (c *volumeContext) Size() string { 125 if c.v.UsageData == nil { 126 return "N/A" 127 } 128 return units.HumanSize(float64(c.v.UsageData.Size)) 129 } 130 131 func (c *volumeContext) Group() string { 132 if c.v.ClusterVolume == nil { 133 return "N/A" 134 } 135 136 return c.v.ClusterVolume.Spec.Group 137 } 138 139 func (c *volumeContext) Availability() string { 140 if c.v.ClusterVolume == nil { 141 return "N/A" 142 } 143 144 return string(c.v.ClusterVolume.Spec.Availability) 145 } 146 147 func (c *volumeContext) Status() string { 148 if c.v.ClusterVolume == nil { 149 return "N/A" 150 } 151 152 if c.v.ClusterVolume.Info == nil || c.v.ClusterVolume.Info.VolumeID == "" { 153 return "pending creation" 154 } 155 156 l := len(c.v.ClusterVolume.PublishStatus) 157 switch l { 158 case 0: 159 return "created" 160 case 1: 161 return "in use (1 node)" 162 default: 163 return fmt.Sprintf("in use (%d nodes)", l) 164 } 165 }