Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch from github.com/pkg/errors to %w-style wrap #5525

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
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
20 changes: 6 additions & 14 deletions cli-plugins/manager/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
package manager

import (
"github.com/pkg/errors"
"fmt"
)

// pluginError is set as Plugin.Err by NewPlugin if the plugin
Expand All @@ -23,12 +23,13 @@ func (e *pluginError) Error() string {
return e.cause.Error()
}

// Cause satisfies the errors.causer interface for pluginError.
// Cause satisfies the github.com/pkg/errors.causer interface for pluginError.
// TODO: remove this once all users switch away from github.com/pkg/errors.
func (e *pluginError) Cause() error {
return e.cause
}

// Unwrap provides compatibility for Go 1.13 error chains.
// Unwrap provides compatibility for Go 1.13+ error chains.
func (e *pluginError) Unwrap() error {
return e.cause
}
Expand All @@ -38,17 +39,8 @@ func (e *pluginError) MarshalText() (text []byte, err error) {
return []byte(e.cause.Error()), nil
}

// wrapAsPluginError wraps an error in a pluginError with an
// additional message, analogous to errors.Wrapf.
func wrapAsPluginError(err error, msg string) error {
if err == nil {
return nil
}
return &pluginError{cause: errors.Wrap(err, msg)}
}

