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