github.com/khulnasoft/cli@v0.0.0-20240402070845-01bcad7beefa/cli/command/image/formatter_history.go (about)

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