Skip to content

Commit

Permalink
formatter package heavy refactoring
Browse files Browse the repository at this point in the history
- make it possible to extract the formatter implementation from the
  "common" code, that way, the formatter package stays small
- extract some formatter into their own packages

This is essentially moving the "formatter" implementation of each type
in their respective packages. The *main* reason to do that, is to be
able to depend on `cli/command/formatter` without depending of the
implementation detail of the formatter. As of now, depending on
`cli/command/formatter` means we depend on `docker/docker/api/types`,
`docker/licensing`, … — that should not be the case. `formatter`
should hold the common code (or helpers) to easily create formatter,
not all formatter implementations.

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
  • Loading branch information
vdemeester committed Oct 23, 2018
1 parent ea836ab commit 69fdd2a
Show file tree
Hide file tree
Showing 75 changed files with 750 additions and 711 deletions.
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
package formatter
package checkpoint

import "github.com/docker/docker/api/types"
import (
"github.com/docker/cli/cli/command/formatter"
"github.com/docker/docker/api/types"
)

const (
defaultCheckpointFormat = "table {{.Name}}"

checkpointNameHeader = "CHECKPOINT NAME"
)

// NewCheckpointFormat returns a format for use with a checkpoint Context
func NewCheckpointFormat(source string) Format {
// NewFormat returns a format for use with a checkpoint Context
func NewFormat(source string) formatter.Format {
switch source {
case TableFormatKey:
case formatter.TableFormatKey:
return defaultCheckpointFormat
}
return Format(source)
return formatter.Format(source)
}

// CheckpointWrite writes formatted checkpoints using the Context
func CheckpointWrite(ctx Context, checkpoints []types.Checkpoint) error {
render := func(format func(subContext subContext) error) error {
// FormatWrite writes formatted checkpoints using the Context
func FormatWrite(ctx formatter.Context, checkpoints []types.Checkpoint) error {
render := func(format func(subContext formatter.SubContext) error) error {
for _, checkpoint := range checkpoints {
if err := format(&checkpointContext{c: checkpoint}); err != nil {
return err
Expand All @@ -31,20 +34,20 @@ func CheckpointWrite(ctx Context, checkpoints []types.Checkpoint) error {
}

type checkpointContext struct {
HeaderContext
formatter.HeaderContext
c types.Checkpoint
}

func newCheckpointContext() *checkpointContext {
cpCtx := checkpointContext{}
cpCtx.header = volumeHeaderContext{
cpCtx.Header = formatter.SubHeaderContext{
"Name": checkpointNameHeader,
}
return &cpCtx
}

func (c *checkpointContext) MarshalJSON() ([]byte, error) {
return marshalJSON(c)
return formatter.MarshalJSON(c)
}

func (c *checkpointContext) Name() string {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,36 @@
package formatter
package checkpoint

import (
"bytes"
"testing"

"github.com/docker/cli/cli/command/formatter"
"github.com/docker/docker/api/types"
"gotest.tools/assert"
)

func TestCheckpointContextFormatWrite(t *testing.T) {
cases := []struct {
context Context
context formatter.Context
expected string
}{
{
Context{Format: NewCheckpointFormat(defaultCheckpointFormat)},
formatter.Context{Format: NewFormat(defaultCheckpointFormat)},
`CHECKPOINT NAME
checkpoint-1
checkpoint-2
checkpoint-3
`,
},
{
Context{Format: NewCheckpointFormat("{{.Name}}")},
formatter.Context{Format: NewFormat("{{.Name}}")},
`checkpoint-1
checkpoint-2
checkpoint-3
`,
},
{
Context{Format: NewCheckpointFormat("{{.Name}}:")},
formatter.Context{Format: NewFormat("{{.Name}}:")},
`checkpoint-1:
checkpoint-2:
checkpoint-3:
Expand All @@ -45,7 +46,7 @@ checkpoint-3:
for _, testcase := range cases {
out := bytes.NewBufferString("")
testcase.context.Output = out
err := CheckpointWrite(testcase.context, checkpoints)
err := FormatWrite(testcase.context, checkpoints)
assert.NilError(t, err)
assert.Equal(t, out.String(), testcase.expected)
}
Expand Down
4 changes: 2 additions & 2 deletions cli/command/checkpoint/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func runList(dockerCli command.Cli, container string, opts listOptions) error {

cpCtx := formatter.Context{
Output: dockerCli.Out(),
Format: formatter.NewCheckpointFormat(formatter.TableFormatKey),
Format: NewFormat(formatter.TableFormatKey),
}
return formatter.CheckpointWrite(cpCtx, checkpoints)
return FormatWrite(cpCtx, checkpoints)
}
49 changes: 25 additions & 24 deletions cli/command/formatter/config.go → cli/command/config/formatter.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
package formatter
package config

import (
"fmt"
"strings"
"time"

"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter"
"github.com/docker/cli/cli/command/inspect"
"github.com/docker/docker/api/types/swarm"
units "github.com/docker/go-units"
)

const (
defaultConfigTableFormat = "table {{.ID}}\t{{.Name}}\t{{.CreatedAt}}\t{{.UpdatedAt}}"
configIDHeader = "ID"
configCreatedHeader = "CREATED"
configUpdatedHeader = "UPDATED"
configInspectPrettyTemplate Format = `ID: {{.ID}}
defaultConfigTableFormat = "table {{.ID}}\t{{.Name}}\t{{.CreatedAt}}\t{{.UpdatedAt}}"
configIDHeader = "ID"
configCreatedHeader = "CREATED"
configUpdatedHeader = "UPDATED"
configInspectPrettyTemplate formatter.Format = `ID: {{.ID}}
Name: {{.Name}}
{{- if .Labels }}
Labels:
Expand All @@ -29,23 +30,23 @@ Data:
{{.Data}}`
)

// NewConfigFormat returns a Format for rendering using a config Context
func NewConfigFormat(source string, quiet bool) Format {
// NewFormat returns a Format for rendering using a config Context
func NewFormat(source string, quiet bool) formatter.Format {
switch source {
case PrettyFormatKey:
case formatter.PrettyFormatKey:
return configInspectPrettyTemplate
case TableFormatKey:
case formatter.TableFormatKey:
if quiet {
return defaultQuietFormat
return formatter.DefaultQuietFormat
}
return defaultConfigTableFormat
}
return Format(source)
return formatter.Format(source)
}

// ConfigWrite writes the context
func ConfigWrite(ctx Context, configs []swarm.Config) error {
render := func(format func(subContext subContext) error) error {
// FormatWrite writes the context
func FormatWrite(ctx formatter.Context, configs []swarm.Config) error {
render := func(format func(subContext formatter.SubContext) error) error {
for _, config := range configs {
configCtx := &configContext{c: config}
if err := format(configCtx); err != nil {
Expand All @@ -60,23 +61,23 @@ func ConfigWrite(ctx Context, configs []swarm.Config) error {
func newConfigContext() *configContext {
cCtx := &configContext{}

cCtx.header = map[string]string{
cCtx.Header = formatter.SubHeaderContext{
"ID": configIDHeader,
"Name": nameHeader,
"Name": formatter.NameHeader,
"CreatedAt": configCreatedHeader,
"UpdatedAt": configUpdatedHeader,
"Labels": labelsHeader,
"Labels": formatter.LabelsHeader,
}
return cCtx
}

type configContext struct {
HeaderContext
formatter.HeaderContext
c swarm.Config
}

func (c *configContext) MarshalJSON() ([]byte, error) {
return marshalJSON(c)
return formatter.MarshalJSON(c)
}

func (c *configContext) ID() string {
Expand Down Expand Up @@ -114,12 +115,12 @@ func (c *configContext) Label(name string) string {
return c.c.Spec.Annotations.Labels[name]
}

// ConfigInspectWrite renders the context for a list of configs
func ConfigInspectWrite(ctx Context, refs []string, getRef inspect.GetRefFunc) error {
// InspectFormatWrite renders the context for a list of configs
func InspectFormatWrite(ctx formatter.Context, refs []string, getRef inspect.GetRefFunc) error {
if ctx.Format != configInspectPrettyTemplate {
return inspect.Inspect(ctx.Output, refs, string(ctx.Format), getRef)
}
render := func(format func(subContext subContext) error) error {
render := func(format func(subContext formatter.SubContext) error) error {
for _, ref := range refs {
configI, _, err := getRef(ref)
if err != nil {
Expand All @@ -140,7 +141,7 @@ func ConfigInspectWrite(ctx Context, refs []string, getRef inspect.GetRefFunc) e

type configInspectContext struct {
swarm.Config
subContext
formatter.SubContext
}

func (ctx *configInspectContext) ID() string {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package formatter
package config

import (
"bytes"
"testing"
"time"

"github.com/docker/cli/cli/command/formatter"
"github.com/docker/docker/api/types/swarm"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
Expand All @@ -13,32 +14,32 @@ import (
func TestConfigContextFormatWrite(t *testing.T) {
// Check default output format (verbose and non-verbose mode) for table headers
cases := []struct {
context Context
context formatter.Context
expected string
}{
// Errors
{
Context{Format: "{{InvalidFunction}}"},
formatter.Context{Format: "{{InvalidFunction}}"},
`Template parsing error: template: :1: function "InvalidFunction" not defined
`,
},
{
Context{Format: "{{nil}}"},
formatter.Context{Format: "{{nil}}"},
`Template parsing error: template: :1:2: executing "" at <nil>: nil is not a command
`,
},
// Table format
{Context{Format: NewConfigFormat("table", false)},
{formatter.Context{Format: NewFormat("table", false)},
`ID NAME CREATED UPDATED
1 passwords Less than a second ago Less than a second ago
2 id_rsa Less than a second ago Less than a second ago
`},
{Context{Format: NewConfigFormat("table {{.Name}}", true)},
{formatter.Context{Format: NewFormat("table {{.Name}}", true)},
`NAME
passwords
id_rsa
`},
{Context{Format: NewConfigFormat("{{.ID}}-{{.Name}}", false)},
{formatter.Context{Format: NewFormat("{{.ID}}-{{.Name}}", false)},
`1-passwords
2-id_rsa
`},
Expand All @@ -55,7 +56,7 @@ id_rsa
for _, testcase := range cases {
out := bytes.NewBufferString("")
testcase.context.Output = out
if err := ConfigWrite(testcase.context, configs); err != nil {
if err := FormatWrite(testcase.context, configs); err != nil {
assert.ErrorContains(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(out.String(), testcase.expected))
Expand Down
4 changes: 2 additions & 2 deletions cli/command/config/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ func runConfigInspect(dockerCli command.Cli, opts inspectOptions) error {

configCtx := formatter.Context{
Output: dockerCli.Out(),
Format: formatter.NewConfigFormat(f, false),
Format: NewFormat(f, false),
}

if err := formatter.ConfigInspectWrite(configCtx, opts.names, getRef); err != nil {
if err := InspectFormatWrite(configCtx, opts.names, getRef); err != nil {
return cli.StatusError{StatusCode: 1, Status: err.Error()}
}
return nil
Expand Down
4 changes: 2 additions & 2 deletions cli/command/config/ls.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func runConfigList(dockerCli command.Cli, options listOptions) error {

configCtx := formatter.Context{
Output: dockerCli.Out(),
Format: formatter.NewConfigFormat(format, options.quiet),
Format: NewFormat(format, options.quiet),
}
return formatter.ConfigWrite(configCtx, configs)
return FormatWrite(configCtx, configs)
}
4 changes: 2 additions & 2 deletions cli/command/container/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func runDiff(dockerCli command.Cli, opts *diffOptions) error {
}
diffCtx := formatter.Context{
Output: dockerCli.Out(),
Format: formatter.NewDiffFormat("{{.Type}} {{.Path}}"),
Format: NewDiffFormat("{{.Type}} {{.Path}}"),
}
return formatter.DiffWrite(diffCtx, changes)
return DiffFormatWrite(diffCtx, changes)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package formatter
package container

import (
"github.com/docker/cli/cli/command/formatter"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/archive"
)
Expand All @@ -13,18 +14,18 @@ const (
)

// NewDiffFormat returns a format for use with a diff Context
func NewDiffFormat(source string) Format {
func NewDiffFormat(source string) formatter.Format {
switch source {
case TableFormatKey:
case formatter.TableFormatKey:
return defaultDiffTableFormat
}
return Format(source)
return formatter.Format(source)
}

// DiffWrite writes formatted diff using the Context
func DiffWrite(ctx Context, changes []container.ContainerChangeResponseItem) error {
// DiffFormatWrite writes formatted diff using the Context
func DiffFormatWrite(ctx formatter.Context, changes []container.ContainerChangeResponseItem) error {

render := func(format func(subContext subContext) error) error {
render := func(format func(subContext formatter.SubContext) error) error {
for _, change := range changes {
if err := format(&diffContext{c: change}); err != nil {
return err
Expand All @@ -36,21 +37,21 @@ func DiffWrite(ctx Context, changes []container.ContainerChangeResponseItem) err
}

type diffContext struct {
HeaderContext
formatter.HeaderContext
c container.ContainerChangeResponseItem
}

func newDiffContext() *diffContext {
diffCtx := diffContext{}
diffCtx.header = map[string]string{
diffCtx.Header = formatter.SubHeaderContext{
"Type": changeTypeHeader,
"Path": pathHeader,
}
return &diffCtx
}

func (d *diffContext) MarshalJSON() ([]byte, error) {
return marshalJSON(d)
return formatter.MarshalJSON(d)
}

func (d *diffContext) Type() string {
Expand Down
Loading

0 comments on commit 69fdd2a

Please sign in to comment.