Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions cli/command/container/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package container

import (
"context"
"errors"
"fmt"
"strings"

Expand All @@ -10,7 +11,6 @@ import (
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts"
containertypes "github.com/moby/moby/api/types/container"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -131,12 +131,12 @@ func runUpdate(ctx context.Context, dockerCli command.Cli, options *updateOption

var (
warns []string
errs []string
errs []error
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is possible to use errors.Join directly on the error type instead of a slice.

var errs error
errs = errors.Join(errs, err)
errs = errors.Join(errs, err)

Copy link
Member Author

@thaJeztah thaJeztah Sep 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, they're subtly different though; repeatedly calling errors.Join effectively is similar to errors.Wrap; the new error is nesting previous errors, whereas a slice approach makes them all "peers"; https://go.dev/play/p/42cXzTSkjoA

package main

import (
	"errors"
	"fmt"
)

func main() {
	errs := []error{
		errors.New("one"),
		errors.New("two"),
		errors.New("three"),
	}
	var nested error
	for _, err := range errs {
		nested = errors.Join(nested, err)
	}

	flat := errors.Join(errs...)

	fmt.Printf("Flat  : %#v\n", flat)
	fmt.Printf("Nested: %#v\n", nested)
}

Output;

Flat  : &errors.joinError{errs:[]error{(*errors.errorString)(0xc000012040), (*errors.errorString)(0xc000012050), (*errors.errorString)(0xc000012060)}}
Nested: &errors.joinError{errs:[]error{(*errors.joinError)(0xc00000e060), (*errors.errorString)(0xc000012060)}}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting, i thought it might've behaved the same

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think they chose a bad name for the function; I was confused as well when I was pointed at it! Join feels like "same level", not "wrap errors to be nested".

In many cases it doesn't make a big difference, e.g. errors.Is will recurse, so will still find nested errors (which sometimes is a bit of a pain / unwanted as well), but sometimes it may matter ("peer" errors vs "nested errors")

)
for _, ctr := range options.containers {
r, err := dockerCli.Client().ContainerUpdate(ctx, ctr, updateConfig)
if err != nil {
errs = append(errs, err.Error())
errs = append(errs, err)
} else {
_, _ = fmt.Fprintln(dockerCli.Out(), ctr)
}
Expand All @@ -145,8 +145,5 @@ func runUpdate(ctx context.Context, dockerCli command.Cli, options *updateOption
if len(warns) > 0 {
_, _ = fmt.Fprintln(dockerCli.Out(), strings.Join(warns, "\n"))
}
if len(errs) > 0 {
return errors.New(strings.Join(errs, "\n"))
}
return nil
return errors.Join(errs...)
}
19 changes: 7 additions & 12 deletions cli/command/node/ps.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package node

import (
"context"
"strings"
"errors"

"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
Expand All @@ -11,7 +11,6 @@ import (
"github.com/docker/cli/opts"
"github.com/moby/moby/api/types/swarm"
"github.com/moby/moby/client"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
Expand Down Expand Up @@ -64,20 +63,20 @@ func runPs(ctx context.Context, dockerCLI command.Cli, options psOptions) error
apiClient := dockerCLI.Client()

var (
errs []string
errs []error
tasks []swarm.Task
)

for _, nodeID := range options.nodeIDs {
nodeRef, err := Reference(ctx, apiClient, nodeID)
if err != nil {
errs = append(errs, err.Error())
errs = append(errs, err)
continue
}

node, _, err := apiClient.NodeInspectWithRaw(ctx, nodeRef)
if err != nil {
errs = append(errs, err.Error())
errs = append(errs, err)
continue
}

Expand All @@ -86,7 +85,7 @@ func runPs(ctx context.Context, dockerCLI command.Cli, options psOptions) error

nodeTasks, err := apiClient.TaskList(ctx, client.TaskListOptions{Filters: filter})
if err != nil {
errs = append(errs, err.Error())
errs = append(errs, err)
continue
}

Expand All @@ -100,13 +99,9 @@ func runPs(ctx context.Context, dockerCLI command.Cli, options psOptions) error

if len(errs) == 0 || len(tasks) != 0 {
if err := task.Print(ctx, dockerCLI, tasks, idresolver.New(apiClient, options.noResolve), !options.noTrunc, options.quiet, format); err != nil {
errs = append(errs, err.Error())
errs = append(errs, err)
}
}

if len(errs) > 0 {
return errors.Errorf("%s", strings.Join(errs, "\n"))
}

return nil
return errors.Join(errs...)
}
Loading