mirror of https://github.com/docker/cli.git
system df: show table output for build cache
Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit ca608c2302
)
Signed-off-by: Tibor Vass <tibor@docker.com>
This commit is contained in:
parent
9d43f1ed48
commit
3c37d6a034
|
@ -0,0 +1,165 @@
|
|||
package formatter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/go-units"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultBuildCacheTableFormat = "table {{.ID}}\t{{.Type}}\t{{.Size}}\t{{.CreatedSince}}\t{{.LastUsedSince}}\t{{.UsageCount}}\t{{.Shared}}\t{{.Description}}"
|
||||
|
||||
cacheIDHeader = "CACHE ID"
|
||||
parentHeader = "PARENT"
|
||||
lastUsedSinceHeader = "LAST USED"
|
||||
usageCountHeader = "USAGE"
|
||||
inUseHeader = "IN USE"
|
||||
sharedHeader = "SHARED"
|
||||
)
|
||||
|
||||
// NewBuildCacheFormat returns a Format for rendering using a Context
|
||||
func NewBuildCacheFormat(source string, quiet bool) Format {
|
||||
switch source {
|
||||
case TableFormatKey:
|
||||
if quiet {
|
||||
return defaultQuietFormat
|
||||
}
|
||||
return Format(defaultBuildCacheTableFormat)
|
||||
case RawFormatKey:
|
||||
if quiet {
|
||||
return `build_cache_id: {{.ID}}`
|
||||
}
|
||||
format := `build_cache_id: {{.ID}}
|
||||
parent_id: {{.Parent}}
|
||||
type: {{.Type}}
|
||||
description: {{.Description}}
|
||||
created_at: {{.CreatedSince}}
|
||||
last_used_at: {{.LastUsedSince}}
|
||||
usage_count: {{.UsageCount}}
|
||||
in_use: {{.InUse}}
|
||||
shared: {{.Shared}}
|
||||
`
|
||||
return Format(format)
|
||||
}
|
||||
return Format(source)
|
||||
}
|
||||
|
||||
func buildCacheSort(buildCache []*types.BuildCache) {
|
||||
sort.Slice(buildCache, func(i, j int) bool {
|
||||
lui, luj := buildCache[i].LastUsedAt, buildCache[j].LastUsedAt
|
||||
switch {
|
||||
case lui == nil && luj == nil:
|
||||
return strings.Compare(buildCache[i].ID, buildCache[j].ID) < 0
|
||||
case lui == nil:
|
||||
return true
|
||||
case luj == nil:
|
||||
return false
|
||||
case lui.Equal(*luj):
|
||||
return strings.Compare(buildCache[i].ID, buildCache[j].ID) < 0
|
||||
default:
|
||||
return lui.Before(*luj)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BuildCacheWrite renders the context for a list of containers
|
||||
func BuildCacheWrite(ctx Context, buildCaches []*types.BuildCache) error {
|
||||
render := func(format func(subContext subContext) error) error {
|
||||
buildCacheSort(buildCaches)
|
||||
for _, bc := range buildCaches {
|
||||
err := format(&buildCacheContext{trunc: ctx.Trunc, v: bc})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return ctx.Write(newBuildCacheContext(), render)
|
||||
}
|
||||
|
||||
type buildCacheHeaderContext map[string]string
|
||||
|
||||
type buildCacheContext struct {
|
||||
HeaderContext
|
||||
trunc bool
|
||||
v *types.BuildCache
|
||||
}
|
||||
|
||||
func newBuildCacheContext() *buildCacheContext {
|
||||
buildCacheCtx := buildCacheContext{}
|
||||
buildCacheCtx.header = buildCacheHeaderContext{
|
||||
"ID": cacheIDHeader,
|
||||
"Parent": parentHeader,
|
||||
"Type": typeHeader,
|
||||
"Size": sizeHeader,
|
||||
"CreatedSince": createdSinceHeader,
|
||||
"LastUsedSince": lastUsedSinceHeader,
|
||||
"UsageCount": usageCountHeader,
|
||||
"InUse": inUseHeader,
|
||||
"Shared": sharedHeader,
|
||||
"Description": descriptionHeader,
|
||||
}
|
||||
return &buildCacheCtx
|
||||
}
|
||||
|
||||
func (c *buildCacheContext) MarshalJSON() ([]byte, error) {
|
||||
return marshalJSON(c)
|
||||
}
|
||||
|
||||
func (c *buildCacheContext) ID() string {
|
||||
id := c.v.ID
|
||||
if c.trunc {
|
||||
id = stringid.TruncateID(c.v.ID)
|
||||
}
|
||||
if c.v.InUse {
|
||||
return id + "*"
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
func (c *buildCacheContext) Parent() string {
|
||||
if c.trunc {
|
||||
return stringid.TruncateID(c.v.Parent)
|
||||
}
|
||||
return c.v.Parent
|
||||
}
|
||||
|
||||
func (c *buildCacheContext) Type() string {
|
||||
return c.v.Type
|
||||
}
|
||||
|
||||
func (c *buildCacheContext) Description() string {
|
||||
return c.v.Description
|
||||
}
|
||||
|
||||
func (c *buildCacheContext) Size() string {
|
||||
return units.HumanSizeWithPrecision(float64(c.v.Size), 3)
|
||||
}
|
||||
|
||||
func (c *buildCacheContext) CreatedSince() string {
|
||||
return units.HumanDuration(time.Now().UTC().Sub(c.v.CreatedAt)) + " ago"
|
||||
}
|
||||
|
||||
func (c *buildCacheContext) LastUsedSince() string {
|
||||
if c.v.LastUsedAt == nil {
|
||||
return ""
|
||||
}
|
||||
return units.HumanDuration(time.Now().UTC().Sub(*c.v.LastUsedAt)) + " ago"
|
||||
}
|
||||
|
||||
func (c *buildCacheContext) UsageCount() string {
|
||||
return fmt.Sprintf("%d", c.v.UsageCount)
|
||||
}
|
||||
|
||||
func (c *buildCacheContext) InUse() string {
|
||||
return fmt.Sprintf("%t", c.v.InUse)
|
||||
}
|
||||
|
||||
func (c *buildCacheContext) Shared() string {
|
||||
return fmt.Sprintf("%t", c.v.Shared)
|
||||
}
|
|
@ -12,22 +12,11 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
defaultDiskUsageImageTableFormat = "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.CreatedSince}} ago\t{{.VirtualSize}}\t{{.SharedSize}}\t{{.UniqueSize}}\t{{.Containers}}"
|
||||
defaultDiskUsageContainerTableFormat = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.LocalVolumes}}\t{{.Size}}\t{{.RunningFor}} ago\t{{.Status}}\t{{.Names}}"
|
||||
defaultDiskUsageVolumeTableFormat = "table {{.Name}}\t{{.Links}}\t{{.Size}}"
|
||||
defaultDiskUsageTableFormat = "table {{.Type}}\t{{.TotalCount}}\t{{.Active}}\t{{.Size}}\t{{.Reclaimable}}"
|
||||
defaultBuildCacheVerboseFormat = `
|
||||
ID: {{.ID}}
|
||||
Parent: {{.Parent}}
|
||||
Type: {{.Type}}
|
||||
Description: {{.Description}}
|
||||
Size: {{.Size}}
|
||||
CreatedAt: {{.CreatedAt}}
|
||||
LastUsedAt: {{.LastUsedAt}}
|
||||
UsageCount: {{.UsageCount}}
|
||||
InUse: {{.InUse}}
|
||||
Shared: {{.Shared}}
|
||||
`
|
||||
defaultDiskUsageImageTableFormat = "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.CreatedSince}}\t{{.VirtualSize}}\t{{.SharedSize}}\t{{.UniqueSize}}\t{{.Containers}}"
|
||||
defaultDiskUsageContainerTableFormat = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.LocalVolumes}}\t{{.Size}}\t{{.RunningFor}}\t{{.Status}}\t{{.Names}}"
|
||||
defaultDiskUsageVolumeTableFormat = "table {{.Name}}\t{{.Links}}\t{{.Size}}"
|
||||
defaultDiskUsageTableFormat = "table {{.Type}}\t{{.TotalCount}}\t{{.Active}}\t{{.Size}}\t{{.Reclaimable}}"
|
||||
defaultDiskUsageBuildCacheTableFormat = "table {{.ID}}\t{{.Type}}\t{{.Size}}\t{{.CreatedSince}}\t{{.LastUsedSince}}\t{{.UsageCount}}\t{{.Shared}}"
|
||||
|
||||
typeHeader = "TYPE"
|
||||
totalHeader = "TOTAL"
|
||||
|
@ -35,7 +24,7 @@ Shared: {{.Shared}}
|
|||
reclaimableHeader = "RECLAIMABLE"
|
||||
containersHeader = "CONTAINERS"
|
||||
sharedSizeHeader = "SHARED SIZE"
|
||||
uniqueSizeHeader = "UNIQUE SiZE"
|
||||
uniqueSizeHeader = "UNIQUE SIZE"
|
||||
)
|
||||
|
||||
// DiskUsageContext contains disk usage specific information required by the formatter, encapsulate a Context struct.
|
||||
|
@ -59,7 +48,6 @@ func (ctx *DiskUsageContext) startSubsection(format string) (*template.Template,
|
|||
return ctx.parseFormat()
|
||||
}
|
||||
|
||||
//
|
||||
// NewDiskUsageFormat returns a format for rendering an DiskUsageContext
|
||||
func NewDiskUsageFormat(source string) Format {
|
||||
switch source {
|
||||
|
@ -132,6 +120,7 @@ func (ctx *DiskUsageContext) Write() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
// nolint: gocyclo
|
||||
func (ctx *DiskUsageContext) verboseWrite() error {
|
||||
// First images
|
||||
tmpl, err := ctx.startSubsection(defaultDiskUsageImageTableFormat)
|
||||
|
@ -199,11 +188,17 @@ func (ctx *DiskUsageContext) verboseWrite() error {
|
|||
// And build cache
|
||||
fmt.Fprintf(ctx.Output, "\nBuild cache usage: %s\n\n", units.HumanSize(float64(ctx.BuilderSize)))
|
||||
|
||||
t := template.Must(template.New("buildcache").Parse(defaultBuildCacheVerboseFormat))
|
||||
|
||||
for _, v := range ctx.BuildCache {
|
||||
t.Execute(ctx.Output, *v)
|
||||
tmpl, err = ctx.startSubsection(defaultDiskUsageBuildCacheTableFormat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buildCacheSort(ctx.BuildCache)
|
||||
for _, v := range ctx.BuildCache {
|
||||
if err := ctx.contextFormat(tmpl, &buildCacheContext{v: v, trunc: true}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
ctx.postFormat(tmpl, newBuildCacheContext())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -32,11 +32,11 @@ Build Cache 0 0 0B
|
|||
DiskUsageContext{Verbose: true},
|
||||
`Images space usage:
|
||||
|
||||
REPOSITORY TAG IMAGE ID CREATED ago SIZE SHARED SIZE UNIQUE SiZE CONTAINERS
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE SHARED SIZE UNIQUE SIZE CONTAINERS
|
||||
|
||||
Containers space usage:
|
||||
|
||||
CONTAINER ID IMAGE COMMAND LOCAL VOLUMES SIZE CREATED ago STATUS NAMES
|
||||
CONTAINER ID IMAGE COMMAND LOCAL VOLUMES SIZE CREATED STATUS NAMES
|
||||
|
||||
Local Volumes space usage:
|
||||
|
||||
|
@ -44,6 +44,7 @@ VOLUME NAME LINKS SIZE
|
|||
|
||||
Build cache usage: 0B
|
||||
|
||||
CACHE ID TYPE SIZE CREATED LAST USED USAGE SHARED
|
||||
`,
|
||||
},
|
||||
// Errors
|
||||
|
|
|
@ -52,13 +52,20 @@ func runDiskUsage(dockerCli command.Cli, opts diskUsageOptions) error {
|
|||
format = formatter.TableFormatKey
|
||||
}
|
||||
|
||||
var bsz int64
|
||||
for _, bc := range du.BuildCache {
|
||||
if !bc.Shared {
|
||||
bsz += bc.Size
|
||||
}
|
||||
}
|
||||
|
||||
duCtx := formatter.DiskUsageContext{
|
||||
Context: formatter.Context{
|
||||
Output: dockerCli.Out(),
|
||||
Format: formatter.NewDiskUsageFormat(format),
|
||||
},
|
||||
LayersSize: du.LayersSize,
|
||||
BuilderSize: du.BuilderSize,
|
||||
BuilderSize: bsz,
|
||||
BuildCache: du.BuildCache,
|
||||
Images: du.Images,
|
||||
Containers: du.Containers,
|
||||
|
|
Loading…
Reference in New Issue