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  }