github.com/kim0/docker@v0.6.2-0.20161130212042-4addda3f07e7/cli/command/task/print.go (about)

     1  package task
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"sort"
     7  	"strings"
     8  	"text/tabwriter"
     9  	"time"
    10  
    11  	"golang.org/x/net/context"
    12  
    13  	"github.com/docker/docker/api/types/swarm"
    14  	"github.com/docker/docker/cli/command"
    15  	"github.com/docker/docker/cli/command/idresolver"
    16  	"github.com/docker/go-units"
    17  )
    18  
    19  const (
    20  	psTaskItemFmt = "%s\t%s\t%s\t%s\t%s %s ago\t%s\n"
    21  	maxErrLength  = 30
    22  )
    23  
    24  type tasksBySlot []swarm.Task
    25  
    26  func (t tasksBySlot) Len() int {
    27  	return len(t)
    28  }
    29  
    30  func (t tasksBySlot) Swap(i, j int) {
    31  	t[i], t[j] = t[j], t[i]
    32  }
    33  
    34  func (t tasksBySlot) Less(i, j int) bool {
    35  	// Sort by slot.
    36  	if t[i].Slot != t[j].Slot {
    37  		return t[i].Slot < t[j].Slot
    38  	}
    39  
    40  	// If same slot, sort by most recent.
    41  	return t[j].Meta.CreatedAt.Before(t[i].CreatedAt)
    42  }
    43  
    44  // Print task information in a table format.
    45  // Besides this, command `docker node ps <node>`
    46  // and `docker stack ps` will call this, too.
    47  func Print(dockerCli *command.DockerCli, ctx context.Context, tasks []swarm.Task, resolver *idresolver.IDResolver, noTrunc bool) error {
    48  	sort.Stable(tasksBySlot(tasks))
    49  
    50  	writer := tabwriter.NewWriter(dockerCli.Out(), 0, 4, 2, ' ', 0)
    51  
    52  	// Ignore flushing errors
    53  	defer writer.Flush()
    54  	fmt.Fprintln(writer, strings.Join([]string{"NAME", "IMAGE", "NODE", "DESIRED STATE", "CURRENT STATE", "ERROR"}, "\t"))
    55  
    56  	if err := print(writer, ctx, tasks, resolver, noTrunc); err != nil {
    57  		return err
    58  	}
    59  
    60  	return nil
    61  }
    62  
    63  // PrintQuiet shows task list in a quiet way.
    64  func PrintQuiet(dockerCli *command.DockerCli, tasks []swarm.Task) error {
    65  	sort.Stable(tasksBySlot(tasks))
    66  
    67  	out := dockerCli.Out()
    68  
    69  	for _, task := range tasks {
    70  		fmt.Fprintln(out, task.ID)
    71  	}
    72  
    73  	return nil
    74  }
    75  
    76  func print(out io.Writer, ctx context.Context, tasks []swarm.Task, resolver *idresolver.IDResolver, noTrunc bool) error {
    77  	prevServiceName := ""
    78  	prevSlot := 0
    79  	for _, task := range tasks {
    80  		serviceName, err := resolver.Resolve(ctx, swarm.Service{}, task.ServiceID)
    81  		if err != nil {
    82  			return err
    83  		}
    84  		nodeValue, err := resolver.Resolve(ctx, swarm.Node{}, task.NodeID)
    85  		if err != nil {
    86  			return err
    87  		}
    88  
    89  		name := task.Annotations.Name
    90  		// TODO: This is the fallback <ServiceName>.<Slot>.<taskID> in case task name is not present in
    91  		// Annotations (upgraded from 1.12).
    92  		// We may be able to remove the following in the future.
    93  		if name == "" {
    94  			if task.Slot != 0 {
    95  				name = fmt.Sprintf("%v.%v.%v", serviceName, task.Slot, task.ID)
    96  			} else {
    97  				name = fmt.Sprintf("%v.%v.%v", serviceName, task.NodeID, task.ID)
    98  			}
    99  		}
   100  
   101  		// Indent the name if necessary
   102  		indentedName := name
   103  		// Since the new format of the task name is <ServiceName>.<Slot>.<taskID>, we should only compare
   104  		// <ServiceName> and <Slot> here.
   105  		if prevServiceName == serviceName && prevSlot == task.Slot {
   106  			indentedName = fmt.Sprintf(" \\_ %s", indentedName)
   107  		}
   108  		prevServiceName = serviceName
   109  		prevSlot = task.Slot
   110  
   111  		// Trim and quote the error message.
   112  		taskErr := task.Status.Err
   113  		if !noTrunc && len(taskErr) > maxErrLength {
   114  			taskErr = fmt.Sprintf("%s…", taskErr[:maxErrLength-1])
   115  		}
   116  		if len(taskErr) > 0 {
   117  			taskErr = fmt.Sprintf("\"%s\"", taskErr)
   118  		}
   119  
   120  		fmt.Fprintf(
   121  			out,
   122  			psTaskItemFmt,
   123  			indentedName,
   124  			task.Spec.ContainerSpec.Image,
   125  			nodeValue,
   126  			command.PrettyPrint(task.DesiredState),
   127  			command.PrettyPrint(task.Status.State),
   128  			strings.ToLower(units.HumanDuration(time.Since(task.Status.Timestamp))),
   129  			taskErr,
   130  		)
   131  	}
   132  	return nil
   133  }