Merge pull request #1370 from tiborvass/df-verbose-format-raw

system/df: allow -v with --format
This commit is contained in:
Vincent Demeester 2018-09-14 11:41:23 +02:00 committed by GitHub
commit a900ba8aef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 123 additions and 53 deletions

View File

@ -15,6 +15,7 @@ const (
defaultBuildCacheTableFormat = "table {{.ID}}\t{{.Type}}\t{{.Size}}\t{{.CreatedSince}}\t{{.LastUsedSince}}\t{{.UsageCount}}\t{{.Shared}}\t{{.Description}}" defaultBuildCacheTableFormat = "table {{.ID}}\t{{.Type}}\t{{.Size}}\t{{.CreatedSince}}\t{{.LastUsedSince}}\t{{.UsageCount}}\t{{.Shared}}\t{{.Description}}"
cacheIDHeader = "CACHE ID" cacheIDHeader = "CACHE ID"
cacheTypeHeader = "CACHE TYPE"
parentHeader = "PARENT" parentHeader = "PARENT"
lastUsedSinceHeader = "LAST USED" lastUsedSinceHeader = "LAST USED"
usageCountHeader = "USAGE" usageCountHeader = "USAGE"
@ -36,10 +37,12 @@ func NewBuildCacheFormat(source string, quiet bool) Format {
} }
format := `build_cache_id: {{.ID}} format := `build_cache_id: {{.ID}}
parent_id: {{.Parent}} parent_id: {{.Parent}}
type: {{.Type}} build_cache_type: {{.CacheType}}
description: {{.Description}} description: {{.Description}}
created_at: {{.CreatedSince}} created_at: {{.CreatedAt}}
last_used_at: {{.LastUsedSince}} created_since: {{.CreatedSince}}
last_used_at: {{.LastUsedAt}}
last_used_since: {{.LastUsedSince}}
usage_count: {{.UsageCount}} usage_count: {{.UsageCount}}
in_use: {{.InUse}} in_use: {{.InUse}}
shared: {{.Shared}} shared: {{.Shared}}
@ -95,7 +98,7 @@ func newBuildCacheContext() *buildCacheContext {
buildCacheCtx.header = buildCacheHeaderContext{ buildCacheCtx.header = buildCacheHeaderContext{
"ID": cacheIDHeader, "ID": cacheIDHeader,
"Parent": parentHeader, "Parent": parentHeader,
"Type": typeHeader, "CacheType": cacheTypeHeader,
"Size": sizeHeader, "Size": sizeHeader,
"CreatedSince": createdSinceHeader, "CreatedSince": createdSinceHeader,
"LastUsedSince": lastUsedSinceHeader, "LastUsedSince": lastUsedSinceHeader,
@ -129,7 +132,7 @@ func (c *buildCacheContext) Parent() string {
return c.v.Parent return c.v.Parent
} }
func (c *buildCacheContext) Type() string { func (c *buildCacheContext) CacheType() string {
return c.v.Type return c.v.Type
} }
@ -141,10 +144,21 @@ func (c *buildCacheContext) Size() string {
return units.HumanSizeWithPrecision(float64(c.v.Size), 3) return units.HumanSizeWithPrecision(float64(c.v.Size), 3)
} }
func (c *buildCacheContext) CreatedAt() string {
return c.v.CreatedAt.String()
}
func (c *buildCacheContext) CreatedSince() string { func (c *buildCacheContext) CreatedSince() string {
return units.HumanDuration(time.Now().UTC().Sub(c.v.CreatedAt)) + " ago" return units.HumanDuration(time.Now().UTC().Sub(c.v.CreatedAt)) + " ago"
} }
func (c *buildCacheContext) LastUsedAt() string {
if c.v.LastUsedAt == nil {
return ""
}
return c.v.LastUsedAt.String()
}
func (c *buildCacheContext) LastUsedSince() string { func (c *buildCacheContext) LastUsedSince() string {
if c.v.LastUsedAt == nil { if c.v.LastUsedAt == nil {
return "" return ""

View File

@ -15,8 +15,8 @@ const (
defaultDiskUsageImageTableFormat = "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.CreatedSince}}\t{{.VirtualSize}}\t{{.SharedSize}}\t{{.UniqueSize}}\t{{.Containers}}" 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}}" defaultDiskUsageContainerTableFormat = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.LocalVolumes}}\t{{.Size}}\t{{.RunningFor}}\t{{.Status}}\t{{.Names}}"
defaultDiskUsageVolumeTableFormat = "table {{.Name}}\t{{.Links}}\t{{.Size}}" defaultDiskUsageVolumeTableFormat = "table {{.Name}}\t{{.Links}}\t{{.Size}}"
defaultDiskUsageBuildCacheTableFormat = "table {{.ID}}\t{{.CacheType}}\t{{.Size}}\t{{.CreatedSince}}\t{{.LastUsedSince}}\t{{.UsageCount}}\t{{.Shared}}"
defaultDiskUsageTableFormat = "table {{.Type}}\t{{.TotalCount}}\t{{.Active}}\t{{.Size}}\t{{.Reclaimable}}" 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" typeHeader = "TYPE"
totalHeader = "TOTAL" totalHeader = "TOTAL"
@ -49,12 +49,25 @@ func (ctx *DiskUsageContext) startSubsection(format string) (*template.Template,
} }
// NewDiskUsageFormat returns a format for rendering an DiskUsageContext // NewDiskUsageFormat returns a format for rendering an DiskUsageContext
func NewDiskUsageFormat(source string) Format { func NewDiskUsageFormat(source string, verbose bool) Format {
switch source { switch {
case TableFormatKey: case verbose && source == RawFormatKey:
format := defaultDiskUsageTableFormat format := `{{range .Images}}type: Image
return Format(format) ` + NewImageFormat(source, false, true) + `
case RawFormatKey: {{end -}}
{{range .Containers}}type: Container
` + NewContainerFormat(source, false, true) + `
{{end -}}
{{range .Volumes}}type: Volume
` + NewVolumeFormat(source, false) + `
{{end -}}
{{range .BuildCache}}type: Build Cache
` + NewBuildCacheFormat(source, false) + `
{{end -}}`
return format
case !verbose && source == TableFormatKey:
return Format(defaultDiskUsageTableFormat)
case !verbose && source == RawFormatKey:
format := `type: {{.Type}} format := `type: {{.Type}}
total: {{.TotalCount}} total: {{.TotalCount}}
active: {{.Active}} active: {{.Active}}
@ -62,8 +75,9 @@ size: {{.Size}}
reclaimable: {{.Reclaimable}} reclaimable: {{.Reclaimable}}
` `
return Format(format) return Format(format)
default:
return Format(source)
} }
return Format(source)
} }
func (ctx *DiskUsageContext) Write() (err error) { func (ctx *DiskUsageContext) Write() (err error) {
@ -120,15 +134,23 @@ func (ctx *DiskUsageContext) Write() (err error) {
return err return err
} }
// nolint: gocyclo type diskUsageContext struct {
func (ctx *DiskUsageContext) verboseWrite() error { Images []*imageContext
// First images Containers []*containerContext
tmpl, err := ctx.startSubsection(defaultDiskUsageImageTableFormat) Volumes []*volumeContext
if err != nil { BuildCache []*buildCacheContext
return err }
}
ctx.Output.Write([]byte("Images space usage:\n\n")) func (ctx *DiskUsageContext) verboseWrite() error {
duc := &diskUsageContext{
Images: make([]*imageContext, 0, len(ctx.Images)),
Containers: make([]*containerContext, 0, len(ctx.Containers)),
Volumes: make([]*volumeContext, 0, len(ctx.Volumes)),
BuildCache: make([]*buildCacheContext, 0, len(ctx.BuildCache)),
}
trunc := ctx.Format.IsTable()
// First images
for _, i := range ctx.Images { for _, i := range ctx.Images {
repo := "<none>" repo := "<none>"
tag := "<none>" tag := "<none>"
@ -144,57 +166,88 @@ func (ctx *DiskUsageContext) verboseWrite() error {
} }
} }
err := ctx.contextFormat(tmpl, &imageContext{ duc.Images = append(duc.Images, &imageContext{
repo: repo, repo: repo,
tag: tag, tag: tag,
trunc: true, trunc: trunc,
i: *i, i: *i,
}) })
if err != nil { }
// Now containers
for _, c := range ctx.Containers {
// Don't display the virtual size
c.SizeRootFs = 0
duc.Containers = append(duc.Containers, &containerContext{trunc: trunc, c: *c})
}
// And volumes
for _, v := range ctx.Volumes {
duc.Volumes = append(duc.Volumes, &volumeContext{v: *v})
}
// And build cache
buildCacheSort(ctx.BuildCache)
for _, v := range ctx.BuildCache {
duc.BuildCache = append(duc.BuildCache, &buildCacheContext{v: v, trunc: trunc})
}
if ctx.Format == TableFormatKey {
return ctx.verboseWriteTable(duc)
}
ctx.preFormat()
tmpl, err := ctx.parseFormat()
if err != nil {
return err
}
return tmpl.Execute(ctx.Output, duc)
}
func (ctx *DiskUsageContext) verboseWriteTable(duc *diskUsageContext) error {
tmpl, err := ctx.startSubsection(defaultDiskUsageImageTableFormat)
if err != nil {
return err
}
ctx.Output.Write([]byte("Images space usage:\n\n"))
for _, img := range duc.Images {
if err := ctx.contextFormat(tmpl, img); err != nil {
return err return err
} }
} }
ctx.postFormat(tmpl, newImageContext()) ctx.postFormat(tmpl, newImageContext())
// Now containers
ctx.Output.Write([]byte("\nContainers space usage:\n\n"))
tmpl, err = ctx.startSubsection(defaultDiskUsageContainerTableFormat) tmpl, err = ctx.startSubsection(defaultDiskUsageContainerTableFormat)
if err != nil { if err != nil {
return err return err
} }
for _, c := range ctx.Containers { ctx.Output.Write([]byte("\nContainers space usage:\n\n"))
// Don't display the virtual size for _, c := range duc.Containers {
c.SizeRootFs = 0 if err := ctx.contextFormat(tmpl, c); err != nil {
err := ctx.contextFormat(tmpl, &containerContext{trunc: true, c: *c})
if err != nil {
return err return err
} }
} }
ctx.postFormat(tmpl, newContainerContext()) ctx.postFormat(tmpl, newContainerContext())
// And volumes
ctx.Output.Write([]byte("\nLocal Volumes space usage:\n\n"))
tmpl, err = ctx.startSubsection(defaultDiskUsageVolumeTableFormat) tmpl, err = ctx.startSubsection(defaultDiskUsageVolumeTableFormat)
if err != nil { if err != nil {
return err return err
} }
for _, v := range ctx.Volumes { ctx.Output.Write([]byte("\nLocal Volumes space usage:\n\n"))
if err := ctx.contextFormat(tmpl, &volumeContext{v: *v}); err != nil { for _, v := range duc.Volumes {
if err := ctx.contextFormat(tmpl, v); err != nil {
return err return err
} }
} }
ctx.postFormat(tmpl, newVolumeContext()) ctx.postFormat(tmpl, newVolumeContext())
// And build cache
fmt.Fprintf(ctx.Output, "\nBuild cache usage: %s\n\n", units.HumanSize(float64(ctx.BuilderSize)))
tmpl, err = ctx.startSubsection(defaultDiskUsageBuildCacheTableFormat) tmpl, err = ctx.startSubsection(defaultDiskUsageBuildCacheTableFormat)
if err != nil { if err != nil {
return err return err
} }
buildCacheSort(ctx.BuildCache) fmt.Fprintf(ctx.Output, "\nBuild cache usage: %s\n\n", units.HumanSize(float64(ctx.BuilderSize)))
for _, v := range ctx.BuildCache { for _, v := range duc.BuildCache {
if err := ctx.contextFormat(tmpl, &buildCacheContext{v: v, trunc: true}); err != nil { if err := ctx.contextFormat(tmpl, v); err != nil {
return err return err
} }
} }

View File

@ -18,7 +18,7 @@ func TestDiskUsageContextFormatWrite(t *testing.T) {
{ {
DiskUsageContext{ DiskUsageContext{
Context: Context{ Context: Context{
Format: NewDiskUsageFormat("table"), Format: NewDiskUsageFormat("table", false),
}, },
Verbose: false}, Verbose: false},
`TYPE TOTAL ACTIVE SIZE RECLAIMABLE `TYPE TOTAL ACTIVE SIZE RECLAIMABLE
@ -29,7 +29,7 @@ Build Cache 0 0 0B
`, `,
}, },
{ {
DiskUsageContext{Verbose: true}, DiskUsageContext{Verbose: true, Context: Context{Format: NewDiskUsageFormat("table", true)}},
`Images space usage: `Images space usage:
REPOSITORY TAG IMAGE ID CREATED SIZE SHARED SIZE UNIQUE SIZE CONTAINERS REPOSITORY TAG IMAGE ID CREATED SIZE SHARED SIZE UNIQUE SIZE CONTAINERS
@ -44,9 +44,17 @@ VOLUME NAME LINKS SIZE
Build cache usage: 0B Build cache usage: 0B
CACHE ID TYPE SIZE CREATED LAST USED USAGE SHARED CACHE ID CACHE TYPE SIZE CREATED LAST USED USAGE SHARED
`, `,
}, },
{
DiskUsageContext{Verbose: true, Context: Context{Format: NewDiskUsageFormat("raw", true)}},
``,
},
{
DiskUsageContext{Verbose: true, Context: Context{Format: NewDiskUsageFormat("{{json .}}", true)}},
`{"Images":[],"Containers":[],"Volumes":[],"BuildCache":[]}`,
},
// Errors // Errors
{ {
DiskUsageContext{ DiskUsageContext{
@ -70,7 +78,7 @@ CACHE ID TYPE SIZE CREATED
{ {
DiskUsageContext{ DiskUsageContext{
Context: Context{ Context: Context{
Format: NewDiskUsageFormat("table"), Format: NewDiskUsageFormat("table", false),
}, },
}, },
`TYPE TOTAL ACTIVE SIZE RECLAIMABLE `TYPE TOTAL ACTIVE SIZE RECLAIMABLE
@ -83,7 +91,7 @@ Build Cache 0 0 0B
{ {
DiskUsageContext{ DiskUsageContext{
Context: Context{ Context: Context{
Format: NewDiskUsageFormat("table {{.Type}}\t{{.Active}}"), Format: NewDiskUsageFormat("table {{.Type}}\t{{.Active}}", false),
}, },
}, },
string(golden.Get(t, "disk-usage-context-write-custom.golden")), string(golden.Get(t, "disk-usage-context-write-custom.golden")),
@ -92,7 +100,7 @@ Build Cache 0 0 0B
{ {
DiskUsageContext{ DiskUsageContext{
Context: Context{ Context: Context{
Format: NewDiskUsageFormat("raw"), Format: NewDiskUsageFormat("raw", false),
}, },
}, },
string(golden.Get(t, "disk-usage-raw-format.golden")), string(golden.Get(t, "disk-usage-raw-format.golden")),

View File

@ -2,7 +2,6 @@ package system
import ( import (
"context" "context"
"errors"
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
@ -38,10 +37,6 @@ func newDiskUsageCommand(dockerCli command.Cli) *cobra.Command {
} }
func runDiskUsage(dockerCli command.Cli, opts diskUsageOptions) error { func runDiskUsage(dockerCli command.Cli, opts diskUsageOptions) error {
if opts.verbose && len(opts.format) != 0 {
return errors.New("the verbose and the format options conflict")
}
du, err := dockerCli.Client().DiskUsage(context.Background()) du, err := dockerCli.Client().DiskUsage(context.Background())
if err != nil { if err != nil {
return err return err
@ -62,7 +57,7 @@ func runDiskUsage(dockerCli command.Cli, opts diskUsageOptions) error {
duCtx := formatter.DiskUsageContext{ duCtx := formatter.DiskUsageContext{
Context: formatter.Context{ Context: formatter.Context{
Output: dockerCli.Out(), Output: dockerCli.Out(),
Format: formatter.NewDiskUsageFormat(format), Format: formatter.NewDiskUsageFormat(format, opts.verbose),
}, },
LayersSize: du.LayersSize, LayersSize: du.LayersSize,
BuilderSize: bsz, BuilderSize: bsz,