container.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. package formatter
  2. import (
  3. "bytes"
  4. "fmt"
  5. "strconv"
  6. "strings"
  7. "time"
  8. "github.com/docker/docker/api"
  9. "github.com/docker/docker/api/types"
  10. "github.com/docker/docker/pkg/stringid"
  11. "github.com/docker/docker/pkg/stringutils"
  12. "github.com/docker/go-units"
  13. )
  14. const (
  15. defaultContainerTableFormat = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.RunningFor}} ago\t{{.Status}}\t{{.Ports}}\t{{.Names}}"
  16. containerIDHeader = "CONTAINER ID"
  17. namesHeader = "NAMES"
  18. commandHeader = "COMMAND"
  19. runningForHeader = "CREATED"
  20. statusHeader = "STATUS"
  21. portsHeader = "PORTS"
  22. mountsHeader = "MOUNTS"
  23. )
  24. // ContainerContext contains container specific information required by the formater, encapsulate a Context struct.
  25. type ContainerContext struct {
  26. Context
  27. // Size when set to true will display the size of the output.
  28. Size bool
  29. // Containers
  30. Containers []types.Container
  31. }
  32. func (ctx ContainerContext) Write() {
  33. switch ctx.Format {
  34. case tableFormatKey:
  35. if ctx.Quiet {
  36. ctx.Format = defaultQuietFormat
  37. } else {
  38. ctx.Format = defaultContainerTableFormat
  39. if ctx.Size {
  40. ctx.Format += `\t{{.Size}}`
  41. }
  42. }
  43. case rawFormatKey:
  44. if ctx.Quiet {
  45. ctx.Format = `container_id: {{.ID}}`
  46. } else {
  47. ctx.Format = `container_id: {{.ID}}\nimage: {{.Image}}\ncommand: {{.Command}}\ncreated_at: {{.CreatedAt}}\nstatus: {{.Status}}\nnames: {{.Names}}\nlabels: {{.Labels}}\nports: {{.Ports}}\n`
  48. if ctx.Size {
  49. ctx.Format += `size: {{.Size}}\n`
  50. }
  51. }
  52. }
  53. ctx.buffer = bytes.NewBufferString("")
  54. ctx.preformat()
  55. tmpl, err := ctx.parseFormat()
  56. if err != nil {
  57. return
  58. }
  59. for _, container := range ctx.Containers {
  60. containerCtx := &containerContext{
  61. trunc: ctx.Trunc,
  62. c: container,
  63. }
  64. err = ctx.contextFormat(tmpl, containerCtx)
  65. if err != nil {
  66. return
  67. }
  68. }
  69. ctx.postformat(tmpl, &containerContext{})
  70. }
  71. type containerContext struct {
  72. baseSubContext
  73. trunc bool
  74. c types.Container
  75. }
  76. func (c *containerContext) ID() string {
  77. c.addHeader(containerIDHeader)
  78. if c.trunc {
  79. return stringid.TruncateID(c.c.ID)
  80. }
  81. return c.c.ID
  82. }
  83. func (c *containerContext) Names() string {
  84. c.addHeader(namesHeader)
  85. names := stripNamePrefix(c.c.Names)
  86. if c.trunc {
  87. for _, name := range names {
  88. if len(strings.Split(name, "/")) == 1 {
  89. names = []string{name}
  90. break
  91. }
  92. }
  93. }
  94. return strings.Join(names, ",")
  95. }
  96. func (c *containerContext) Image() string {
  97. c.addHeader(imageHeader)
  98. if c.c.Image == "" {
  99. return "<no image>"
  100. }
  101. if c.trunc {
  102. if trunc := stringid.TruncateID(c.c.ImageID); trunc == stringid.TruncateID(c.c.Image) {
  103. return trunc
  104. }
  105. }
  106. return c.c.Image
  107. }
  108. func (c *containerContext) Command() string {
  109. c.addHeader(commandHeader)
  110. command := c.c.Command
  111. if c.trunc {
  112. command = stringutils.Ellipsis(command, 20)
  113. }
  114. return strconv.Quote(command)
  115. }
  116. func (c *containerContext) CreatedAt() string {
  117. c.addHeader(createdAtHeader)
  118. return time.Unix(int64(c.c.Created), 0).String()
  119. }
  120. func (c *containerContext) RunningFor() string {
  121. c.addHeader(runningForHeader)
  122. createdAt := time.Unix(int64(c.c.Created), 0)
  123. return units.HumanDuration(time.Now().UTC().Sub(createdAt))
  124. }
  125. func (c *containerContext) Ports() string {
  126. c.addHeader(portsHeader)
  127. return api.DisplayablePorts(c.c.Ports)
  128. }
  129. func (c *containerContext) Status() string {
  130. c.addHeader(statusHeader)
  131. return c.c.Status
  132. }
  133. func (c *containerContext) Size() string {
  134. c.addHeader(sizeHeader)
  135. srw := units.HumanSize(float64(c.c.SizeRw))
  136. sv := units.HumanSize(float64(c.c.SizeRootFs))
  137. sf := srw
  138. if c.c.SizeRootFs > 0 {
  139. sf = fmt.Sprintf("%s (virtual %s)", srw, sv)
  140. }
  141. return sf
  142. }
  143. func (c *containerContext) Labels() string {
  144. c.addHeader(labelsHeader)
  145. if c.c.Labels == nil {
  146. return ""
  147. }
  148. var joinLabels []string
  149. for k, v := range c.c.Labels {
  150. joinLabels = append(joinLabels, fmt.Sprintf("%s=%s", k, v))
  151. }
  152. return strings.Join(joinLabels, ",")
  153. }
  154. func (c *containerContext) Label(name string) string {
  155. n := strings.Split(name, ".")
  156. r := strings.NewReplacer("-", " ", "_", " ")
  157. h := r.Replace(n[len(n)-1])
  158. c.addHeader(h)
  159. if c.c.Labels == nil {
  160. return ""
  161. }
  162. return c.c.Labels[name]
  163. }
  164. func (c *containerContext) Mounts() string {
  165. c.addHeader(mountsHeader)
  166. var name string
  167. var mounts []string
  168. for _, m := range c.c.Mounts {
  169. if m.Name == "" {
  170. name = m.Source
  171. } else {
  172. name = m.Name
  173. }
  174. if c.trunc {
  175. name = stringutils.Ellipsis(name, 15)
  176. }
  177. mounts = append(mounts, name)
  178. }
  179. return strings.Join(mounts, ",")
  180. }