blob: 62734533551dbbb58b0d50940348fff99c46c5ed [file] [log] [blame]
package formatter
import (
"fmt"
"strconv"
"strings"
"time"
"github.com/docker/docker/api"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/stringutils"
units "github.com/docker/go-units"
)
const (
defaultContainerTableFormat = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.RunningFor}} ago\t{{.Status}}\t{{.Ports}}\t{{.Names}}"
containerIDHeader = "CONTAINER ID"
namesHeader = "NAMES"
commandHeader = "COMMAND"
runningForHeader = "CREATED"
statusHeader = "STATUS"
portsHeader = "PORTS"
mountsHeader = "MOUNTS"
localVolumes = "LOCAL VOLUMES"
networksHeader = "NETWORKS"
)
// NewContainerFormat returns a Format for rendering using a Context
func NewContainerFormat(source string, quiet bool, size bool) Format {
switch source {
case TableFormatKey:
if quiet {
return defaultQuietFormat
}
format := defaultContainerTableFormat
if size {
format += `\t{{.Size}}`
}
return Format(format)
case RawFormatKey:
if quiet {
return `container_id: {{.ID}}`
}
format := `container_id: {{.ID}}
image: {{.Image}}
command: {{.Command}}
created_at: {{.CreatedAt}}
status: {{- pad .Status 1 0}}
names: {{.Names}}
labels: {{- pad .Labels 1 0}}
ports: {{- pad .Ports 1 0}}
`
if size {
format += `size: {{.Size}}\n`
}
return Format(format)
}
return Format(source)
}
// ContainerWrite renders the context for a list of containers
func ContainerWrite(ctx Context, containers []types.Container) error {
render := func(format func(subContext subContext) error) error {
for _, container := range containers {
err := format(&containerContext{trunc: ctx.Trunc, c: container})
if err != nil {
return err
}
}
return nil
}
return ctx.Write(&containerContext{}, render)
}
type containerContext struct {
HeaderContext
trunc bool
c types.Container
}
func (c *containerContext) MarshalJSON() ([]byte, error) {
return marshalJSON(c)
}
func (c *containerContext) ID() string {
c.AddHeader(containerIDHeader)
if c.trunc {
return stringid.TruncateID(c.c.ID)
}
return c.c.ID
}
func (c *containerContext) Names() string {
c.AddHeader(namesHeader)
names := stripNamePrefix(c.c.Names)
if c.trunc {
for _, name := range names {
if len(strings.Split(name, "/")) == 1 {
names = []string{name}
break
}
}
}
return strings.Join(names, ",")
}
func (c *containerContext) Image() string {
c.AddHeader(imageHeader)
if c.c.Image == "" {
return "<no image>"
}
if c.trunc {
if trunc := stringid.TruncateID(c.c.ImageID); trunc == stringid.TruncateID(c.c.Image) {
return trunc
}
}
return c.c.Image
}
func (c *containerContext) Command() string {
c.AddHeader(commandHeader)
command := c.c.Command
if c.trunc {
command = stringutils.Ellipsis(command, 20)
}
return strconv.Quote(command)
}
func (c *containerContext) CreatedAt() string {
c.AddHeader(createdAtHeader)
return time.Unix(int64(c.c.Created), 0).String()
}
func (c *containerContext) RunningFor() string {
c.AddHeader(runningForHeader)
createdAt := time.Unix(int64(c.c.Created), 0)
return units.HumanDuration(time.Now().UTC().Sub(createdAt))
}
func (c *containerContext) Ports() string {
c.AddHeader(portsHeader)
return api.DisplayablePorts(c.c.Ports)
}
func (c *containerContext) Status() string {
c.AddHeader(statusHeader)
return c.c.Status
}
func (c *containerContext) Size() string {
c.AddHeader(sizeHeader)
srw := units.HumanSizeWithPrecision(float64(c.c.SizeRw), 3)
sv := units.HumanSizeWithPrecision(float64(c.c.SizeRootFs), 3)
sf := srw
if c.c.SizeRootFs > 0 {
sf = fmt.Sprintf("%s (virtual %s)", srw, sv)
}
return sf
}
func (c *containerContext) Labels() string {
c.AddHeader(labelsHeader)
if c.c.Labels == nil {
return ""
}
var joinLabels []string
for k, v := range c.c.Labels {
joinLabels = append(joinLabels, fmt.Sprintf("%s=%s", k, v))
}
return strings.Join(joinLabels, ",")
}
func (c *containerContext) Label(name string) string {
n := strings.Split(name, ".")
r := strings.NewReplacer("-", " ", "_", " ")
h := r.Replace(n[len(n)-1])
c.AddHeader(h)
if c.c.Labels == nil {
return ""
}
return c.c.Labels[name]
}
func (c *containerContext) Mounts() string {
c.AddHeader(mountsHeader)
var name string
var mounts []string
for _, m := range c.c.Mounts {
if m.Name == "" {
name = m.Source
} else {
name = m.Name
}
if c.trunc {
name = stringutils.Ellipsis(name, 15)
}
mounts = append(mounts, name)
}
return strings.Join(mounts, ",")
}
func (c *containerContext) LocalVolumes() string {
c.AddHeader(localVolumes)
count := 0
for _, m := range c.c.Mounts {
if m.Driver == "local" {
count++
}
}
return fmt.Sprintf("%d", count)
}
func (c *containerContext) Networks() string {
c.AddHeader(networksHeader)
if c.c.NetworkSettings == nil {
return ""
}
networks := []string{}
for k := range c.c.NetworkSettings.Networks {
networks = append(networks, k)
}
return strings.Join(networks, ",")
}