Skip to content

Commit 4c882e0

Browse files
committed
opts: use stdlib errors and touch-up some errors
- remove uses of github.com/pkg/errors - slight improvement on handling parsing errors - add some test-cases Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
1 parent 2eec746 commit 4c882e0

11 files changed

Lines changed: 64 additions & 39 deletions

File tree

opts/duration.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
package opts
22

33
import (
4+
"errors"
45
"time"
5-
6-
"github.com/pkg/errors"
76
)
87

98
// PositiveDurationOpt is an option type for time.Duration that uses a pointer.
@@ -20,7 +19,7 @@ func (d *PositiveDurationOpt) Set(s string) error {
2019
return err
2120
}
2221
if *d.DurationOpt.value < 0 {
23-
return errors.Errorf("duration cannot be negative")
22+
return errors.New("duration cannot be negative")
2423
}
2524
return nil
2625
}

opts/env.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
package opts
22

33
import (
4+
"errors"
45
"os"
56
"strings"
6-
7-
"github.com/pkg/errors"
87
)
98

109
// ValidateEnv validates an environment variable and returns it.

opts/gpus.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ package opts
22

33
import (
44
"encoding/csv"
5+
"errors"
56
"fmt"
67
"strconv"
78
"strings"
89

910
"github.com/docker/docker/api/types/container"
10-
"github.com/pkg/errors"
1111
)
1212

