github.com/panekj/cli@v0.0.0-20230304125325-467dd2f3797e/cli/command/image/formatter_history.go (about)

     1  package image
     2  
     3  import (
     4  	"strconv"
     5  	"strings"
     6  	"time"
     7  
     8  	"github.com/docker/cli/cli/command/formatter"
     9  	"github.com/docker/docker/api/types/image"
    10  	"github.com/docker/docker/pkg/stringid"
    11  	units "github.com/docker/go-units"
    12  )
    13  
    14  const (
    15  	defaultHistoryTableFormat  = "table {{.ID}}\t{{.CreatedSince}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}"
    16  	nonHumanHistoryTableFormat = "table {{.ID}}\t{{.CreatedAt}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}"
    17  
    18  	historyIDHeader = "IMAGE"
    19  	createdByHeader = "CREATED BY"
    20  	commentHeader   = "COMMENT"
    21  )
    22  
    23  // NewHistoryFormat returns a format for rendering an HistoryContext
    24  func NewHistoryFormat(source string, quiet bool, human bool) formatter.Format {
    25  	switch source {
    26  	case formatter.TableFormatKey:
    27  		switch {
    28  		case quiet:
    29  			return formatter.DefaultQuietFormat
    30  		case !human:
    31  			return nonHumanHistoryTableFormat
    32  		default:
    33  			return defaultHistoryTableFormat
    34  		}
    35  	}
    36  
    37  	return formatter.Format(source)
    38  }
    39  
    40  // HistoryWrite writes the context
    41  func HistoryWrite(ctx formatter.Context, human bool, histories []image.HistoryResponseItem) error {
    42  	render := func(format func(subContext formatter.SubContext) error) error {
    43  		for _, history := range histories {
    44  			historyCtx := &historyContext{trunc: ctx.Trunc, h: history, human: human}
    45  			if err := format(historyCtx); err != nil {
    46  				return err
    47  			}
    48  		}
    49  		return nil
    50  	}
    51  	historyCtx := &historyContext{}
    52  	historyCtx.Header = formatter.SubHeaderContext{
    53  		"ID":           historyIDHeader,
    54  		"CreatedSince": formatter.CreatedSinceHeader,
    55  		"CreatedAt":    formatter.CreatedAtHeader,
    56  		"CreatedBy":    createdByHeader,
    57  		"Size":         formatter.SizeHeader,
    58  		"Comment":      commentHeader,
    59  	}
    60  	return ctx.Write(historyCtx, render)
    61  }
    62  
    63  type historyContext struct {
    64  	formatter.HeaderContext
    65  	trunc bool
    66  	human bool
    67  	h     image.HistoryResponseItem
    68  }
    69  
    70  func (c *historyContext) MarshalJSON() ([]byte, error) {
    71  	return formatter.MarshalJSON(c)
    72  }
    73  
    74  func (c *historyContext) ID() string {
    75  	if c.trunc {
    76  		return stringid.TruncateID(c.h.ID)
    77  	}
    78  	return c.h.ID
    79  }
    80  
    81  func (c *historyContext) CreatedAt() string {
    82  	return time.Unix(c.h.Created, 0).Format(time.RFC3339)
    83  }
    84  
    85  // epoch is the time before which created-at dates are not displayed with human units.
    86  var epoch = time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC).Unix()
    87  
    88  func (c *historyContext) CreatedSince() string {
    89  	if !c.human {
    90  		return c.CreatedAt()
    91  	}
    92  	if c.h.Created <= epoch {
    93  		return "N/A"
    94  	}
    95  	created := units.HumanDuration(time.Now().UTC().Sub(time.Unix(c.h.Created, 0)))
    96  	return created + " ago"
    97  }
    98  
    99  func (c *historyContext) CreatedBy() string {
   100  	createdBy := strings.Replace(c.h.CreatedBy, "\t", " ", -1)
   101  	if c.trunc {
   102  		return formatter.Ellipsis(createdBy, 45)
   103  	}
   104  	return createdBy
   105  }
   106  
   107  func (c *historyContext) Size() string {
   108  	if c.human {
   109  		return units.HumanSizeWithPrecision(float64(c.h.Size), 3)
   110  	}
   111  	return strconv.FormatInt(c.h.Size, 10)
   112  }
   113  
   114  func (c *historyContext) Comment() string {
   115  	return c.h.Comment
   116  }