// NewPluginError creates a new pluginError, analogous to
// errors.Errorf.
// [fmt.Errorf].
func NewPluginError(msg string, args ...any) error {
return &pluginError{cause: errors.Errorf(msg, args...)}
return &pluginError{cause: fmt.Errorf(msg, args...)}
}
2 changes: 1 addition & 1 deletion cli-plugins/manager/error_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func TestPluginError(t *testing.T) {
assert.Check(t, is.Error(err, "new error"))

inner := errors.New("testing")
err = wrapAsPluginError(inner, "wrapping")
err = NewPluginError("wrapping: %w", inner)
assert.Check(t, is.Error(err, "wrapping: testing"))
assert.Check(t, is.ErrorIs(err, inner))

Expand Down
17 changes: 9 additions & 8 deletions cli-plugins/manager/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ package manager
import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"

"github.com/pkg/errors"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -44,14 +45,14 @@ func newPlugin(c Candidate, cmds []*cobra.Command) (Plugin, error) {
// which would fail here, so there are all real errors.
fullname := filepath.Base(path)
if fullname == "." {
return Plugin{}, errors.Errorf("unable to determine basename of plugin candidate %q", path)
return Plugin{}, fmt.Errorf("unable to determine basename of plugin candidate %q", path)
}
var err error
if fullname, err = trimExeSuffix(fullname); err != nil {
return Plugin{}, errors.Wrapf(err, "plugin candidate %q", path)
return Plugin{}, fmt.Errorf("plugin candidate %q: %w", path, err)
}
if !strings.HasPrefix(fullname, NamePrefix) {
return Plugin{}, errors.Errorf("plugin candidate %q: does not have %q prefix", path, NamePrefix)
return Plugin{}, fmt.Errorf("plugin candidate %q: does not have %q prefix", path, NamePrefix)
}

p := Plugin{
Expand Down Expand Up @@ -85,12 +86,12 @@ func newPlugin(c Candidate, cmds []*cobra.Command) (Plugin, error) {
// We are supposed to check for relevant execute permissions here. Instead we rely on an attempt to execute.
meta, err := c.Metadata()
if err != nil {
p.Err = wrapAsPluginError(err, "failed to fetch metadata")
p.Err = NewPluginError("failed to fetch metadata: %w", err)
return p, nil
}

if err := json.Unmarshal(meta, &p.Metadata); err != nil {
p.Err = wrapAsPluginError(err, "invalid metadata")
p.Err = NewPluginError("invalid metadata: %w", err)
return p, nil
}
if p.Metadata.SchemaVersion != "0.1.0" {
Expand All @@ -109,15 +110,15 @@ func newPlugin(c Candidate, cmds []*cobra.Command) (Plugin, error) {
func (p *Plugin) RunHook(ctx context.Context, hookData HookPluginData) ([]byte, error) {
hDataBytes, err := json.Marshal(hookData)
if err != nil {
return nil, wrapAsPluginError(err, "failed to marshall hook data")
return nil, NewPluginError("failed to marshall hook data: %w", err)
}

pCmd := exec.CommandContext(ctx, p.Path, p.Name, HookSubcommandName, string(hDataBytes))
pCmd.Env = os.Environ()
pCmd.Env = append(pCmd.Env, ReexecEnvvar+"="+os.Args[0])
hookCmdOutput, err := pCmd.Output()
if err != nil {
return nil, wrapAsPluginError(err, "failed to execute plugin hook subcommand")
return nil, NewPluginError("failed to execute plugin hook subcommand: %w", err)
}

return hookCmdOutput, nil
Expand Down
7 changes: 3 additions & 4 deletions cli-plugins/manager/suffix_windows.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
package manager

import (
"fmt"
"path/filepath"
"strings"

"github.com/pkg/errors"
)

// This is made slightly more complex due to needing to be case insensitive.
func trimExeSuffix(s string) (string, error) {
ext := filepath.Ext(s)
if ext == "" {
return "", errors.Errorf("path %q lacks required file extension", s)
return "", fmt.Errorf("path %q lacks required file extension", s)
}

exe := ".exe"
if !strings.EqualFold(ext, exe) {
return "", errors.Errorf("path %q lacks required %q suffix", s, exe)
return "", fmt.Errorf("path %q lacks required %q suffix", s, exe)
}
return strings.TrimSuffix(s, ext), nil
}
Expand Down
4 changes: 2 additions & 2 deletions cli/cobra.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"github.com/fvbommel/sortorder"
"github.com/moby/term"
"github.com/morikuni/aec"
"github.com/pkg/errors"

"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
Expand Down Expand Up @@ -214,7 +214,7 @@ var helpCommand = &cobra.Command{
RunE: func(c *cobra.Command, args []string) error {
cmd, args, e := c.Root().Find(args)
if cmd == nil || e != nil || len(args) > 0 {
return errors.Errorf("unknown help topic: %v", strings.Join(args, " "))
return fmt.Errorf("unknown help topic: %v", strings.Join(args, " "))
}
helpFunc := cmd.HelpFunc()
helpFunc(cmd, args)
Expand Down
5 changes: 3 additions & 2 deletions cli/command/checkpoint/create_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package checkpoint

import (
"fmt"
"io"
"strings"
"testing"

"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types/checkpoint"
"github.com/pkg/errors"

"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
Expand All @@ -29,7 +30,7 @@ func TestCheckpointCreateErrors(t *testing.T) {
{
args: []string{"foo", "bar"},
checkpointCreateFunc: func(container string, options checkpoint.CreateOptions) error {
return errors.Errorf("error creating checkpoint for container foo")
return fmt.Errorf("error creating checkpoint for container foo")
},
expectedError: "error creating checkpoint for container foo",
},
Expand Down
5 changes: 3 additions & 2 deletions cli/command/checkpoint/list_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package checkpoint

import (
"fmt"
"io"
"testing"

"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types/checkpoint"
"github.com/pkg/errors"

"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/golden"
Expand All @@ -29,7 +30,7 @@ func TestCheckpointListErrors(t *testing.T) {
{
args: []string{"foo"},
checkpointListFunc: func(container string, options checkpoint.ListOptions) ([]checkpoint.Summary, error) {
return []checkpoint.Summary{}, errors.Errorf("error getting checkpoints for container foo")
return []checkpoint.Summary{}, fmt.Errorf("error getting checkpoints for container foo")
},
expectedError: "error getting checkpoints for container foo",
},
Expand Down
5 changes: 3 additions & 2 deletions cli/command/checkpoint/remove_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package checkpoint

import (
"fmt"
"io"
"testing"

"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types/checkpoint"
"github.com/pkg/errors"

"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
Expand All @@ -28,7 +29,7 @@ func TestCheckpointRemoveErrors(t *testing.T) {
{
args: []string{"foo", "bar"},
checkpointDeleteFunc: func(container string, options checkpoint.DeleteOptions) error {
return errors.Errorf("error deleting checkpoint")
return fmt.Errorf("error deleting checkpoint")
},
expectedError: "error deleting checkpoint",
},
Expand Down
9 changes: 5 additions & 4 deletions cli/command/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package command

import (
"context"
"errors"
"fmt"
"io"
"os"
Expand Down Expand Up @@ -33,7 +34,7 @@ import (
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
"github.com/docker/go-connections/tlsconfig"
"github.com/pkg/errors"

"github.com/spf13/cobra"
notaryclient "github.com/theupdateframework/notary/client"
)
Expand Down Expand Up @@ -177,7 +178,7 @@ func (cli *DockerCli) BuildKitEnabled() (bool, error) {
if v := os.Getenv("DOCKER_BUILDKIT"); v != "" {
enabled, err := strconv.ParseBool(v)
if err != nil {
return false, errors.Wrap(err, "DOCKER_BUILDKIT environment variable expects boolean value")
return false, fmt.Errorf("DOCKER_BUILDKIT environment variable expects boolean value: %w", err)
}
return enabled, nil
}
Expand Down Expand Up @@ -311,7 +312,7 @@ func NewAPIClientFromFlags(opts *cliflags.ClientOptions, configFile *configfile.
}
endpoint, err := resolveDockerEndpoint(contextStore, resolveContextName(opts, configFile))
if err != nil {
return nil, errors.Wrap(err, "unable to resolve docker endpoint")
return nil, fmt.Errorf("unable to resolve docker endpoint: %w", err)
}
return newAPIClientFromEndpoint(endpoint, configFile)
}
Expand Down Expand Up @@ -492,7 +493,7 @@ func (cli *DockerCli) initialize() error {
cli.init.Do(func() {
cli.dockerEndpoint, cli.initErr = cli.getDockerEndPoint()
if cli.initErr != nil {
cli.initErr = errors.Wrap(cli.initErr, "unable to resolve docker endpoint")
cli.initErr = fmt.Errorf("unable to resolve docker endpoint: %w", cli.initErr)
return
}
if cli.client == nil {
Expand Down
8 changes: 4 additions & 4 deletions cli/command/cli_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package command
import (
"context"
"encoding/csv"
"fmt"
"io"
"net/http"
"os"
Expand All @@ -13,7 +14,6 @@ import (
"github.com/docker/docker/client"
"github.com/docker/docker/errdefs"
"github.com/moby/term"
"github.com/pkg/errors"
)

// CLIOption is a functional argument to apply options to a [DockerCli]. These
Expand Down Expand Up @@ -177,7 +177,7 @@ func withCustomHeadersFromEnv() client.Opt {
csvReader := csv.NewReader(strings.NewReader(value))
fields, err := csvReader.Read()
if err != nil {
return errdefs.InvalidParameter(errors.Errorf("failed to parse custom headers from %s environment variable: value must be formatted as comma-separated key=value pairs", envOverrideHTTPHeaders))
return errdefs.InvalidParameter(fmt.Errorf("failed to parse custom headers from %s environment variable: value must be formatted as comma-separated key=value pairs", envOverrideHTTPHeaders))
}
if len(fields) == 0 {
return nil
Expand All @@ -191,15 +191,15 @@ func withCustomHeadersFromEnv() client.Opt {
k = strings.TrimSpace(k)

if k == "" {
return errdefs.InvalidParameter(errors.Errorf(`failed to set custom headers from %s environment variable: value contains a key=value pair with an empty key: '%s'`, envOverrideHTTPHeaders, kv))
return errdefs.InvalidParameter(fmt.Errorf(`failed to set custom headers from %s environment variable: value contains a key=value pair with an empty key: '%s'`, envOverrideHTTPHeaders, kv))
}

// We don't currently allow empty key=value pairs, and produce an error.
// This is something we could allow in future (e.g. to read value
// from an environment variable with the same name). In the meantime,
// produce an error to prevent users from depending on this.
if !hasValue {
return errdefs.InvalidParameter(errors.Errorf(`failed to set custom headers from %s environment variable: missing "=" in key=value pair: '%s'`, envOverrideHTTPHeaders, kv))
return errdefs.InvalidParameter(fmt.Errorf(`failed to set custom headers from %s environment variable: missing "=" in key=value pair: '%s'`, envOverrideHTTPHeaders, kv))
}

env[http.CanonicalHeaderKey(k)] = v
Expand Down
3 changes: 2 additions & 1 deletion cli/command/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package command
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"net"
Expand All @@ -22,7 +23,7 @@ import (
"github.com/docker/docker/api"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/pkg/errors"

"gotest.tools/v3/assert"
"gotest.tools/v3/fs"
)
Expand Down
4 changes: 2 additions & 2 deletions cli/command/config/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types/swarm"
"github.com/moby/sys/sequential"
"github.com/pkg/errors"

"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -63,7 +63,7 @@ func RunConfigCreate(ctx context.Context, dockerCli command.Cli, options CreateO

configData, err := io.ReadAll(in)
if err != nil {
return errors.Errorf("Error reading content from %q: %v", options.File, err)
return fmt.Errorf("Error reading content from %q: %v", options.File, err)
}

spec := swarm.ConfigSpec{
Expand Down
Loading
Loading