github.com/campoy/docker@v1.8.0-rc1/api/client/ps/custom.go (about)

     1  package ps
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"strconv"
     7  	"strings"
     8  	"text/tabwriter"
     9  	"text/template"
    10  	"time"
    11  
    12  	"github.com/docker/docker/api"
    13  	"github.com/docker/docker/api/types"
    14  	"github.com/docker/docker/pkg/stringid"
    15  	"github.com/docker/docker/pkg/stringutils"
    16  	"github.com/docker/docker/pkg/units"
    17  )
    18  
    19  const (
    20  	tableKey = "table"
    21  
    22  	idHeader         = "CONTAINER ID"
    23  	imageHeader      = "IMAGE"
    24  	namesHeader      = "NAMES"
    25  	commandHeader    = "COMMAND"
    26  	createdAtHeader  = "CREATED AT"
    27  	runningForHeader = "CREATED"
    28  	statusHeader     = "STATUS"
    29  	portsHeader      = "PORTS"
    30  	sizeHeader       = "SIZE"
    31  	labelsHeader     = "LABELS"
    32  )
    33  
    34  type containerContext struct {
    35  	trunc  bool
    36  	header []string
    37  	c      types.Container
    38  }
    39  
    40  func (c *containerContext) ID() string {
    41  	c.addHeader(idHeader)
    42  	if c.trunc {
    43  		return stringid.TruncateID(c.c.ID)
    44  	}
    45  	return c.c.ID
    46  }
    47  
    48  func (c *containerContext) Names() string {
    49  	c.addHeader(namesHeader)
    50  	names := stripNamePrefix(c.c.Names)
    51  	if c.trunc {
    52  		for _, name := range names {
    53  			if len(strings.Split(name, "/")) == 1 {
    54  				names = []string{name}
    55  				break
    56  			}
    57  		}
    58  	}
    59  	return strings.Join(names, ",")
    60  }
    61  
    62  func (c *containerContext) Image() string {
    63  	c.addHeader(imageHeader)
    64  	if c.c.Image == "" {
    65  		return "<no image>"
    66  	}
    67  	return c.c.Image
    68  }
    69  
    70  func (c *containerContext) Command() string {
    71  	c.addHeader(commandHeader)
    72  	command := c.c.Command
    73  	if c.trunc {
    74  		command = stringutils.Truncate(command, 20)
    75  	}
    76  	return strconv.Quote(command)
    77  }
    78  
    79  func (c *containerContext) CreatedAt() string {
    80  	c.addHeader(createdAtHeader)
    81  	return time.Unix(int64(c.c.Created), 0).String()
    82  }
    83  
    84  func (c *containerContext) RunningFor() string {
    85  	c.addHeader(runningForHeader)
    86  	createdAt := time.Unix(int64(c.c.Created), 0)
    87  	return units.HumanDuration(time.Now().UTC().Sub(createdAt))
    88  }
    89  
    90  func (c *containerContext) Ports() string {
    91  	c.addHeader(portsHeader)
    92  	return api.DisplayablePorts(c.c.Ports)
    93  }
    94  
    95  func (c *containerContext) Status() string {
    96  	c.addHeader(statusHeader)
    97  	return c.c.Status
    98  }
    99  
   100  func (c *containerContext) Size() string {
   101  	c.addHeader(sizeHeader)
   102  	srw := units.HumanSize(float64(c.c.SizeRw))
   103  	sv := units.HumanSize(float64(c.c.SizeRootFs))
   104  
   105  	sf := srw
   106  	if c.c.SizeRootFs > 0 {
   107  		sf = fmt.Sprintf("%s (virtual %s)", srw, sv)
   108  	}
   109  	return sf
   110  }
   111  
   112  func (c *containerContext) Labels() string {
   113  	c.addHeader(labelsHeader)
   114  	if c.c.Labels == nil {
   115  		return ""
   116  	}
   117  
   118  	var joinLabels []string
   119  	for k, v := range c.c.Labels {
   120  		joinLabels = append(joinLabels, fmt.Sprintf("%s=%s", k, v))
   121  	}
   122  	return strings.Join(joinLabels, ",")
   123  }
   124  
   125  func (c *containerContext) Label(name string) string {
   126  	n := strings.Split(name, ".")
   127  	r := strings.NewReplacer("-", " ", "_", " ")
   128  	h := r.Replace(n[len(n)-1])
   129  
   130  	c.addHeader(h)
   131  
   132  	if c.c.Labels == nil {
   133  		return ""
   134  	}
   135  	return c.c.Labels[name]
   136  }
   137  
   138  func (c *containerContext) fullHeader() string {
   139  	if c.header == nil {
   140  		return ""
   141  	}
   142  	return strings.Join(c.header, "\t")
   143  }
   144  
   145  func (c *containerContext) addHeader(header string) {
   146  	if c.header == nil {
   147  		c.header = []string{}
   148  	}
   149  	c.header = append(c.header, strings.ToUpper(header))
   150  }
   151  
   152  func customFormat(ctx Context, containers []types.Container) {
   153  	var (
   154  		table  bool
   155  		header string
   156  		format = ctx.Format
   157  		buffer = bytes.NewBufferString("")
   158  	)
   159  
   160  	if strings.HasPrefix(ctx.Format, tableKey) {
   161  		table = true
   162  		format = format[len(tableKey):]
   163  	}
   164  
   165  	format = strings.Trim(format, " ")
   166  	r := strings.NewReplacer(`\t`, "\t", `\n`, "\n")
   167  	format = r.Replace(format)
   168  
   169  	if table && ctx.Size {
   170  		format += "\t{{.Size}}"
   171  	}
   172  
   173  	tmpl, err := template.New("ps template").Parse(format)
   174  	if err != nil {
   175  		buffer.WriteString(fmt.Sprintf("Invalid `docker ps` format: %v\n", err))
   176  	}
   177  
   178  	for _, container := range containers {
   179  		containerCtx := &containerContext{
   180  			trunc: ctx.Trunc,
   181  			c:     container,
   182  		}
   183  		if err := tmpl.Execute(buffer, containerCtx); err != nil {
   184  			buffer = bytes.NewBufferString(fmt.Sprintf("Invalid `docker ps` format: %v\n", err))
   185  			break
   186  		}
   187  		if table && len(header) == 0 {
   188  			header = containerCtx.fullHeader()
   189  		}
   190  		buffer.WriteString("\n")
   191  	}
   192  
   193  	if table {
   194  		if len(header) == 0 {
   195  			// if we still don't have a header, we didn't have any containers so we need to fake it to get the right headers from the template
   196  			containerCtx := &containerContext{}
   197  			tmpl.Execute(bytes.NewBufferString(""), containerCtx)
   198  			header = containerCtx.fullHeader()
   199  		}
   200  
   201  		t := tabwriter.NewWriter(ctx.Output, 20, 1, 3, ' ', 0)
   202  		t.Write([]byte(header))
   203  		t.Write([]byte("\n"))
   204  		buffer.WriteTo(t)
   205  		t.Flush()
   206  	} else {
   207  		buffer.WriteTo(ctx.Output)
   208  	}
   209  }
   210  
   211  func stripNamePrefix(ss []string) []string {
   212  	for i, s := range ss {
   213  		ss[i] = s[1:]
   214  	}
   215  
   216  	return ss
   217  }