github.com/a4a881d4/docker@v1.9.0-rc2/api/client/ps/formatter.go (about) 1 package ps 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "strings" 8 "text/tabwriter" 9 "text/template" 10 11 "github.com/docker/docker/api/types" 12 ) 13 14 const ( 15 tableFormatKey = "table" 16 rawFormatKey = "raw" 17 18 defaultTableFormat = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.RunningFor}} ago\t{{.Status}}\t{{.Ports}}\t{{.Names}}" 19 defaultQuietFormat = "{{.ID}}" 20 ) 21 22 // Context contains information required by the formatter to print the output as desired. 23 type Context struct { 24 // Output is the output stream to which the formatted string is written. 25 Output io.Writer 26 // Format is used to choose raw, table or custom format for the output. 27 Format string 28 // Size when set to true will display the size of the output. 29 Size bool 30 // Quiet when set to true will simply print minimal information. 31 Quiet bool 32 // Trunc when set to true will truncate the output of certain fields such as Container ID. 33 Trunc bool 34 } 35 36 // Format helps to format the output using the parameters set in the Context. 37 // Currently Format allow to display in raw, table or custom format the output. 38 func Format(ctx Context, containers []types.Container) { 39 switch ctx.Format { 40 case tableFormatKey: 41 tableFormat(ctx, containers) 42 case rawFormatKey: 43 rawFormat(ctx, containers) 44 default: 45 customFormat(ctx, containers) 46 } 47 } 48 49 func rawFormat(ctx Context, containers []types.Container) { 50 if ctx.Quiet { 51 ctx.Format = `container_id: {{.ID}}` 52 } else { 53 ctx.Format = `container_id: {{.ID}} 54 image: {{.Image}} 55 command: {{.Command}} 56 created_at: {{.CreatedAt}} 57 status: {{.Status}} 58 names: {{.Names}} 59 labels: {{.Labels}} 60 ports: {{.Ports}} 61 ` 62 if ctx.Size { 63 ctx.Format += `size: {{.Size}} 64 ` 65 } 66 } 67 68 customFormat(ctx, containers) 69 } 70 71 func tableFormat(ctx Context, containers []types.Container) { 72 ctx.Format = defaultTableFormat 73 if ctx.Quiet { 74 ctx.Format = defaultQuietFormat 75 } 76 77 customFormat(ctx, containers) 78 } 79 80 func customFormat(ctx Context, containers []types.Container) { 81 var ( 82 table bool 83 header string 84 format = ctx.Format 85 buffer = bytes.NewBufferString("") 86 ) 87 88 if strings.HasPrefix(ctx.Format, tableKey) { 89 table = true 90 format = format[len(tableKey):] 91 } 92 93 format = strings.Trim(format, " ") 94 r := strings.NewReplacer(`\t`, "\t", `\n`, "\n") 95 format = r.Replace(format) 96 97 if table && ctx.Size { 98 format += "\t{{.Size}}" 99 } 100 101 tmpl, err := template.New("").Parse(format) 102 if err != nil { 103 buffer.WriteString(fmt.Sprintf("Template parsing error: %v\n", err)) 104 buffer.WriteTo(ctx.Output) 105 return 106 } 107 108 for _, container := range containers { 109 containerCtx := &containerContext{ 110 trunc: ctx.Trunc, 111 c: container, 112 } 113 if err := tmpl.Execute(buffer, containerCtx); err != nil { 114 buffer = bytes.NewBufferString(fmt.Sprintf("Template parsing error: %v\n", err)) 115 buffer.WriteTo(ctx.Output) 116 return 117 } 118 if table && len(header) == 0 { 119 header = containerCtx.fullHeader() 120 } 121 buffer.WriteString("\n") 122 } 123 124 if table { 125 if len(header) == 0 { 126 // 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 127 containerCtx := &containerContext{} 128 tmpl.Execute(bytes.NewBufferString(""), containerCtx) 129 header = containerCtx.fullHeader() 130 } 131 132 t := tabwriter.NewWriter(ctx.Output, 20, 1, 3, ' ', 0) 133 t.Write([]byte(header)) 134 t.Write([]byte("\n")) 135 buffer.WriteTo(t) 136 t.Flush() 137 } else { 138 buffer.WriteTo(ctx.Output) 139 } 140 }