1313
// GpuOpts is a Value type for parsing mounts
@@ -21,7 +21,11 @@ func parseCount(s string) (int, error) {
2121
}
2222
i, err := strconv.Atoi(s)
2323
if err != nil {
24-
return 0, errors.Wrap(err, "count must be an integer")
24+
var numErr *strconv.NumError
25+
if errors.As(err, &numErr) {
26+
err = numErr.Err
27+
}
28+
return 0, fmt.Errorf(`invalid count (%s): value must be either "all" or an integer: %w`, s, err)
2529
}
2630
return i, nil
2731
}
@@ -72,7 +76,7 @@ func (o *GpuOpts) Set(value string) error {
7276
r := csv.NewReader(strings.NewReader(val))
7377
optFields, err := r.Read()
7478
if err != nil {
75-
return errors.Wrap(err, "failed to read gpu options")
79+
return fmt.Errorf("failed to read gpu options: %w", err)
7680
}
7781
req.Options = ConvertKVStringsToMap(optFields)
7882
default:

opts/gpus_test.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ func TestGpusOptAll(t *testing.T) {
1616
"count=-1",
1717
} {
1818
var gpus GpuOpts
19-
gpus.Set(testcase)
19+
assert.Check(t, gpus.Set(testcase))
2020
gpuReqs := gpus.Value()
2121
assert.Assert(t, is.Len(gpuReqs, 1))
2222
assert.Check(t, is.DeepEqual(gpuReqs[0], container.DeviceRequest{
@@ -27,15 +27,21 @@ func TestGpusOptAll(t *testing.T) {
2727
}
2828
}
2929

30+
func TestGpusOptInvalidCount(t *testing.T) {
31+
var gpus GpuOpts
32+
err := gpus.Set(`count=invalid-integer`)
33+
assert.Error(t, err, `invalid count (invalid-integer): value must be either "all" or an integer: invalid syntax`)
34+
}
35+
3036
func TestGpusOpts(t *testing.T) {
3137
for _, testcase := range []string{
32-
"driver=nvidia,\"capabilities=compute,utility\",\"options=foo=bar,baz=qux\"",
33-
"1,driver=nvidia,\"capabilities=compute,utility\",\"options=foo=bar,baz=qux\"",
34-
"count=1,driver=nvidia,\"capabilities=compute,utility\",\"options=foo=bar,baz=qux\"",
35-
"driver=nvidia,\"capabilities=compute,utility\",\"options=foo=bar,baz=qux\",count=1",
38+
`driver=nvidia,"capabilities=compute,utility","options=foo=bar,baz=qux"`,
39+
`1,driver=nvidia,"capabilities=compute,utility","options=foo=bar,baz=qux"`,
40+
`count=1,driver=nvidia,"capabilities=compute,utility","options=foo=bar,baz=qux"`,
41+
`driver=nvidia,"capabilities=compute,utility","options=foo=bar,baz=qux",count=1`,
3642
} {
3743
var gpus GpuOpts
38-
gpus.Set(testcase)
44+
assert.Check(t, gpus.Set(testcase))
3945
gpuReqs := gpus.Value()
4046
assert.Assert(t, is.Len(gpuReqs, 1))
4147
assert.Check(t, is.DeepEqual(gpuReqs[0], container.DeviceRequest{

opts/mount.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,7 @@ func (m *MountOpt) Set(value string) error {
135135
// TODO: implicitly set propagation and error if the user specifies a propagation in a future refactor/UX polish pass
136136
// https://github.com/docker/cli/pull/4316#discussion_r1341974730
137137
default:
138-
return fmt.Errorf("invalid value for %s: %s (must be \"enabled\", \"disabled\", \"writable\", or \"readonly\")",
139-
key, val)
138+
return fmt.Errorf(`invalid value for %s: %s (must be "enabled", "disabled", "writable", or "readonly")`, key, val)
140139
}
141140
case "volume-subpath":
142141
volumeOptions().Subpath = val

opts/network.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,11 @@ func (n *NetworkOpt) Set(value string) error { //nolint:gocyclo
8989
case gwPriorityOpt:
9090
netOpt.GwPriority, err = strconv.Atoi(val)
9191
if err != nil {
92-
return fmt.Errorf("invalid gw-priority: %w", err)
92+
var numErr *strconv.NumError
93+
if errors.As(err, &numErr) {
94+
err = numErr.Err
95+
}
96+
return fmt.Errorf("invalid gw-priority (%s): %w", val, err)
9397
}
9498
default:
9599
return errors.New("invalid field key " + key)

opts/network_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@ func TestNetworkOptAdvancedSyntaxInvalid(t *testing.T) {
149149
value: "driver-opt=field1=value1,driver-opt=field2=value2",
150150
expectedError: "network name/id is not specified",
151151
},
152+
{
153+
value: "gw-priority=invalid-integer",
154+
expectedError: "invalid gw-priority (invalid-integer): invalid syntax",
155+
},
152156
}
153157
for _, tc := range testCases {
154158
t.Run(tc.value, func(t *testing.T) {

opts/opts.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package opts
22

33
import (
4+
"errors"
45
"fmt"
56
"math/big"
67
"net"
@@ -9,8 +10,7 @@ import (
910
"strings"
1011

1112
"github.com/docker/docker/api/types/filters"
12-
units "github.com/docker/go-units"
13-
"github.com/pkg/errors"
13+
"github.com/docker/go-units"
1414
)
1515

1616
var (

opts/opts_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,10 @@ func TestListOptsWithoutValidator(t *testing.T) {
136136
t.Errorf("%d != 3", o.Len())
137137
}
138138
if !o.Get("bar") {
139-
t.Error("o.Get(\"bar\") == false")
139+
t.Error(`o.Get("bar") == false`)
140140
}
141141
if o.Get("baz") {
142-
t.Error("o.Get(\"baz\") == true")
142+
t.Error(`o.Get("baz") == true`)
143143
}
144144
o.Delete("foo")
145145
if o.String() != "[bar bar]" {

opts/port.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,42 +46,50 @@ func (p *PortOpt) Set(value string) error {
4646
// TODO(thaJeztah): these options should not be case-insensitive.
4747
key, val, ok := strings.Cut(strings.ToLower(field), "=")
4848
if !ok || key == "" {
49-
return fmt.Errorf("invalid field %s", field)
49+
return fmt.Errorf("invalid field: %s", field)
5050
}
5151
switch key {
5252
case portOptProtocol:
5353
if val != string(swarm.PortConfigProtocolTCP) && val != string(swarm.PortConfigProtocolUDP) && val != string(swarm.PortConfigProtocolSCTP) {
54-
return fmt.Errorf("invalid protocol value %s", val)
54+
return fmt.Errorf("invalid protocol value '%s'", val)
5555
}
5656

5757
pConfig.Protocol = swarm.PortConfigProtocol(val)
5858
case portOptMode:
5959
if val != string(swarm.PortConfigPublishModeIngress) && val != string(swarm.PortConfigPublishModeHost) {
60-
return fmt.Errorf("invalid publish mode value %s", val)
60+
return fmt.Errorf("invalid publish mode value (%s): must be either '%s' or '%s'", val, swarm.PortConfigPublishModeIngress, swarm.PortConfigPublishModeHost)
6161
}
6262

6363
pConfig.PublishMode = swarm.PortConfigPublishMode(val)
6464
case portOptTargetPort:
6565
tPort, err := strconv.ParseUint(val, 10, 16)
6666
if err != nil {
67-
return err
67+
var numErr *strconv.NumError
68+
if errors.As(err, &numErr) {
69+
err = numErr.Err
70+
}
71+
return fmt.Errorf("invalid target port (%s): value must be an integer: %w", val, err)
6872
}
6973

7074
pConfig.TargetPort = uint32(tPort)
7175
case portOptPublishedPort:
7276
pPort, err := strconv.ParseUint(val, 10, 16)
7377
if err != nil {
74-
return err
78+
var numErr *strconv.NumError
79+
if errors.As(err, &numErr) {
80+
err = numErr.Err
81+
}
82+
return fmt.Errorf("invalid published port (%s): value must be an integer: %w", val, err)
7583
}
7684

7785
pConfig.PublishedPort = uint32(pPort)
7886
default:
79-
return fmt.Errorf("invalid field key %s", key)
87+
return fmt.Errorf("invalid field key: %s", key)
8088
}
8189
}
8290

8391
if pConfig.TargetPort == 0 {
84-
return fmt.Errorf("missing mandatory field %q", portOptTargetPort)
92+
return fmt.Errorf("missing mandatory field '%s'", portOptTargetPort)
8593
}
8694

8795
if pConfig.PublishMode == "" {

0 commit comments

Comments
 (0)