From e3903a1ac8722714f8413ccdd28f4bb03b2cde0d Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 21 Aug 2025 13:46:16 +0200 Subject: [PATCH 01/11] cli/command/network: deprecate NewFormat, FormatWrite It's part of the presentation logic of the cli, and only used internally. We can consider providing utilities for these, but better as part of separate packages. Signed-off-by: Sebastiaan van Stijn --- cli/command/network/formatter.go | 22 ++++++++++++++++++---- cli/command/network/formatter_test.go | 22 +++++++++++----------- cli/command/network/list.go | 4 ++-- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/cli/command/network/formatter.go b/cli/command/network/formatter.go index b27195af4c..59f97060cf 100644 --- a/cli/command/network/formatter.go +++ b/cli/command/network/formatter.go @@ -17,8 +17,15 @@ const ( internalHeader = "INTERNAL" ) -// NewFormat returns a Format for rendering using a network Context +// NewFormat returns a Format for rendering using a network Context. +// +// Deprecated: this function was only used internally and will be removed in the next release. func NewFormat(source string, quiet bool) formatter.Format { + return newFormat(source, quiet) +} + +// newFormat returns a [formatter.Format] for rendering a networkContext. +func newFormat(source string, quiet bool) formatter.Format { switch source { case formatter.TableFormatKey: if quiet { @@ -35,10 +42,17 @@ func NewFormat(source string, quiet bool) formatter.Format { } // FormatWrite writes the context -func FormatWrite(ctx formatter.Context, networks []network.Summary) error { +// +// Deprecated: this function was only used internally and will be removed in the next release. +func FormatWrite(fmtCtx formatter.Context, networks []network.Summary) error { + return formatWrite(fmtCtx, networks) +} + +// formatWrite writes the context. +func formatWrite(fmtCtx formatter.Context, networks []network.Summary) error { render := func(format func(subContext formatter.SubContext) error) error { for _, nw := range networks { - networkCtx := &networkContext{trunc: ctx.Trunc, n: nw} + networkCtx := &networkContext{trunc: fmtCtx.Trunc, n: nw} if err := format(networkCtx); err != nil { return err } @@ -57,7 +71,7 @@ func FormatWrite(ctx formatter.Context, networks []network.Summary) error { "Labels": formatter.LabelsHeader, "CreatedAt": formatter.CreatedAtHeader, } - return ctx.Write(&networkCtx, render) + return fmtCtx.Write(&networkCtx, render) } type networkContext struct { diff --git a/cli/command/network/formatter_test.go b/cli/command/network/formatter_test.go index ccf8255715..152c94c26d 100644 --- a/cli/command/network/formatter_test.go +++ b/cli/command/network/formatter_test.go @@ -91,27 +91,27 @@ func TestNetworkContextWrite(t *testing.T) { }, // Table format { - formatter.Context{Format: NewFormat("table", false)}, + formatter.Context{Format: newFormat("table", false)}, `NETWORK ID NAME DRIVER SCOPE networkID1 foobar_baz foo local networkID2 foobar_bar bar local `, }, { - formatter.Context{Format: NewFormat("table", true)}, + formatter.Context{Format: newFormat("table", true)}, `networkID1 networkID2 `, }, { - formatter.Context{Format: NewFormat("table {{.Name}}", false)}, + formatter.Context{Format: newFormat("table {{.Name}}", false)}, `NAME foobar_baz foobar_bar `, }, { - formatter.Context{Format: NewFormat("table {{.Name}}", true)}, + formatter.Context{Format: newFormat("table {{.Name}}", true)}, `NAME foobar_baz foobar_bar @@ -119,7 +119,7 @@ foobar_bar }, // Raw Format { - formatter.Context{Format: NewFormat("raw", false)}, + formatter.Context{Format: newFormat("raw", false)}, `network_id: networkID1 name: foobar_baz driver: foo @@ -133,21 +133,21 @@ scope: local `, }, { - formatter.Context{Format: NewFormat("raw", true)}, + formatter.Context{Format: newFormat("raw", true)}, `network_id: networkID1 network_id: networkID2 `, }, // Custom Format { - formatter.Context{Format: NewFormat("{{.Name}}", false)}, + formatter.Context{Format: newFormat("{{.Name}}", false)}, `foobar_baz foobar_bar `, }, // Custom Format with CreatedAt { - formatter.Context{Format: NewFormat("{{.Name}} {{.CreatedAt}}", false)}, + formatter.Context{Format: newFormat("{{.Name}} {{.CreatedAt}}", false)}, `foobar_baz 2016-01-01 00:00:00 +0000 UTC foobar_bar 2017-01-01 00:00:00 +0000 UTC `, @@ -166,7 +166,7 @@ foobar_bar 2017-01-01 00:00:00 +0000 UTC t.Run(string(tc.context.Format), func(t *testing.T) { var out bytes.Buffer tc.context.Output = &out - err := FormatWrite(tc.context, networks) + err := formatWrite(tc.context, networks) if err != nil { assert.Error(t, err, tc.expected) } else { @@ -187,7 +187,7 @@ func TestNetworkContextWriteJSON(t *testing.T) { } out := bytes.NewBufferString("") - err := FormatWrite(formatter.Context{Format: "{{json .}}", Output: out}, networks) + err := formatWrite(formatter.Context{Format: "{{json .}}", Output: out}, networks) if err != nil { t.Fatal(err) } @@ -206,7 +206,7 @@ func TestNetworkContextWriteJSONField(t *testing.T) { {ID: "networkID2", Name: "foobar_bar"}, } out := bytes.NewBufferString("") - err := FormatWrite(formatter.Context{Format: "{{json .ID}}", Output: out}, networks) + err := formatWrite(formatter.Context{Format: "{{json .ID}}", Output: out}, networks) if err != nil { t.Fatal(err) } diff --git a/cli/command/network/list.go b/cli/command/network/list.go index cfceecee2b..01aa33bc15 100644 --- a/cli/command/network/list.go +++ b/cli/command/network/list.go @@ -67,8 +67,8 @@ func runList(ctx context.Context, dockerCli command.Cli, options listOptions) er networksCtx := formatter.Context{ Output: dockerCli.Out(), - Format: NewFormat(format, options.quiet), + Format: newFormat(format, options.quiet), Trunc: !options.noTrunc, } - return FormatWrite(networksCtx, networkResources) + return formatWrite(networksCtx, networkResources) } From 15cf4fa912cc6319110065d4f8c83cc6517ca8b2 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 21 Aug 2025 14:01:22 +0200 Subject: [PATCH 02/11] cli/command/image: deprecate NewHistoryFormat, HistoryWrite It's part of the presentation logic of the cli, and only used internally. We can consider providing utilities for these, but better as part of separate packages. Signed-off-by: Sebastiaan van Stijn --- cli/command/image/formatter_history.go | 20 +++++++++++++++++--- cli/command/image/formatter_history_test.go | 6 +++--- cli/command/image/history.go | 4 ++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/cli/command/image/formatter_history.go b/cli/command/image/formatter_history.go index 6832276afe..9d6d243fa0 100644 --- a/cli/command/image/formatter_history.go +++ b/cli/command/image/formatter_history.go @@ -20,7 +20,14 @@ const ( ) // NewHistoryFormat returns a format for rendering an HistoryContext +// +// Deprecated: this function was only used internally and will be removed in the next release. func NewHistoryFormat(source string, quiet bool, human bool) formatter.Format { + return newHistoryFormat(source, quiet, human) +} + +// newHistoryFormat returns a format for rendering a historyContext. +func newHistoryFormat(source string, quiet bool, human bool) formatter.Format { if source == formatter.TableFormatKey { switch { case quiet: @@ -36,10 +43,17 @@ func NewHistoryFormat(source string, quiet bool, human bool) formatter.Format { } // HistoryWrite writes the context -func HistoryWrite(ctx formatter.Context, human bool, histories []image.HistoryResponseItem) error { +// +// Deprecated: this function was only used internally and will be removed in the next release. +func HistoryWrite(fmtCtx formatter.Context, human bool, histories []image.HistoryResponseItem) error { + return historyWrite(fmtCtx, human, histories) +} + +// historyWrite writes the context +func historyWrite(fmtCtx formatter.Context, human bool, histories []image.HistoryResponseItem) error { render := func(format func(subContext formatter.SubContext) error) error { for _, history := range histories { - historyCtx := &historyContext{trunc: ctx.Trunc, h: history, human: human} + historyCtx := &historyContext{trunc: fmtCtx.Trunc, h: history, human: human} if err := format(historyCtx); err != nil { return err } @@ -55,7 +69,7 @@ func HistoryWrite(ctx formatter.Context, human bool, histories []image.HistoryRe "Size": formatter.SizeHeader, "Comment": commentHeader, } - return ctx.Write(historyCtx, render) + return fmtCtx.Write(historyCtx, render) } type historyContext struct { diff --git a/cli/command/image/formatter_history_test.go b/cli/command/image/formatter_history_test.go index 3405b5250c..babcac348b 100644 --- a/cli/command/image/formatter_history_test.go +++ b/cli/command/image/formatter_history_test.go @@ -237,7 +237,7 @@ imageID6 17 years ago /bin/bash echo 183MB }{ { formatter.Context{ - Format: NewHistoryFormat("table", false, true), + Format: newHistoryFormat("table", false, true), Trunc: true, Output: out, }, @@ -245,7 +245,7 @@ imageID6 17 years ago /bin/bash echo 183MB }, { formatter.Context{ - Format: NewHistoryFormat("table", false, true), + Format: newHistoryFormat("table", false, true), Trunc: false, Output: out, }, @@ -255,7 +255,7 @@ imageID6 17 years ago /bin/bash echo 183MB for _, tc := range cases { t.Run(string(tc.context.Format), func(t *testing.T) { - err := HistoryWrite(tc.context, true, histories) + err := historyWrite(tc.context, true, histories) assert.NilError(t, err) assert.Equal(t, out.String(), tc.expected) // Clean buffer diff --git a/cli/command/image/history.go b/cli/command/image/history.go index 61c716bde2..2214f818e6 100644 --- a/cli/command/image/history.go +++ b/cli/command/image/history.go @@ -77,8 +77,8 @@ func runHistory(ctx context.Context, dockerCli command.Cli, opts historyOptions) historyCtx := formatter.Context{ Output: dockerCli.Out(), - Format: NewHistoryFormat(format, opts.quiet, opts.human), + Format: newHistoryFormat(format, opts.quiet, opts.human), Trunc: !opts.noTrunc, } - return HistoryWrite(historyCtx, opts.human, history) + return historyWrite(historyCtx, opts.human, history) } From d861b78a8ac4d98d3c814b798b84e43ce991d26b Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 21 Aug 2025 14:12:01 +0200 Subject: [PATCH 03/11] cli/command/checkpoint: deprecate NewFormat, FormatWrite It's part of the presentation logic of the cli, and only used internally. We can consider providing utilities for these, but better as part of separate packages. Signed-off-by: Sebastiaan van Stijn --- cli/command/checkpoint/formatter.go | 18 ++++++++++++++++-- cli/command/checkpoint/formatter_test.go | 8 ++++---- cli/command/checkpoint/list.go | 4 ++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/cli/command/checkpoint/formatter.go b/cli/command/checkpoint/formatter.go index 3ec69c20cf..10706343a5 100644 --- a/cli/command/checkpoint/formatter.go +++ b/cli/command/checkpoint/formatter.go @@ -11,7 +11,14 @@ const ( ) // NewFormat returns a format for use with a checkpoint Context +// +// Deprecated: this function was only used internally and will be removed in the next release. func NewFormat(source string) formatter.Format { + return newFormat(source) +} + +// newFormat returns a format for use with a checkpointContext. +func newFormat(source string) formatter.Format { if source == formatter.TableFormatKey { return defaultCheckpointFormat } @@ -19,7 +26,14 @@ func NewFormat(source string) formatter.Format { } // FormatWrite writes formatted checkpoints using the Context -func FormatWrite(ctx formatter.Context, checkpoints []checkpoint.Summary) error { +// +// Deprecated: this function was only used internally and will be removed in the next release. +func FormatWrite(fmtCtx formatter.Context, checkpoints []checkpoint.Summary) error { + return formatWrite(fmtCtx, checkpoints) +} + +// formatWrite writes formatted checkpoints using the Context +func formatWrite(fmtCtx formatter.Context, checkpoints []checkpoint.Summary) error { render := func(format func(subContext formatter.SubContext) error) error { for _, cp := range checkpoints { if err := format(&checkpointContext{c: cp}); err != nil { @@ -28,7 +42,7 @@ func FormatWrite(ctx formatter.Context, checkpoints []checkpoint.Summary) error } return nil } - return ctx.Write(newCheckpointContext(), render) + return fmtCtx.Write(newCheckpointContext(), render) } type checkpointContext struct { diff --git a/cli/command/checkpoint/formatter_test.go b/cli/command/checkpoint/formatter_test.go index 18100f4c53..5704fa45b9 100644 --- a/cli/command/checkpoint/formatter_test.go +++ b/cli/command/checkpoint/formatter_test.go @@ -15,7 +15,7 @@ func TestCheckpointContextFormatWrite(t *testing.T) { expected string }{ { - formatter.Context{Format: NewFormat(defaultCheckpointFormat)}, + formatter.Context{Format: newFormat(defaultCheckpointFormat)}, `CHECKPOINT NAME checkpoint-1 checkpoint-2 @@ -23,14 +23,14 @@ checkpoint-3 `, }, { - formatter.Context{Format: NewFormat("{{.Name}}")}, + formatter.Context{Format: newFormat("{{.Name}}")}, `checkpoint-1 checkpoint-2 checkpoint-3 `, }, { - formatter.Context{Format: NewFormat("{{.Name}}:")}, + formatter.Context{Format: newFormat("{{.Name}}:")}, `checkpoint-1: checkpoint-2: checkpoint-3: @@ -41,7 +41,7 @@ checkpoint-3: for _, testcase := range cases { out := bytes.NewBufferString("") testcase.context.Output = out - err := FormatWrite(testcase.context, []checkpoint.Summary{ + err := formatWrite(testcase.context, []checkpoint.Summary{ {Name: "checkpoint-1"}, {Name: "checkpoint-2"}, {Name: "checkpoint-3"}, diff --git a/cli/command/checkpoint/list.go b/cli/command/checkpoint/list.go index 818e8ee026..af954c6d37 100644 --- a/cli/command/checkpoint/list.go +++ b/cli/command/checkpoint/list.go @@ -45,7 +45,7 @@ func runList(ctx context.Context, dockerCli command.Cli, container string, opts cpCtx := formatter.Context{ Output: dockerCli.Out(), - Format: NewFormat(formatter.TableFormatKey), + Format: newFormat(formatter.TableFormatKey), } - return FormatWrite(cpCtx, checkpoints) + return formatWrite(cpCtx, checkpoints) } From e626f778ec6e2f5b38c5a87f307e94331c5acf0c Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 21 Aug 2025 14:21:56 +0200 Subject: [PATCH 04/11] cli/command/config: deprecate NewFormat, FormatWrite, InspectFormatWrite It's part of the presentation logic of the cli, and only used internally. We can consider providing utilities for these, but better as part of separate packages. Signed-off-by: Sebastiaan van Stijn --- cli/command/config/formatter.go | 33 +++++++++++++++++++++++----- cli/command/config/formatter_test.go | 8 +++---- cli/command/config/inspect.go | 4 ++-- cli/command/config/ls.go | 4 ++-- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/cli/command/config/formatter.go b/cli/command/config/formatter.go index b08994bf50..046a6e6346 100644 --- a/cli/command/config/formatter.go +++ b/cli/command/config/formatter.go @@ -30,7 +30,14 @@ Data: ) // NewFormat returns a Format for rendering using a config Context +// +// Deprecated: this function was only used internally and will be removed in the next release. func NewFormat(source string, quiet bool) formatter.Format { + return newFormat(source, quiet) +} + +// newFormat returns a Format for rendering using a configContext. +func newFormat(source string, quiet bool) formatter.Format { switch source { case formatter.PrettyFormatKey: return configInspectPrettyTemplate @@ -44,7 +51,14 @@ func NewFormat(source string, quiet bool) formatter.Format { } // FormatWrite writes the context -func FormatWrite(ctx formatter.Context, configs []swarm.Config) error { +// +// Deprecated: this function was only used internally and will be removed in the next release. +func FormatWrite(fmtCtx formatter.Context, configs []swarm.Config) error { + return formatWrite(fmtCtx, configs) +} + +// formatWrite writes the context +func formatWrite(fmtCtx formatter.Context, configs []swarm.Config) error { render := func(format func(subContext formatter.SubContext) error) error { for _, config := range configs { configCtx := &configContext{c: config} @@ -54,7 +68,7 @@ func FormatWrite(ctx formatter.Context, configs []swarm.Config) error { } return nil } - return ctx.Write(newConfigContext(), render) + return fmtCtx.Write(newConfigContext(), render) } func newConfigContext() *configContext { @@ -115,9 +129,16 @@ func (c *configContext) Label(name string) string { } // 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) +// +// Deprecated: this function was only used internally and will be removed in the next release. +func InspectFormatWrite(fmtCtx formatter.Context, refs []string, getRef inspect.GetRefFunc) error { + return inspectFormatWrite(fmtCtx, refs, getRef) +} + +// inspectFormatWrite renders the context for a list of configs +func inspectFormatWrite(fmtCtx formatter.Context, refs []string, getRef inspect.GetRefFunc) error { + if fmtCtx.Format != configInspectPrettyTemplate { + return inspect.Inspect(fmtCtx.Output, refs, string(fmtCtx.Format), getRef) } render := func(format func(subContext formatter.SubContext) error) error { for _, ref := range refs { @@ -135,7 +156,7 @@ func InspectFormatWrite(ctx formatter.Context, refs []string, getRef inspect.Get } return nil } - return ctx.Write(&configInspectContext{}, render) + return fmtCtx.Write(&configInspectContext{}, render) } type configInspectContext struct { diff --git a/cli/command/config/formatter_test.go b/cli/command/config/formatter_test.go index 493c9908ed..879160a750 100644 --- a/cli/command/config/formatter_test.go +++ b/cli/command/config/formatter_test.go @@ -27,21 +27,21 @@ func TestConfigContextFormatWrite(t *testing.T) { }, // Table format { - formatter.Context{Format: NewFormat("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 `, }, { - formatter.Context{Format: NewFormat("table {{.Name}}", true)}, + formatter.Context{Format: newFormat("table {{.Name}}", true)}, `NAME passwords id_rsa `, }, { - formatter.Context{Format: NewFormat("{{.ID}}-{{.Name}}", false)}, + formatter.Context{Format: newFormat("{{.ID}}-{{.Name}}", false)}, `1-passwords 2-id_rsa `, @@ -64,7 +64,7 @@ id_rsa t.Run(string(tc.context.Format), func(t *testing.T) { var out bytes.Buffer tc.context.Output = &out - if err := FormatWrite(tc.context, configs); err != nil { + if err := formatWrite(tc.context, configs); err != nil { assert.ErrorContains(t, err, tc.expected) } else { assert.Equal(t, out.String(), tc.expected) diff --git a/cli/command/config/inspect.go b/cli/command/config/inspect.go index 1983857eb5..d25af89a79 100644 --- a/cli/command/config/inspect.go +++ b/cli/command/config/inspect.go @@ -63,10 +63,10 @@ func RunConfigInspect(ctx context.Context, dockerCLI command.Cli, opts InspectOp configCtx := formatter.Context{ Output: dockerCLI.Out(), - Format: NewFormat(f, false), + Format: newFormat(f, false), } - if err := InspectFormatWrite(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 diff --git a/cli/command/config/ls.go b/cli/command/config/ls.go index 70be1b34f2..c18869befd 100644 --- a/cli/command/config/ls.go +++ b/cli/command/config/ls.go @@ -68,7 +68,7 @@ func RunConfigList(ctx context.Context, dockerCLI command.Cli, options ListOptio configCtx := formatter.Context{ Output: dockerCLI.Out(), - Format: NewFormat(format, options.Quiet), + Format: newFormat(format, options.Quiet), } - return FormatWrite(configCtx, configs) + return formatWrite(configCtx, configs) } From 123ef81f7db4ec9e99083a8dc6aae00f3c9ecfcd Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 21 Aug 2025 14:36:20 +0200 Subject: [PATCH 05/11] cli/command/node: deprecate NewFormat, FormatWrite, InspectFormatWrite It's part of the presentation logic of the cli, and only used internally. We can consider providing utilities for these, but better as part of separate packages. Signed-off-by: Sebastiaan van Stijn --- cli/command/node/formatter.go | 33 ++++++++++++++++++++++++------ cli/command/node/formatter_test.go | 28 ++++++++++++------------- cli/command/node/inspect.go | 4 ++-- cli/command/node/list.go | 4 ++-- 4 files changed, 45 insertions(+), 24 deletions(-) diff --git a/cli/command/node/formatter.go b/cli/command/node/formatter.go index 58814874fe..4111494baa 100644 --- a/cli/command/node/formatter.go +++ b/cli/command/node/formatter.go @@ -80,7 +80,14 @@ TLS Info: ) // NewFormat returns a Format for rendering using a node Context +// +// Deprecated: this function was only used internally and will be removed in the next release. func NewFormat(source string, quiet bool) formatter.Format { + return newFormat(source, quiet) +} + +// newFormat returns a Format for rendering using a nodeContext. +func newFormat(source string, quiet bool) formatter.Format { switch source { case formatter.PrettyFormatKey: return nodeInspectPrettyTemplate @@ -99,7 +106,14 @@ func NewFormat(source string, quiet bool) formatter.Format { } // FormatWrite writes the context -func FormatWrite(ctx formatter.Context, nodes []swarm.Node, info system.Info) error { +// +// Deprecated: this function was only used internally and will be removed in the next release. +func FormatWrite(fmtCtx formatter.Context, nodes []swarm.Node, info system.Info) error { + return formatWrite(fmtCtx, nodes, info) +} + +// formatWrite writes the context. +func formatWrite(fmtCtx formatter.Context, nodes []swarm.Node, info system.Info) error { render := func(format func(subContext formatter.SubContext) error) error { for _, node := range nodes { nodeCtx := &nodeContext{n: node, info: info} @@ -120,7 +134,7 @@ func FormatWrite(ctx formatter.Context, nodes []swarm.Node, info system.Info) er "EngineVersion": engineVersionHeader, "TLSStatus": tlsStatusHeader, } - return ctx.Write(&nodeCtx, render) + return fmtCtx.Write(&nodeCtx, render) } type nodeContext struct { @@ -180,9 +194,16 @@ func (c *nodeContext) EngineVersion() string { } // InspectFormatWrite renders the context for a list of nodes -func InspectFormatWrite(ctx formatter.Context, refs []string, getRef inspect.GetRefFunc) error { - if ctx.Format != nodeInspectPrettyTemplate { - return inspect.Inspect(ctx.Output, refs, string(ctx.Format), getRef) +// +// Deprecated: this function was only used internally and will be removed in the next release. +func InspectFormatWrite(fmtCtx formatter.Context, refs []string, getRef inspect.GetRefFunc) error { + return inspectFormatWrite(fmtCtx, refs, getRef) +} + +// inspectFormatWrite renders the context for a list of nodes. +func inspectFormatWrite(fmtCtx formatter.Context, refs []string, getRef inspect.GetRefFunc) error { + if fmtCtx.Format != nodeInspectPrettyTemplate { + return inspect.Inspect(fmtCtx.Output, refs, string(fmtCtx.Format), getRef) } render := func(format func(subContext formatter.SubContext) error) error { for _, ref := range refs { @@ -200,7 +221,7 @@ func InspectFormatWrite(ctx formatter.Context, refs []string, getRef inspect.Get } return nil } - return ctx.Write(&nodeInspectContext{}, render) + return fmtCtx.Write(&nodeInspectContext{}, render) } type nodeInspectContext struct { diff --git a/cli/command/node/formatter_test.go b/cli/command/node/formatter_test.go index 44abeb7a0f..f842e49341 100644 --- a/cli/command/node/formatter_test.go +++ b/cli/command/node/formatter_test.go @@ -74,7 +74,7 @@ func TestNodeContextWrite(t *testing.T) { }, // Table format { - context: formatter.Context{Format: NewFormat("table", false)}, + context: formatter.Context{Format: newFormat("table", false)}, expected: `ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION nodeID1 foobar_baz Foo Drain Leader 18.03.0-ce nodeID2 foobar_bar Bar Active Reachable 1.2.3 @@ -82,7 +82,7 @@ nodeID3 foobar_boo Boo Active ` + "\n", // clusterInfo: swarm.ClusterInfo{TLSInfo: swarm.TLSInfo{TrustRoot: "hi"}}, }, { - context: formatter.Context{Format: NewFormat("table", true)}, + context: formatter.Context{Format: newFormat("table", true)}, expected: `nodeID1 nodeID2 nodeID3 @@ -90,7 +90,7 @@ nodeID3 clusterInfo: swarm.ClusterInfo{TLSInfo: swarm.TLSInfo{TrustRoot: "hi"}}, }, { - context: formatter.Context{Format: NewFormat("table {{.Hostname}}", false)}, + context: formatter.Context{Format: newFormat("table {{.Hostname}}", false)}, expected: `HOSTNAME foobar_baz foobar_bar @@ -99,7 +99,7 @@ foobar_boo clusterInfo: swarm.ClusterInfo{TLSInfo: swarm.TLSInfo{TrustRoot: "hi"}}, }, { - context: formatter.Context{Format: NewFormat("table {{.Hostname}}", true)}, + context: formatter.Context{Format: newFormat("table {{.Hostname}}", true)}, expected: `HOSTNAME foobar_baz foobar_bar @@ -108,7 +108,7 @@ foobar_boo clusterInfo: swarm.ClusterInfo{TLSInfo: swarm.TLSInfo{TrustRoot: "hi"}}, }, { - context: formatter.Context{Format: NewFormat("table {{.ID}}\t{{.Hostname}}\t{{.TLSStatus}}", false)}, + context: formatter.Context{Format: newFormat("table {{.ID}}\t{{.Hostname}}\t{{.TLSStatus}}", false)}, expected: `ID HOSTNAME TLS STATUS nodeID1 foobar_baz Needs Rotation nodeID2 foobar_bar Ready @@ -117,7 +117,7 @@ nodeID3 foobar_boo Unknown clusterInfo: swarm.ClusterInfo{TLSInfo: swarm.TLSInfo{TrustRoot: "hi"}}, }, { // no cluster TLS status info, TLS status for all nodes is unknown - context: formatter.Context{Format: NewFormat("table {{.ID}}\t{{.Hostname}}\t{{.TLSStatus}}", false)}, + context: formatter.Context{Format: newFormat("table {{.ID}}\t{{.Hostname}}\t{{.TLSStatus}}", false)}, expected: `ID HOSTNAME TLS STATUS nodeID1 foobar_baz Unknown nodeID2 foobar_bar Unknown @@ -127,7 +127,7 @@ nodeID3 foobar_boo Unknown }, // Raw Format { - context: formatter.Context{Format: NewFormat("raw", false)}, + context: formatter.Context{Format: newFormat("raw", false)}, expected: `node_id: nodeID1 hostname: foobar_baz status: Foo @@ -148,7 +148,7 @@ manager_status: ` + "\n\n", // to preserve whitespace clusterInfo: swarm.ClusterInfo{TLSInfo: swarm.TLSInfo{TrustRoot: "hi"}}, }, { - context: formatter.Context{Format: NewFormat("raw", true)}, + context: formatter.Context{Format: newFormat("raw", true)}, expected: `node_id: nodeID1 node_id: nodeID2 node_id: nodeID3 @@ -157,7 +157,7 @@ node_id: nodeID3 }, // Custom Format { - context: formatter.Context{Format: NewFormat("{{.Hostname}} {{.TLSStatus}}", false)}, + context: formatter.Context{Format: newFormat("{{.Hostname}} {{.TLSStatus}}", false)}, expected: `foobar_baz Needs Rotation foobar_bar Ready foobar_boo Unknown @@ -205,7 +205,7 @@ foobar_boo Unknown var out bytes.Buffer tc.context.Output = &out - err := FormatWrite(tc.context, nodes, system.Info{Swarm: swarm.Info{Cluster: &tc.clusterInfo}}) + err := formatWrite(tc.context, nodes, system.Info{Swarm: swarm.Info{Cluster: &tc.clusterInfo}}) if err != nil { assert.Error(t, err, tc.expected) } else { @@ -252,7 +252,7 @@ func TestNodeContextWriteJSON(t *testing.T) { {ID: "nodeID3", Description: swarm.NodeDescription{Hostname: "foobar_boo", Engine: swarm.EngineDescription{EngineVersion: "18.03.0-ce"}}}, } out := bytes.NewBufferString("") - err := FormatWrite(formatter.Context{Format: "{{json .}}", Output: out}, nodes, testcase.info) + err := formatWrite(formatter.Context{Format: "{{json .}}", Output: out}, nodes, testcase.info) if err != nil { t.Fatal(err) } @@ -272,7 +272,7 @@ func TestNodeContextWriteJSONField(t *testing.T) { {ID: "nodeID2", Description: swarm.NodeDescription{Hostname: "foobar_bar"}}, } out := bytes.NewBufferString("") - err := FormatWrite(formatter.Context{Format: "{{json .ID}}", Output: out}, nodes, system.Info{}) + err := formatWrite(formatter.Context{Format: "{{json .ID}}", Output: out}, nodes, system.Info{}) if err != nil { t.Fatal(err) } @@ -317,10 +317,10 @@ func TestNodeInspectWriteContext(t *testing.T) { } out := bytes.NewBufferString("") context := formatter.Context{ - Format: NewFormat("pretty", false), + Format: newFormat("pretty", false), Output: out, } - err := InspectFormatWrite(context, []string{"nodeID1"}, func(string) (any, []byte, error) { + err := inspectFormatWrite(context, []string{"nodeID1"}, func(string) (any, []byte, error) { return node, nil, nil }) if err != nil { diff --git a/cli/command/node/inspect.go b/cli/command/node/inspect.go index f293861d47..8f2519e04e 100644 --- a/cli/command/node/inspect.go +++ b/cli/command/node/inspect.go @@ -66,10 +66,10 @@ func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions) nodeCtx := formatter.Context{ Output: dockerCli.Out(), - Format: NewFormat(f, false), + Format: newFormat(f, false), } - if err := InspectFormatWrite(nodeCtx, opts.nodeIds, getRef); err != nil { + if err := inspectFormatWrite(nodeCtx, opts.nodeIds, getRef); err != nil { return cli.StatusError{StatusCode: 1, Status: err.Error()} } return nil diff --git a/cli/command/node/list.go b/cli/command/node/list.go index 8e9df4113c..77adb09e49 100644 --- a/cli/command/node/list.go +++ b/cli/command/node/list.go @@ -79,10 +79,10 @@ func runList(ctx context.Context, dockerCli command.Cli, options listOptions) er nodesCtx := formatter.Context{ Output: dockerCli.Out(), - Format: NewFormat(format, options.quiet), + Format: newFormat(format, options.quiet), } sort.Slice(nodes, func(i, j int) bool { return sortorder.NaturalLess(nodes[i].Description.Hostname, nodes[j].Description.Hostname) }) - return FormatWrite(nodesCtx, nodes, info) + return formatWrite(nodesCtx, nodes, info) } From bf47419852f5a41bc079b8f377091780f8bdfe63 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 21 Aug 2025 14:41:18 +0200 Subject: [PATCH 06/11] cli/command/plugin: deprecate NewFormat, FormatWrite It's part of the presentation logic of the cli, and only used internally. We can consider providing utilities for these, but better as part of separate packages. Signed-off-by: Sebastiaan van Stijn --- cli/command/plugin/formatter.go | 20 +++++++++++++++++--- cli/command/plugin/formatter_test.go | 20 ++++++++++---------- cli/command/plugin/list.go | 4 ++-- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/cli/command/plugin/formatter.go b/cli/command/plugin/formatter.go index b6f61f191a..4407745eb3 100644 --- a/cli/command/plugin/formatter.go +++ b/cli/command/plugin/formatter.go @@ -21,7 +21,14 @@ enabled: {{.Enabled}} ) // NewFormat returns a Format for rendering using a plugin Context +// +// Deprecated: this function was only used internally and will be removed in the next release. func NewFormat(source string, quiet bool) formatter.Format { + return newFormat(source, quiet) +} + +// newFormat returns a Format for rendering using a pluginContext. +func newFormat(source string, quiet bool) formatter.Format { switch source { case formatter.TableFormatKey: if quiet { @@ -38,10 +45,17 @@ func NewFormat(source string, quiet bool) formatter.Format { } // FormatWrite writes the context -func FormatWrite(ctx formatter.Context, plugins []*plugin.Plugin) error { +// +// Deprecated: this function was only used internally and will be removed in the next release. +func FormatWrite(fmtCtx formatter.Context, plugins []*plugin.Plugin) error { + return formatWrite(fmtCtx, plugins) +} + +// formatWrite writes the context +func formatWrite(fmtCtx formatter.Context, plugins []*plugin.Plugin) error { render := func(format func(subContext formatter.SubContext) error) error { for _, p := range plugins { - pluginCtx := &pluginContext{trunc: ctx.Trunc, p: *p} + pluginCtx := &pluginContext{trunc: fmtCtx.Trunc, p: *p} if err := format(pluginCtx); err != nil { return err } @@ -56,7 +70,7 @@ func FormatWrite(ctx formatter.Context, plugins []*plugin.Plugin) error { "Enabled": enabledHeader, "PluginReference": formatter.ImageHeader, } - return ctx.Write(&pluginCtx, render) + return fmtCtx.Write(&pluginCtx, render) } type pluginContext struct { diff --git a/cli/command/plugin/formatter_test.go b/cli/command/plugin/formatter_test.go index b3e9e733e0..abc9e3ec3a 100644 --- a/cli/command/plugin/formatter_test.go +++ b/cli/command/plugin/formatter_test.go @@ -86,7 +86,7 @@ func TestPluginContextWrite(t *testing.T) { }, { doc: "table format", - context: formatter.Context{Format: NewFormat("table", false)}, + context: formatter.Context{Format: newFormat("table", false)}, expected: `ID NAME DESCRIPTION ENABLED pluginID1 foobar_baz description 1 true pluginID2 foobar_bar description 2 false @@ -94,14 +94,14 @@ pluginID2 foobar_bar description 2 false }, { doc: "table format, quiet", - context: formatter.Context{Format: NewFormat("table", true)}, + context: formatter.Context{Format: newFormat("table", true)}, expected: `pluginID1 pluginID2 `, }, { doc: "table format name col", - context: formatter.Context{Format: NewFormat("table {{.Name}}", false)}, + context: formatter.Context{Format: newFormat("table {{.Name}}", false)}, expected: `NAME foobar_baz foobar_bar @@ -109,7 +109,7 @@ foobar_bar }, { doc: "table format name col, quiet", - context: formatter.Context{Format: NewFormat("table {{.Name}}", true)}, + context: formatter.Context{Format: newFormat("table {{.Name}}", true)}, expected: `NAME foobar_baz foobar_bar @@ -117,7 +117,7 @@ foobar_bar }, { doc: "raw format", - context: formatter.Context{Format: NewFormat("raw", false)}, + context: formatter.Context{Format: newFormat("raw", false)}, expected: `plugin_id: pluginID1 name: foobar_baz description: description 1 @@ -132,14 +132,14 @@ enabled: false }, { doc: "raw format, quiet", - context: formatter.Context{Format: NewFormat("raw", true)}, + context: formatter.Context{Format: newFormat("raw", true)}, expected: `plugin_id: pluginID1 plugin_id: pluginID2 `, }, { doc: "custom format", - context: formatter.Context{Format: NewFormat("{{.Name}}", false)}, + context: formatter.Context{Format: newFormat("{{.Name}}", false)}, expected: `foobar_baz foobar_bar `, @@ -156,7 +156,7 @@ foobar_bar var out bytes.Buffer tc.context.Output = &out - err := FormatWrite(tc.context, plugins) + err := formatWrite(tc.context, plugins) if err != nil { assert.Error(t, err, tc.expected) } else { @@ -177,7 +177,7 @@ func TestPluginContextWriteJSON(t *testing.T) { } out := bytes.NewBufferString("") - err := FormatWrite(formatter.Context{Format: "{{json .}}", Output: out}, plugins) + err := formatWrite(formatter.Context{Format: "{{json .}}", Output: out}, plugins) if err != nil { t.Fatal(err) } @@ -196,7 +196,7 @@ func TestPluginContextWriteJSONField(t *testing.T) { {ID: "pluginID2", Name: "foobar_bar"}, } out := bytes.NewBufferString("") - err := FormatWrite(formatter.Context{Format: "{{json .ID}}", Output: out}, plugins) + err := formatWrite(formatter.Context{Format: "{{json .ID}}", Output: out}, plugins) if err != nil { t.Fatal(err) } diff --git a/cli/command/plugin/list.go b/cli/command/plugin/list.go index 0c7234a2c3..da08a06f95 100644 --- a/cli/command/plugin/list.go +++ b/cli/command/plugin/list.go @@ -66,8 +66,8 @@ func runList(ctx context.Context, dockerCli command.Cli, options listOptions) er pluginsCtx := formatter.Context{ Output: dockerCli.Out(), - Format: NewFormat(format, options.quiet), + Format: newFormat(format, options.quiet), Trunc: !options.noTrunc, } - return FormatWrite(pluginsCtx, plugins) + return formatWrite(pluginsCtx, plugins) } From 83371c2014711110aaf375c146ca0912a4a5ba85 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 21 Aug 2025 14:46:59 +0200 Subject: [PATCH 07/11] cli/command/registry: deprecate NewSearchFormat, SearchWrite It's part of the presentation logic of the cli, and only used internally. We can consider providing utilities for these, but better as part of separate packages. Signed-off-by: Sebastiaan van Stijn --- cli/command/registry/formatter_search.go | 22 +++++++++++++++---- cli/command/registry/formatter_search_test.go | 10 ++++----- cli/command/registry/search.go | 4 ++-- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/cli/command/registry/formatter_search.go b/cli/command/registry/formatter_search.go index 9a1600c3de..3a7cb187b9 100644 --- a/cli/command/registry/formatter_search.go +++ b/cli/command/registry/formatter_search.go @@ -16,8 +16,15 @@ const ( automatedHeader = "AUTOMATED" ) -// NewSearchFormat returns a Format for rendering using a network Context +// NewSearchFormat returns a Format for rendering using a search Context +// +// Deprecated: this function was only used internally and will be removed in the next release. func NewSearchFormat(source string) formatter.Format { + return newFormat(source) +} + +// newFormat returns a Format for rendering using a searchContext. +func newFormat(source string) formatter.Format { switch source { case "", formatter.TableFormatKey: return defaultSearchTableFormat @@ -26,10 +33,17 @@ func NewSearchFormat(source string) formatter.Format { } // SearchWrite writes the context -func SearchWrite(ctx formatter.Context, results []registrytypes.SearchResult) error { +// +// Deprecated: this function was only used internally and will be removed in the next release. +func SearchWrite(fmtCtx formatter.Context, results []registrytypes.SearchResult) error { + return formatWrite(fmtCtx, results) +} + +// formatWrite writes the context. +func formatWrite(fmtCtx formatter.Context, results []registrytypes.SearchResult) error { render := func(format func(subContext formatter.SubContext) error) error { for _, result := range results { - searchCtx := &searchContext{trunc: ctx.Trunc, s: result} + searchCtx := &searchContext{trunc: fmtCtx.Trunc, s: result} if err := format(searchCtx); err != nil { return err } @@ -43,7 +57,7 @@ func SearchWrite(ctx formatter.Context, results []registrytypes.SearchResult) er "StarCount": starsHeader, "IsOfficial": officialHeader, } - return ctx.Write(&searchCtx, render) + return fmtCtx.Write(&searchCtx, render) } type searchContext struct { diff --git a/cli/command/registry/formatter_search_test.go b/cli/command/registry/formatter_search_test.go index 88c60203b6..e23a263467 100644 --- a/cli/command/registry/formatter_search_test.go +++ b/cli/command/registry/formatter_search_test.go @@ -157,12 +157,12 @@ func TestSearchContextWrite(t *testing.T) { }, { doc: "Table format", - format: NewSearchFormat("table"), + format: newFormat("table"), expected: string(golden.Get(t, "search-context-write-table.golden")), }, { doc: "Table format, single column", - format: NewSearchFormat("table {{.Name}}"), + format: newFormat("table {{.Name}}"), expected: `NAME result1 result2 @@ -170,14 +170,14 @@ result2 }, { doc: "Custom format, single field", - format: NewSearchFormat("{{.Name}}"), + format: newFormat("{{.Name}}"), expected: `result1 result2 `, }, { doc: "Custom Format, two columns", - format: NewSearchFormat("{{.Name}} {{.StarCount}}"), + format: newFormat("{{.Name}} {{.StarCount}}"), expected: `result1 5000 result2 5 `, @@ -192,7 +192,7 @@ result2 5 for _, tc := range cases { t.Run(tc.doc, func(t *testing.T) { var out bytes.Buffer - err := SearchWrite(formatter.Context{Format: tc.format, Output: &out}, results) + err := formatWrite(formatter.Context{Format: tc.format, Output: &out}, results) if tc.expectedErr != "" { assert.Check(t, is.Error(err, tc.expectedErr)) } else { diff --git a/cli/command/registry/search.go b/cli/command/registry/search.go index 59865e4f4f..ff42de5ca4 100644 --- a/cli/command/registry/search.go +++ b/cli/command/registry/search.go @@ -74,10 +74,10 @@ func runSearch(ctx context.Context, dockerCli command.Cli, options searchOptions searchCtx := formatter.Context{ Output: dockerCli.Out(), - Format: NewSearchFormat(options.format), + Format: newFormat(options.format), Trunc: !options.noTrunc, } - return SearchWrite(searchCtx, results) + return formatWrite(searchCtx, results) } // authConfigKey is the key used to store credentials for Docker Hub. It is From f3088e37a071ef01fb6cb813e7ca0fce75c516ef Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 21 Aug 2025 14:52:00 +0200 Subject: [PATCH 08/11] cli/command/secret: deprecate NewFormat, FormatWrite, InspectFormatWrite It's part of the presentation logic of the cli, and only used internally. We can consider providing utilities for these, but better as part of separate packages. Signed-off-by: Sebastiaan van Stijn --- cli/command/secret/formatter.go | 33 +++++++++++++++++++++++----- cli/command/secret/formatter_test.go | 8 +++---- cli/command/secret/inspect.go | 4 ++-- cli/command/secret/ls.go | 4 ++-- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/cli/command/secret/formatter.go b/cli/command/secret/formatter.go index 5a84d39444..101c4dddb6 100644 --- a/cli/command/secret/formatter.go +++ b/cli/command/secret/formatter.go @@ -29,7 +29,14 @@ Updated at: {{.UpdatedAt}}` ) // NewFormat returns a Format for rendering using a secret Context +// +// Deprecated: this function was only used internally and will be removed in the next release. func NewFormat(source string, quiet bool) formatter.Format { + return newFormat(source, quiet) +} + +// newFormat returns a Format for rendering using a secretContext. +func newFormat(source string, quiet bool) formatter.Format { switch source { case formatter.PrettyFormatKey: return secretInspectPrettyTemplate @@ -43,7 +50,14 @@ func NewFormat(source string, quiet bool) formatter.Format { } // FormatWrite writes the context -func FormatWrite(ctx formatter.Context, secrets []swarm.Secret) error { +// +// Deprecated: this function was only used internally and will be removed in the next release. +func FormatWrite(fmtCtx formatter.Context, secrets []swarm.Secret) error { + return formatWrite(fmtCtx, secrets) +} + +// formatWrite writes the context +func formatWrite(fmtCtx formatter.Context, secrets []swarm.Secret) error { render := func(format func(subContext formatter.SubContext) error) error { for _, secret := range secrets { secretCtx := &secretContext{s: secret} @@ -53,7 +67,7 @@ func FormatWrite(ctx formatter.Context, secrets []swarm.Secret) error { } return nil } - return ctx.Write(newSecretContext(), render) + return fmtCtx.Write(newSecretContext(), render) } func newSecretContext() *secretContext { @@ -122,9 +136,16 @@ func (c *secretContext) Label(name string) string { } // InspectFormatWrite renders the context for a list of secrets -func InspectFormatWrite(ctx formatter.Context, refs []string, getRef inspect.GetRefFunc) error { - if ctx.Format != secretInspectPrettyTemplate { - return inspect.Inspect(ctx.Output, refs, string(ctx.Format), getRef) +// +// Deprecated: this function was only used internally and will be removed in the next release. +func InspectFormatWrite(fmtCtx formatter.Context, refs []string, getRef inspect.GetRefFunc) error { + return inspectFormatWrite(fmtCtx, refs, getRef) +} + +// inspectFormatWrite renders the context for a list of secrets. +func inspectFormatWrite(fmtCtx formatter.Context, refs []string, getRef inspect.GetRefFunc) error { + if fmtCtx.Format != secretInspectPrettyTemplate { + return inspect.Inspect(fmtCtx.Output, refs, string(fmtCtx.Format), getRef) } render := func(format func(subContext formatter.SubContext) error) error { for _, ref := range refs { @@ -142,7 +163,7 @@ func InspectFormatWrite(ctx formatter.Context, refs []string, getRef inspect.Get } return nil } - return ctx.Write(&secretInspectContext{}, render) + return fmtCtx.Write(&secretInspectContext{}, render) } type secretInspectContext struct { diff --git a/cli/command/secret/formatter_test.go b/cli/command/secret/formatter_test.go index 76dc11e026..72473ecd67 100644 --- a/cli/command/secret/formatter_test.go +++ b/cli/command/secret/formatter_test.go @@ -27,21 +27,21 @@ func TestSecretContextFormatWrite(t *testing.T) { }, // Table format { - formatter.Context{Format: NewFormat("table", false)}, + formatter.Context{Format: newFormat("table", false)}, `ID NAME DRIVER 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 `, }, { - formatter.Context{Format: NewFormat("table {{.Name}}", true)}, + formatter.Context{Format: newFormat("table {{.Name}}", true)}, `NAME passwords id_rsa `, }, { - formatter.Context{Format: NewFormat("{{.ID}}-{{.Name}}", false)}, + formatter.Context{Format: newFormat("{{.ID}}-{{.Name}}", false)}, `1-passwords 2-id_rsa `, @@ -65,7 +65,7 @@ id_rsa var out bytes.Buffer tc.context.Output = &out - if err := FormatWrite(tc.context, secrets); err != nil { + if err := formatWrite(tc.context, secrets); err != nil { assert.Error(t, err, tc.expected) } else { assert.Equal(t, out.String(), tc.expected) diff --git a/cli/command/secret/inspect.go b/cli/command/secret/inspect.go index 22fed4b6e7..7712e4be13 100644 --- a/cli/command/secret/inspect.go +++ b/cli/command/secret/inspect.go @@ -61,10 +61,10 @@ func runSecretInspect(ctx context.Context, dockerCli command.Cli, opts inspectOp secretCtx := formatter.Context{ Output: dockerCli.Out(), - Format: NewFormat(f, false), + Format: newFormat(f, false), } - if err := InspectFormatWrite(secretCtx, opts.names, getRef); err != nil { + if err := inspectFormatWrite(secretCtx, opts.names, getRef); err != nil { return cli.StatusError{StatusCode: 1, Status: err.Error()} } return nil diff --git a/cli/command/secret/ls.go b/cli/command/secret/ls.go index c841ddfb29..e56acc4975 100644 --- a/cli/command/secret/ls.go +++ b/cli/command/secret/ls.go @@ -66,7 +66,7 @@ func runSecretList(ctx context.Context, dockerCli command.Cli, options listOptio secretCtx := formatter.Context{ Output: dockerCli.Out(), - Format: NewFormat(format, options.quiet), + Format: newFormat(format, options.quiet), } - return FormatWrite(secretCtx, secrets) + return formatWrite(secretCtx, secrets) } From 9f453d3fea42f46c779d4ed0df800e118724177c Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 21 Aug 2025 14:58:51 +0200 Subject: [PATCH 09/11] cli/command/service: deprecate NewFormat, InspectFormatWrite It's part of the presentation logic of the cli, and only used internally. We can consider providing utilities for these, but better as part of separate packages. Signed-off-by: Sebastiaan van Stijn --- cli/command/service/formatter.go | 22 ++++++++++++++++++---- cli/command/service/inspect.go | 4 ++-- cli/command/service/inspect_test.go | 12 ++++++------ 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/cli/command/service/formatter.go b/cli/command/service/formatter.go index fa1a0dc260..5cf62efb1e 100644 --- a/cli/command/service/formatter.go +++ b/cli/command/service/formatter.go @@ -196,7 +196,14 @@ Ports: ` // NewFormat returns a Format for rendering using a Context +// +// Deprecated: this function was only used internally and will be removed in the next release. func NewFormat(source string) formatter.Format { + return newFormat(source) +} + +// newFormat returns a Format for rendering using a Context. +func newFormat(source string) formatter.Format { switch source { case formatter.PrettyFormatKey: return serviceInspectPrettyTemplate @@ -218,9 +225,16 @@ func resolveNetworks(service swarm.Service, getNetwork inspect.GetRefFunc) map[s } // InspectFormatWrite renders the context for a list of services -func InspectFormatWrite(ctx formatter.Context, refs []string, getRef, getNetwork inspect.GetRefFunc) error { - if ctx.Format != serviceInspectPrettyTemplate { - return inspect.Inspect(ctx.Output, refs, string(ctx.Format), getRef) +// +// Deprecated: this function was only used internally and will be removed in the next release. +func InspectFormatWrite(fmtCtx formatter.Context, refs []string, getRef, getNetwork inspect.GetRefFunc) error { + return inspectFormatWrite(fmtCtx, refs, getRef, getNetwork) +} + +// inspectFormatWrite renders the context for a list of services +func inspectFormatWrite(fmtCtx formatter.Context, refs []string, getRef, getNetwork inspect.GetRefFunc) error { + if fmtCtx.Format != serviceInspectPrettyTemplate { + return inspect.Inspect(fmtCtx.Output, refs, string(fmtCtx.Format), getRef) } render := func(format func(subContext formatter.SubContext) error) error { for _, ref := range refs { @@ -238,7 +252,7 @@ func InspectFormatWrite(ctx formatter.Context, refs []string, getRef, getNetwork } return nil } - return ctx.Write(&serviceInspectContext{}, render) + return fmtCtx.Write(&serviceInspectContext{}, render) } type serviceInspectContext struct { diff --git a/cli/command/service/inspect.go b/cli/command/service/inspect.go index b529840496..044311f327 100644 --- a/cli/command/service/inspect.go +++ b/cli/command/service/inspect.go @@ -97,10 +97,10 @@ func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions) serviceCtx := formatter.Context{ Output: dockerCli.Out(), - Format: NewFormat(f), + Format: newFormat(f), } - if err := InspectFormatWrite(serviceCtx, opts.refs, getRef, getNetwork); err != nil { + if err := inspectFormatWrite(serviceCtx, opts.refs, getRef, getNetwork); err != nil { return cli.StatusError{StatusCode: 1, Status: err.Error()} } return nil diff --git a/cli/command/service/inspect_test.go b/cli/command/service/inspect_test.go index e3eef89dcf..4bd232b329 100644 --- a/cli/command/service/inspect_test.go +++ b/cli/command/service/inspect_test.go @@ -131,7 +131,7 @@ func formatServiceInspect(t *testing.T, format formatter.Format, now time.Time) Format: format, } - err := InspectFormatWrite(ctx, []string{"de179gar9d0o7ltdybungplod"}, + err := inspectFormatWrite(ctx, []string{"de179gar9d0o7ltdybungplod"}, func(ref string) (any, []byte, error) { return s, nil, nil }, @@ -149,12 +149,12 @@ func formatServiceInspect(t *testing.T, format formatter.Format, now time.Time) } func TestPrettyPrint(t *testing.T) { - s := formatServiceInspect(t, NewFormat("pretty"), time.Now()) + s := formatServiceInspect(t, newFormat("pretty"), time.Now()) golden.Assert(t, s, "service-inspect-pretty.golden") } func TestPrettyPrintWithNoUpdateConfig(t *testing.T) { - s := formatServiceInspect(t, NewFormat("pretty"), time.Now()) + s := formatServiceInspect(t, newFormat("pretty"), time.Now()) if strings.Contains(s, "UpdateStatus") { t.Fatal("Pretty print failed before parsing UpdateStatus") } @@ -167,8 +167,8 @@ func TestJSONFormatWithNoUpdateConfig(t *testing.T) { now := time.Now() // s1: [{"ID":..}] // s2: {"ID":..} - s1 := formatServiceInspect(t, NewFormat(""), now) - s2 := formatServiceInspect(t, NewFormat("{{json .}}"), now) + s1 := formatServiceInspect(t, newFormat(""), now) + s2 := formatServiceInspect(t, newFormat("{{json .}}"), now) var m1Wrap []map[string]any if err := json.Unmarshal([]byte(s1), &m1Wrap); err != nil { t.Fatal(err) @@ -185,7 +185,7 @@ func TestJSONFormatWithNoUpdateConfig(t *testing.T) { } func TestPrettyPrintWithConfigsAndSecrets(t *testing.T) { - s := formatServiceInspect(t, NewFormat("pretty"), time.Now()) + s := formatServiceInspect(t, newFormat("pretty"), time.Now()) assert.Check(t, is.Contains(s, "Log Driver:"), "Pretty print missing Log Driver") assert.Check(t, is.Contains(s, "Configs:"), "Pretty print missing configs") assert.Check(t, is.Contains(s, "Secrets:"), "Pretty print missing secrets") From c3ee82fdc325d373e47b6cae733198334db492ff Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 21 Aug 2025 15:09:44 +0200 Subject: [PATCH 10/11] cli/command/task: deprecate NewTaskFormat, FormatWrite It's part of the presentation logic of the cli, and only used internally. We can consider providing utilities for these, but better as part of separate packages. Signed-off-by: Sebastiaan van Stijn --- cli/command/task/formatter.go | 20 +++++++++++++++++--- cli/command/task/formatter_test.go | 14 +++++++------- cli/command/task/print.go | 4 ++-- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/cli/command/task/formatter.go b/cli/command/task/formatter.go index 60d70179b3..7f754e8d95 100644 --- a/cli/command/task/formatter.go +++ b/cli/command/task/formatter.go @@ -23,7 +23,14 @@ const ( ) // NewTaskFormat returns a Format for rendering using a task Context +// +// Deprecated: this function was only used internally and will be removed in the next release. func NewTaskFormat(source string, quiet bool) formatter.Format { + return newTaskFormat(source, quiet) +} + +// newTaskFormat returns a Format for rendering using a taskContext. +func newTaskFormat(source string, quiet bool) formatter.Format { switch source { case formatter.TableFormatKey: if quiet { @@ -40,10 +47,17 @@ func NewTaskFormat(source string, quiet bool) formatter.Format { } // FormatWrite writes the context -func FormatWrite(ctx formatter.Context, tasks []swarm.Task, names map[string]string, nodes map[string]string) error { +// +// Deprecated: this function was only used internally and will be removed in the next release. +func FormatWrite(fmtCtx formatter.Context, tasks []swarm.Task, names map[string]string, nodes map[string]string) error { + return formatWrite(fmtCtx, tasks, names, nodes) +} + +// formatWrite writes the context. +func formatWrite(fmtCtx formatter.Context, tasks []swarm.Task, names map[string]string, nodes map[string]string) error { render := func(format func(subContext formatter.SubContext) error) error { for _, task := range tasks { - taskCtx := &taskContext{trunc: ctx.Trunc, task: task, name: names[task.ID], node: nodes[task.ID]} + taskCtx := &taskContext{trunc: fmtCtx.Trunc, task: task, name: names[task.ID], node: nodes[task.ID]} if err := format(taskCtx); err != nil { return err } @@ -61,7 +75,7 @@ func FormatWrite(ctx formatter.Context, tasks []swarm.Task, names map[string]str "Error": formatter.ErrorHeader, "Ports": formatter.PortsHeader, } - return ctx.Write(&taskCtx, render) + return fmtCtx.Write(&taskCtx, render) } type taskContext struct { diff --git a/cli/command/task/formatter_test.go b/cli/command/task/formatter_test.go index 71d6b69810..0d2a359bc6 100644 --- a/cli/command/task/formatter_test.go +++ b/cli/command/task/formatter_test.go @@ -27,30 +27,30 @@ func TestTaskContextWrite(t *testing.T) { `template parsing error: template: :1:2: executing "" at : nil is not a command`, }, { - formatter.Context{Format: NewTaskFormat("table", true)}, + formatter.Context{Format: newTaskFormat("table", true)}, `taskID1 taskID2 `, }, { - formatter.Context{Format: NewTaskFormat("table {{.Name}}\t{{.Node}}\t{{.Ports}}", false)}, + formatter.Context{Format: newTaskFormat("table {{.Name}}\t{{.Node}}\t{{.Ports}}", false)}, string(golden.Get(t, "task-context-write-table-custom.golden")), }, { - formatter.Context{Format: NewTaskFormat("table {{.Name}}", true)}, + formatter.Context{Format: newTaskFormat("table {{.Name}}", true)}, `NAME foobar_baz foobar_bar `, }, { - formatter.Context{Format: NewTaskFormat("raw", true)}, + formatter.Context{Format: newTaskFormat("raw", true)}, `id: taskID1 id: taskID2 `, }, { - formatter.Context{Format: NewTaskFormat("{{.Name}} {{.Node}}", false)}, + formatter.Context{Format: newTaskFormat("{{.Name}} {{.Node}}", false)}, `foobar_baz foo1 foobar_bar foo2 `, @@ -75,7 +75,7 @@ foobar_bar foo2 var out bytes.Buffer tc.context.Output = &out - if err := FormatWrite(tc.context, tasks, names, nodes); err != nil { + if err := formatWrite(tc.context, tasks, names, nodes); err != nil { assert.Error(t, err, tc.expected) } else { assert.Equal(t, out.String(), tc.expected) @@ -94,7 +94,7 @@ func TestTaskContextWriteJSONField(t *testing.T) { "taskID2": "foobar_bar", } out := bytes.NewBufferString("") - err := FormatWrite(formatter.Context{Format: "{{json .ID}}", Output: out}, tasks, names, map[string]string{}) + err := formatWrite(formatter.Context{Format: "{{json .ID}}", Output: out}, tasks, names, map[string]string{}) if err != nil { t.Fatal(err) } diff --git a/cli/command/task/print.go b/cli/command/task/print.go index d9d015767b..615cb84e11 100644 --- a/cli/command/task/print.go +++ b/cli/command/task/print.go @@ -50,7 +50,7 @@ func Print(ctx context.Context, dockerCli command.Cli, tasks []swarm.Task, resol tasksCtx := formatter.Context{ Output: dockerCli.Out(), - Format: NewTaskFormat(format, quiet), + Format: newTaskFormat(format, quiet), Trunc: trunc, } @@ -75,7 +75,7 @@ func Print(ctx context.Context, dockerCli command.Cli, tasks []swarm.Task, resol nodes[task.ID] = nodeValue } - return FormatWrite(tasksCtx, tasks, names, nodes) + return formatWrite(tasksCtx, tasks, names, nodes) } // generateTaskNames generates names for the given tasks, and returns a copy of From 95c9b1b13bfd064d1d6d4f2a637862c0564ac237 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 21 Aug 2025 15:21:29 +0200 Subject: [PATCH 11/11] cli/command/trust: deprecate formatting-related functions and types It's part of the presentation logic of the cli, and only used internally. We can consider providing utilities for these, but better as part of separate packages. This deprecates the following types and functions: - `SignedTagInfo` - `SignerInfo` - `NewTrustTagFormat` - `NewSignerInfoFormat` - `TagWrite` - `SignerInfoWrite` Signed-off-by: Sebastiaan van Stijn --- cli/command/trust/formatter.go | 51 ++++++++++++++++++++++++----- cli/command/trust/formatter_test.go | 38 ++++++++++----------- cli/command/trust/inspect_pretty.go | 16 ++++----- 3 files changed, 69 insertions(+), 36 deletions(-) diff --git a/cli/command/trust/formatter.go b/cli/command/trust/formatter.go index 9597cfbd76..e536995fd7 100644 --- a/cli/command/trust/formatter.go +++ b/cli/command/trust/formatter.go @@ -21,7 +21,15 @@ const ( // Name: name of the signed tag // Digest: hex encoded digest of the contents // Signers: list of entities who signed the tag -type SignedTagInfo struct { +// +// Deprecated: this type was only used internally and will be removed in the next release. +type SignedTagInfo = signedTagInfo + +// signedTagInfo represents all formatted information needed to describe a signed tag: +// Name: name of the signed tag +// Digest: hex encoded digest of the contents +// Signers: list of entities who signed the tag +type signedTagInfo struct { Name string Digest string Signers []string @@ -30,23 +38,41 @@ type SignedTagInfo struct { // SignerInfo represents all formatted information needed to describe a signer: // Name: name of the signer role // Keys: the keys associated with the signer -type SignerInfo struct { +// +// Deprecated: this type was only used internally and will be removed in the next release. +type SignerInfo = signerInfo + +// signerInfo represents all formatted information needed to describe a signer: +// Name: name of the signer role +// Keys: the keys associated with the signer +type signerInfo struct { Name string Keys []string } // NewTrustTagFormat returns a Format for rendering using a trusted tag Context +// +// Deprecated: this function was only used internally and will be removed in the next release. func NewTrustTagFormat() formatter.Format { return defaultTrustTagTableFormat } // NewSignerInfoFormat returns a Format for rendering a signer role info Context +// +// Deprecated: this function was only used internally and will be removed in the next release. func NewSignerInfoFormat() formatter.Format { return defaultSignerInfoTableFormat } // TagWrite writes the context -func TagWrite(ctx formatter.Context, signedTagInfoList []SignedTagInfo) error { +// +// Deprecated: this function was only used internally and will be removed in the next release. +func TagWrite(fmtCtx formatter.Context, signedTagInfoList []signedTagInfo) error { + return tagWrite(fmtCtx, signedTagInfoList) +} + +// tagWrite writes the context +func tagWrite(fmtCtx formatter.Context, signedTagInfoList []signedTagInfo) error { render := func(format func(subContext formatter.SubContext) error) error { for _, signedTag := range signedTagInfoList { if err := format(&trustTagContext{s: signedTag}); err != nil { @@ -61,12 +87,12 @@ func TagWrite(ctx formatter.Context, signedTagInfoList []SignedTagInfo) error { "Digest": trustedDigestHeader, "Signers": signersHeader, } - return ctx.Write(&trustTagCtx, render) + return fmtCtx.Write(&trustTagCtx, render) } type trustTagContext struct { formatter.HeaderContext - s SignedTagInfo + s signedTagInfo } // SignedTag returns the name of the signed tag @@ -86,11 +112,18 @@ func (c *trustTagContext) Signers() string { } // SignerInfoWrite writes the context -func SignerInfoWrite(ctx formatter.Context, signerInfoList []SignerInfo) error { +// +// Deprecated: this function was only used internally and will be removed in the next release. +func SignerInfoWrite(fmtCtx formatter.Context, signerInfoList []signerInfo) error { + return signerInfoWrite(fmtCtx, signerInfoList) +} + +// signerInfoWrite writes the context. +func signerInfoWrite(fmtCtx formatter.Context, signerInfoList []signerInfo) error { render := func(format func(subContext formatter.SubContext) error) error { for _, signerInfo := range signerInfoList { if err := format(&signerInfoContext{ - trunc: ctx.Trunc, + trunc: fmtCtx.Trunc, s: signerInfo, }); err != nil { return err @@ -103,13 +136,13 @@ func SignerInfoWrite(ctx formatter.Context, signerInfoList []SignerInfo) error { "Signer": signerNameHeader, "Keys": keysHeader, } - return ctx.Write(&signerInfoCtx, render) + return fmtCtx.Write(&signerInfoCtx, render) } type signerInfoContext struct { formatter.HeaderContext trunc bool - s SignerInfo + s signerInfo } // Keys returns the sorted list of keys associated with the signer diff --git a/cli/command/trust/formatter_test.go b/cli/command/trust/formatter_test.go index 4c0c194f4c..413a2605ab 100644 --- a/cli/command/trust/formatter_test.go +++ b/cli/command/trust/formatter_test.go @@ -23,7 +23,7 @@ func TestTrustTag(t *testing.T) { }{ { trustTagContext{ - s: SignedTagInfo{ + s: signedTagInfo{ Name: trustedTag, Digest: digest, Signers: nil, @@ -34,7 +34,7 @@ func TestTrustTag(t *testing.T) { }, { trustTagContext{ - s: SignedTagInfo{ + s: signedTagInfo{ Name: trustedTag, Digest: digest, Signers: nil, @@ -46,7 +46,7 @@ func TestTrustTag(t *testing.T) { // Empty signers makes a row with empty string { trustTagContext{ - s: SignedTagInfo{ + s: signedTagInfo{ Name: trustedTag, Digest: digest, Signers: nil, @@ -57,7 +57,7 @@ func TestTrustTag(t *testing.T) { }, { trustTagContext{ - s: SignedTagInfo{ + s: signedTagInfo{ Name: trustedTag, Digest: digest, Signers: []string{"alice", "bob", "claire"}, @@ -69,7 +69,7 @@ func TestTrustTag(t *testing.T) { // alphabetic signing on Signers { trustTagContext{ - s: SignedTagInfo{ + s: signedTagInfo{ Name: trustedTag, Digest: digest, Signers: []string{"claire", "bob", "alice"}, @@ -110,7 +110,7 @@ func TestTrustTagContextWrite(t *testing.T) { // Table Format { formatter.Context{ - Format: NewTrustTagFormat(), + Format: defaultTrustTagTableFormat, }, `SIGNED TAG DIGEST SIGNERS tag1 deadbeef alice @@ -120,7 +120,7 @@ tag3 bbbbbbbb }, } - signedTags := []SignedTagInfo{ + signedTags := []signedTagInfo{ {Name: "tag1", Digest: "deadbeef", Signers: []string{"alice"}}, {Name: "tag2", Digest: "aaaaaaaa", Signers: []string{"alice", "bob"}}, {Name: "tag3", Digest: "bbbbbbbb", Signers: []string{}}, @@ -131,7 +131,7 @@ tag3 bbbbbbbb var out bytes.Buffer tc.context.Output = &out - if err := TagWrite(tc.context, signedTags); err != nil { + if err := tagWrite(tc.context, signedTags); err != nil { assert.Error(t, err, tc.expected) } else { assert.Equal(t, out.String(), tc.expected) @@ -140,7 +140,7 @@ tag3 bbbbbbbb } } -// With no trust data, the TagWrite will print an empty table: +// With no trust data, the formatWrite will print an empty table: // it's up to the caller to decide whether or not to print this versus an error func TestTrustTagContextEmptyWrite(t *testing.T) { emptyCase := struct { @@ -148,16 +148,16 @@ func TestTrustTagContextEmptyWrite(t *testing.T) { expected string }{ formatter.Context{ - Format: NewTrustTagFormat(), + Format: defaultTrustTagTableFormat, }, `SIGNED TAG DIGEST SIGNERS `, } - emptySignedTags := []SignedTagInfo{} + emptySignedTags := []signedTagInfo{} out := bytes.NewBufferString("") emptyCase.context.Output = out - err := TagWrite(emptyCase.context, emptySignedTags) + err := tagWrite(emptyCase.context, emptySignedTags) assert.NilError(t, err) assert.Check(t, is.Equal(emptyCase.expected, out.String())) } @@ -168,15 +168,15 @@ func TestSignerInfoContextEmptyWrite(t *testing.T) { expected string }{ formatter.Context{ - Format: NewSignerInfoFormat(), + Format: defaultSignerInfoTableFormat, }, `SIGNER KEYS `, } - emptySignerInfo := []SignerInfo{} + emptySignerInfo := []signerInfo{} out := bytes.NewBufferString("") emptyCase.context.Output = out - err := SignerInfoWrite(emptyCase.context, emptySignerInfo) + err := signerInfoWrite(emptyCase.context, emptySignerInfo) assert.NilError(t, err) assert.Check(t, is.Equal(emptyCase.expected, out.String())) } @@ -202,7 +202,7 @@ func TestSignerInfoContextWrite(t *testing.T) { // Table Format { formatter.Context{ - Format: NewSignerInfoFormat(), + Format: defaultSignerInfoTableFormat, Trunc: true, }, `SIGNER KEYS @@ -214,7 +214,7 @@ eve foobarbazqux, key31, key32 // No truncation { formatter.Context{ - Format: NewSignerInfoFormat(), + Format: defaultSignerInfoTableFormat, }, `SIGNER KEYS alice key11, key12 @@ -224,7 +224,7 @@ eve foobarbazquxquux, key31, key32 }, } - signerInfo := []SignerInfo{ + signerInfo := []signerInfo{ {Name: "alice", Keys: []string{"key11", "key12"}}, {Name: "bob", Keys: []string{"key21"}}, {Name: "eve", Keys: []string{"key31", "key32", "foobarbazquxquux"}}, @@ -234,7 +234,7 @@ eve foobarbazquxquux, key31, key32 var out bytes.Buffer tc.context.Output = &out - if err := SignerInfoWrite(tc.context, signerInfo); err != nil { + if err := signerInfoWrite(tc.context, signerInfo); err != nil { assert.Error(t, err, tc.expected) } else { assert.Equal(t, out.String(), tc.expected) diff --git a/cli/command/trust/inspect_pretty.go b/cli/command/trust/inspect_pretty.go index b0b5e8c51c..3eac2cfbe8 100644 --- a/cli/command/trust/inspect_pretty.go +++ b/cli/command/trust/inspect_pretty.go @@ -56,33 +56,33 @@ func printSortedAdminKeys(out io.Writer, adminRoles []client.RoleWithSignatures) func printSignatures(out io.Writer, signatureRows []trustTagRow) error { trustTagCtx := formatter.Context{ Output: out, - Format: NewTrustTagFormat(), + Format: defaultTrustTagTableFormat, } // convert the formatted type before printing - formattedTags := []SignedTagInfo{} + formattedTags := []signedTagInfo{} for _, sigRow := range signatureRows { formattedSigners := sigRow.Signers if len(formattedSigners) == 0 { formattedSigners = append(formattedSigners, fmt.Sprintf("(%s)", releasedRoleName)) } - formattedTags = append(formattedTags, SignedTagInfo{ + formattedTags = append(formattedTags, signedTagInfo{ Name: sigRow.SignedTag, Digest: sigRow.Digest, Signers: formattedSigners, }) } - return TagWrite(trustTagCtx, formattedTags) + return tagWrite(trustTagCtx, formattedTags) } func printSignerInfo(out io.Writer, roleToKeyIDs map[string][]string) error { signerInfoCtx := formatter.Context{ Output: out, - Format: NewSignerInfoFormat(), + Format: defaultSignerInfoTableFormat, Trunc: true, } - formattedSignerInfo := []SignerInfo{} + formattedSignerInfo := []signerInfo{} for name, keyIDs := range roleToKeyIDs { - formattedSignerInfo = append(formattedSignerInfo, SignerInfo{ + formattedSignerInfo = append(formattedSignerInfo, signerInfo{ Name: name, Keys: keyIDs, }) @@ -90,5 +90,5 @@ func printSignerInfo(out io.Writer, roleToKeyIDs map[string][]string) error { sort.Slice(formattedSignerInfo, func(i, j int) bool { return sortorder.NaturalLess(formattedSignerInfo[i].Name, formattedSignerInfo[j].Name) }) - return SignerInfoWrite(signerInfoCtx, formattedSignerInfo) + return signerInfoWrite(signerInfoCtx, formattedSignerInfo) }