github.com/sld880311/docker@v0.0.0-20200524143708-d5593973a475/cli/command/formatter/container.go (about) 1 package formatter 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 "time" 8 9 "github.com/docker/docker/api" 10 "github.com/docker/docker/api/types" 11 "github.com/docker/docker/pkg/stringid" 12 "github.com/docker/docker/pkg/stringutils" 13 units "github.com/docker/go-units" 14 ) 15 16 const ( 17 defaultContainerTableFormat = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.RunningFor}} ago\t{{.Status}}\t{{.Ports}}\t{{.Names}}" 18 19 containerIDHeader = "CONTAINER ID" 20 namesHeader = "NAMES" 21 commandHeader = "COMMAND" 22 runningForHeader = "CREATED" 23 statusHeader = "STATUS" 24 portsHeader = "PORTS" 25 mountsHeader = "MOUNTS" 26 localVolumes = "LOCAL VOLUMES" 27 networksHeader = "NETWORKS" 28 ) 29 30 // NewContainerFormat returns a Format for rendering using a Context 31 func NewContainerFormat(source string, quiet bool, size bool) Format { 32 switch source { 33 case TableFormatKey: 34 if quiet { 35 return defaultQuietFormat 36 } 37 format := defaultContainerTableFormat 38 if size { 39 format += `\t{{.Size}}` 40 } 41 return Format(format) 42 case RawFormatKey: 43 if quiet { 44 return `container_id: {{.ID}}` 45 } 46 format := `container_id: {{.ID}} 47 image: {{.Image}} 48 command: {{.Command}} 49 created_at: {{.CreatedAt}} 50 status: {{- pad .Status 1 0}} 51 names: {{.Names}} 52 labels: {{- pad .Labels 1 0}} 53 ports: {{- pad .Ports 1 0}} 54 ` 55 if size { 56 format += `size: {{.Size}}\n` 57 } 58 return Format(format) 59 } 60 return Format(source) 61 } 62 63 // ContainerWrite renders the context for a list of containers 64 func ContainerWrite(ctx Context, containers []types.Container) error { 65 render := func(format func(subContext subContext) error) error { 66 for _, container := range containers { 67 err := format(&containerContext{trunc: ctx.Trunc, c: container}) 68 if err != nil { 69 return err 70 } 71 } 72 return nil 73 } 74 return ctx.Write(&containerContext{}, render) 75 } 76 77 type containerContext struct { 78 HeaderContext 79 trunc bool 80 c types.Container 81 } 82 83 func (c *containerContext) MarshalJSON() ([]byte, error) { 84 return marshalJSON(c) 85 } 86 87 func (c *containerContext) ID() string { 88 c.AddHeader(containerIDHeader) 89 if c.trunc { 90 return stringid.TruncateID(c.c.ID) 91 } 92 return c.c.ID 93 } 94 95 func (c *containerContext) Names() string { 96 c.AddHeader(namesHeader) 97 names := stripNamePrefix(c.c.Names) 98 if c.trunc { 99 for _, name := range names { 100 if len(strings.Split(name, "/")) == 1 { 101 names = []string{name} 102 break 103 } 104 } 105 } 106 return strings.Join(names, ",") 107 } 108 109 func (c *containerContext) Image() string { 110 c.AddHeader(imageHeader) 111 if c.c.Image == "" { 112 return "<no image>" 113 } 114 if c.trunc { 115 if trunc := stringid.TruncateID(c.c.ImageID); trunc == stringid.TruncateID(c.c.Image) { 116 return trunc 117 } 118 } 119 return c.c.Image 120 } 121 122 func (c *containerContext) Command() string { 123 c.AddHeader(commandHeader) 124 command := c.c.Command 125 if c.trunc { 126 command = stringutils.Ellipsis(command, 20) 127 } 128 return strconv.Quote(command) 129 } 130 131 func (c *containerContext) CreatedAt() string { 132 c.AddHeader(createdAtHeader) 133 return time.Unix(int64(c.c.Created), 0).String() 134 } 135 136 func (c *containerContext) RunningFor() string { 137 c.AddHeader(runningForHeader) 138 createdAt := time.Unix(int64(c.c.Created), 0) 139 return units.HumanDuration(time.Now().UTC().Sub(createdAt)) 140 } 141 142 func (c *containerContext) Ports() string { 143 c.AddHeader(portsHeader) 144 return api.DisplayablePorts(c.c.Ports) 145 } 146 147 func (c *containerContext) Status() string { 148 c.AddHeader(statusHeader) 149 return c.c.Status 150 } 151 152 func (c *containerContext) Size() string { 153 c.AddHeader(sizeHeader) 154 srw := units.HumanSizeWithPrecision(float64(c.c.SizeRw), 3) 155 sv := units.HumanSizeWithPrecision(float64(c.c.SizeRootFs), 3) 156 157 sf := srw 158 if c.c.SizeRootFs > 0 { 159 sf = fmt.Sprintf("%s (virtual %s)", srw, sv) 160 } 161 return sf 162 } 163 164 func (c *containerContext) Labels() string { 165 c.AddHeader(labelsHeader) 166 if c.c.Labels == nil { 167 return "" 168 } 169 170 var joinLabels []string 171 for k, v := range c.c.Labels { 172 joinLabels = append(joinLabels, fmt.Sprintf("%s=%s", k, v)) 173 } 174 return strings.Join(joinLabels, ",") 175 } 176 177 func (c *containerContext) Label(name string) string { 178 n := strings.Split(name, ".") 179 r := strings.NewReplacer("-", " ", "_", " ") 180 h := r.Replace(n[len(n)-1]) 181 182 c.AddHeader(h) 183 184 if c.c.Labels == nil { 185 return "" 186 } 187 return c.c.Labels[name] 188 } 189 190 func (c *containerContext) Mounts() string { 191 c.AddHeader(mountsHeader) 192 193 var name string 194 var mounts []string 195 for _, m := range c.c.Mounts { 196 if m.Name == "" { 197 name = m.Source 198 } else { 199 name = m.Name 200 } 201 if c.trunc { 202 name = stringutils.Ellipsis(name, 15) 203 } 204 mounts = append(mounts, name) 205 } 206 return strings.Join(mounts, ",") 207 } 208 209 func (c *containerContext) LocalVolumes() string { 210 c.AddHeader(localVolumes) 211 212 count := 0 213 for _, m := range c.c.Mounts { 214 if m.Driver == "local" { 215 count++ 216 } 217 } 218 219 return fmt.Sprintf("%d", count) 220 } 221 222 func (c *containerContext) Networks() string { 223 c.AddHeader(networksHeader) 224 225 if c.c.NetworkSettings == nil { 226 return "" 227 } 228 229 networks := []string{} 230 for k := range c.c.NetworkSettings.Networks { 231 networks = append(networks, k) 232 } 233 234 return strings.Join(networks, ",") 235 }