From d38317c78173088e59c875e67eb77d2cb1b0300a Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 11 Aug 2025 15:03:39 +0200 Subject: [PATCH] cli/compose: use stdlib errors Signed-off-by: Sebastiaan van Stijn --- cli/compose/convert/service.go | 33 +++++++-------- cli/compose/convert/volume.go | 7 ++-- cli/compose/interpolation/interpolation.go | 8 ++-- cli/compose/loader/interpolate.go | 4 +- cli/compose/loader/loader.go | 48 +++++++++++----------- cli/compose/loader/merge.go | 24 +++++------ cli/compose/schema/schema.go | 3 +- 7 files changed, 63 insertions(+), 64 deletions(-) diff --git a/cli/compose/convert/service.go b/cli/compose/convert/service.go index d5aaebd7f..2b86991da 100644 --- a/cli/compose/convert/service.go +++ b/cli/compose/convert/service.go @@ -2,6 +2,8 @@ package convert import ( "context" + "errors" + "fmt" "os" "sort" "strings" @@ -14,7 +16,6 @@ import ( "github.com/moby/moby/api/types/swarm" "github.com/moby/moby/api/types/versions" "github.com/moby/moby/client" - "github.com/pkg/errors" ) const ( @@ -34,16 +35,16 @@ func Services( for _, service := range config.Services { secrets, err := convertServiceSecrets(ctx, apiClient, namespace, service.Secrets, config.Secrets) if err != nil { - return nil, errors.Wrapf(err, "service %s", service.Name) + return nil, fmt.Errorf("service %s: %w", service.Name, err) } configs, err := convertServiceConfigObjs(ctx, apiClient, namespace, service, config.Configs) if err != nil { - return nil, errors.Wrapf(err, "service %s", service.Name) + return nil, fmt.Errorf("service %s: %w", service.Name, err) } serviceSpec, err := Service(apiClient.ClientVersion(), namespace, service, config.Networks, config.Volumes, secrets, configs) if err != nil { - return nil, errors.Wrapf(err, "service %s", service.Name) + return nil, fmt.Errorf("service %s: %w", service.Name, err) } result[service.Name] = serviceSpec } @@ -212,7 +213,7 @@ func convertServiceNetworks( for networkName, network := range networks { networkConfig, ok := networkConfigs[networkName] if !ok && networkName != defaultNetwork { - return nil, errors.Errorf("undefined network %q", networkName) + return nil, fmt.Errorf("undefined network %q", networkName) } var aliases []string var driverOpts map[string]string @@ -256,7 +257,7 @@ func convertServiceSecrets( lookup := func(key string) (composetypes.FileObjectConfig, error) { secretSpec, exists := secretSpecs[key] if !exists { - return composetypes.FileObjectConfig{}, errors.Errorf("undefined secret %q", key) + return composetypes.FileObjectConfig{}, fmt.Errorf("undefined secret %q", key) } return composetypes.FileObjectConfig(secretSpec), nil } @@ -301,7 +302,7 @@ func convertServiceConfigObjs( lookup := func(key string) (composetypes.FileObjectConfig, error) { configSpec, exists := configSpecs[key] if !exists { - return composetypes.FileObjectConfig{}, errors.Errorf("undefined config %q", key) + return composetypes.FileObjectConfig{}, fmt.Errorf("undefined config %q", key) } return composetypes.FileObjectConfig(configSpec), nil } @@ -318,7 +319,7 @@ func convertServiceConfigObjs( }) } - // finally, after converting all of the file objects, create any + // finally, after converting all file objects, create any // Runtime-type configs that are needed. these are configs that are not // mounted into the container, but are used in some other way by the // container runtime. Currently, this only means CredentialSpecs, but in @@ -442,7 +443,7 @@ func convertHealthcheck(healthcheck *composetypes.HealthCheckConfig) (*container ) if healthcheck.Disable { if len(healthcheck.Test) != 0 { - return nil, errors.Errorf("test and disable can't be set at the same time") + return nil, errors.New("test and disable can't be set at the same time") } return &container.HealthConfig{ Test: []string{"NONE"}, @@ -494,7 +495,7 @@ func convertRestartPolicy(restart string, source *composetypes.RestartPolicy) (* MaxAttempts: &attempts, }, nil default: - return nil, errors.Errorf("unknown restart policy: %s", restart) + return nil, fmt.Errorf("unknown restart policy: %s", restart) } } @@ -618,12 +619,12 @@ func convertDeployMode(mode string, replicas *uint64) (swarm.ServiceMode, error) switch mode { case "global-job": if replicas != nil { - return serviceMode, errors.Errorf("replicas can only be used with replicated or replicated-job mode") + return serviceMode, errors.New("replicas can only be used with replicated or replicated-job mode") } serviceMode.GlobalJob = &swarm.GlobalJob{} case "global": if replicas != nil { - return serviceMode, errors.Errorf("replicas can only be used with replicated or replicated-job mode") + return serviceMode, errors.New("replicas can only be used with replicated or replicated-job mode") } serviceMode.Global = &swarm.GlobalService{} case "replicated-job": @@ -634,7 +635,7 @@ func convertDeployMode(mode string, replicas *uint64) (swarm.ServiceMode, error) case "replicated", "": serviceMode.Replicated = &swarm.ReplicatedService{Replicas: replicas} default: - return serviceMode, errors.Errorf("Unknown mode: %s", mode) + return serviceMode, fmt.Errorf("unknown mode: %s", mode) } return serviceMode, nil } @@ -667,9 +668,9 @@ func convertCredentialSpec(namespace Namespace, spec composetypes.CredentialSpec case l == 0: return nil, nil case l == 2: - return nil, errors.Errorf("invalid credential spec: cannot specify both %s and %s", o[0], o[1]) + return nil, fmt.Errorf("invalid credential spec: cannot specify both %s and %s", o[0], o[1]) case l > 2: - return nil, errors.Errorf("invalid credential spec: cannot specify both %s, and %s", strings.Join(o[:l-1], ", "), o[l-1]) + return nil, fmt.Errorf("invalid credential spec: cannot specify both %s, and %s", strings.Join(o[:l-1], ", "), o[l-1]) } swarmCredSpec := swarm.CredentialSpec(spec) // if we're using a swarm Config for the credential spec, over-write it @@ -688,7 +689,7 @@ func convertCredentialSpec(namespace Namespace, spec composetypes.CredentialSpec return &swarmCredSpec, nil } } - return nil, errors.Errorf("invalid credential spec: spec specifies config %v, but no such config can be found", swarmCredSpec.Config) + return nil, fmt.Errorf("invalid credential spec: spec specifies config %v, but no such config can be found", swarmCredSpec.Config) } return &swarmCredSpec, nil } diff --git a/cli/compose/convert/volume.go b/cli/compose/convert/volume.go index 778aae265..6155dffe8 100644 --- a/cli/compose/convert/volume.go +++ b/cli/compose/convert/volume.go @@ -1,11 +1,12 @@ package convert import ( + "errors" + "fmt" "strings" composetypes "github.com/docker/cli/cli/compose/types" "github.com/moby/moby/api/types/mount" - "github.com/pkg/errors" ) type volumes map[string]composetypes.VolumeConfig @@ -59,7 +60,7 @@ func handleVolumeToMount( stackVolume, exists := stackVolumes[volume.Source] if !exists { - return mount.Mount{}, errors.Errorf("undefined volume %q", volume.Source) + return mount.Mount{}, fmt.Errorf("undefined volume %q", volume.Source) } result.Source = namespace.Scope(volume.Source) @@ -219,7 +220,7 @@ func handleClusterToMount( // external volumes with a given group exist. stackVolume, exists := stackVolumes[volume.Source] if !exists { - return mount.Mount{}, errors.Errorf("undefined volume %q", volume.Source) + return mount.Mount{}, fmt.Errorf("undefined volume %q", volume.Source) } // if the volume is not specified with a group source, we may namespace diff --git a/cli/compose/interpolation/interpolation.go b/cli/compose/interpolation/interpolation.go index c7bee693a..63c73b1d7 100644 --- a/cli/compose/interpolation/interpolation.go +++ b/cli/compose/interpolation/interpolation.go @@ -4,11 +4,11 @@ package interpolation import ( + "fmt" "os" "strings" "github.com/docker/cli/cli/compose/template" - "github.com/pkg/errors" ) // Options supported by Interpolate @@ -68,7 +68,7 @@ func recursiveInterpolate(value any, path Path, opts Options) (any, error) { } casted, err := caster(newValue) if err != nil { - return casted, newPathError(path, errors.Wrap(err, "failed to cast to expected type")) + return casted, newPathError(path, fmt.Errorf("failed to cast to expected type: %w", err)) } return casted, nil @@ -104,11 +104,11 @@ func newPathError(path Path, err error) error { case nil: return nil case *template.InvalidTemplateError: - return errors.Errorf( + return fmt.Errorf( "invalid interpolation format for %s: %#v; you may need to escape any $ with another $", path, err.Template) default: - return errors.Wrapf(err, "error while interpolating %s", path) + return fmt.Errorf("error while interpolating %s: %w", path, err) } } diff --git a/cli/compose/loader/interpolate.go b/cli/compose/loader/interpolate.go index 93ac9d83d..bcbf5dd5d 100644 --- a/cli/compose/loader/interpolate.go +++ b/cli/compose/loader/interpolate.go @@ -4,11 +4,11 @@ package loader import ( + "fmt" "strconv" "strings" interp "github.com/docker/cli/cli/compose/interpolation" - "github.com/pkg/errors" ) var interpolateTypeCastMapping = map[interp.Path]interp.Cast{ @@ -67,7 +67,7 @@ func toBoolean(value string) (any, error) { case "n", "no", "false", "off": return false, nil default: - return nil, errors.Errorf("invalid boolean: %s", value) + return nil, fmt.Errorf("invalid boolean: %s", value) } } diff --git a/cli/compose/loader/loader.go b/cli/compose/loader/loader.go index 416a475e6..d59ed6792 100644 --- a/cli/compose/loader/loader.go +++ b/cli/compose/loader/loader.go @@ -4,6 +4,7 @@ package loader import ( + "errors" "fmt" "path" "path/filepath" @@ -26,7 +27,6 @@ import ( "github.com/google/shlex" "github.com/moby/moby/api/types/container" "github.com/moby/moby/api/types/versions" - "github.com/pkg/errors" "github.com/sirupsen/logrus" "gopkg.in/yaml.v3" ) @@ -65,7 +65,7 @@ func ParseYAML(source []byte) (map[string]any, error) { } _, ok := cfg.(map[string]any) if !ok { - return nil, errors.Errorf("top-level object must be a mapping") + return nil, errors.New("top-level object must be a mapping") } converted, err := convertToStringKeysRecursive(cfg, "") if err != nil { @@ -77,7 +77,7 @@ func ParseYAML(source []byte) (map[string]any, error) { // Load reads a ConfigDetails and returns a fully loaded configuration func Load(configDetails types.ConfigDetails, opt ...func(*Options)) (*types.Config, error) { if len(configDetails.ConfigFiles) < 1 { - return nil, errors.Errorf("No files specified") + return nil, errors.New("no files specified") } options := &Options{ @@ -102,7 +102,7 @@ func Load(configDetails types.ConfigDetails, opt ...func(*Options)) (*types.Conf configDetails.Version = version } if configDetails.Version != version { - return nil, errors.Errorf("version mismatched between two composefiles : %v and %v", configDetails.Version, version) + return nil, fmt.Errorf("version mismatched between two composefiles : %v and %v", configDetails.Version, version) } if err := validateForbidden(configDict); err != nil { @@ -533,7 +533,7 @@ func transformUlimits(data any) (any, error) { ulimit.Hard = value["hard"].(int) return ulimit, nil default: - return data, errors.Errorf("invalid type %T for ulimits", value) + return data, fmt.Errorf("invalid type %T for ulimits", value) } } @@ -552,7 +552,7 @@ func LoadNetworks(source map[string]any, version string) (map[string]types.Netwo switch { case network.External.Name != "": if network.Name != "" { - return nil, errors.Errorf("network %s: network.external.name and network.name conflict; only use network.name", name) + return nil, fmt.Errorf("network %s: network.external.name and network.name conflict; only use network.name", name) } if versions.GreaterThanOrEqualTo(version, "3.5") { logrus.Warnf("network %s: network.external.name is deprecated in favor of network.name", name) @@ -569,9 +569,7 @@ func LoadNetworks(source map[string]any, version string) (map[string]types.Netwo } func externalVolumeError(volume, key string) error { - return errors.Errorf( - "conflicting parameters \"external\" and %q specified for volume %q", - key, volume) + return fmt.Errorf(`conflicting parameters "external" and %q specified for volume %q`, key, volume) } // LoadVolumes produces a VolumeConfig map from a compose file Dict @@ -595,7 +593,7 @@ func LoadVolumes(source map[string]any, version string) (map[string]types.Volume return nil, externalVolumeError(name, "labels") case volume.External.Name != "": if volume.Name != "" { - return nil, errors.Errorf("volume %s: volume.external.name and volume.name conflict; only use volume.name", name) + return nil, fmt.Errorf("volume %s: volume.external.name and volume.name conflict; only use volume.name", name) } if versions.GreaterThanOrEqualTo(version, "3.4") { logrus.Warnf("volume %s: volume.external.name is deprecated in favor of volume.name", name) @@ -656,7 +654,7 @@ func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfi // handle deprecated external.name if obj.External.Name != "" { if obj.Name != "" { - return obj, errors.Errorf("%[1]s %[2]s: %[1]s.external.name and %[1]s.name conflict; only use %[1]s.name", objType, name) + return obj, fmt.Errorf("%[1]s %[2]s: %[1]s.external.name and %[1]s.name conflict; only use %[1]s.name", objType, name) } if versions.GreaterThanOrEqualTo(details.Version, "3.5") { logrus.Warnf("%[1]s %[2]s: %[1]s.external.name is deprecated in favor of %[1]s.name", objType, name) @@ -669,7 +667,7 @@ func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfi // if not "external: true" case obj.Driver != "": if obj.File != "" { - return obj, errors.Errorf("%[1]s %[2]s: %[1]s.driver and %[1]s.file conflict; only use %[1]s.driver", objType, name) + return obj, fmt.Errorf("%[1]s %[2]s: %[1]s.driver and %[1]s.file conflict; only use %[1]s.driver", objType, name) } default: obj.File = absPath(details.WorkingDir, obj.File) @@ -692,7 +690,7 @@ var transformMapStringString TransformerFunc = func(data any) (any, error) { case map[string]string: return value, nil default: - return data, errors.Errorf("invalid type %T for map[string]string", value) + return data, fmt.Errorf("invalid type %T for map[string]string", value) } } @@ -703,7 +701,7 @@ var transformExternal TransformerFunc = func(data any) (any, error) { case map[string]any: return map[string]any{"external": true, "name": value["name"]}, nil default: - return data, errors.Errorf("invalid type %T for external", value) + return data, fmt.Errorf("invalid type %T for external", value) } } @@ -731,12 +729,12 @@ var transformServicePort TransformerFunc = func(data any) (any, error) { case map[string]any: ports = append(ports, value) default: - return data, errors.Errorf("invalid type %T for port", value) + return data, fmt.Errorf("invalid type %T for port", value) } } return ports, nil default: - return data, errors.Errorf("invalid type %T for port", entries) + return data, fmt.Errorf("invalid type %T for port", entries) } } @@ -747,7 +745,7 @@ var transformStringSourceMap TransformerFunc = func(data any) (any, error) { case map[string]any: return data, nil default: - return data, errors.Errorf("invalid type %T for secret", value) + return data, fmt.Errorf("invalid type %T for secret", value) } } @@ -758,7 +756,7 @@ var transformBuildConfig TransformerFunc = func(data any) (any, error) { case map[string]any: return data, nil default: - return data, errors.Errorf("invalid type %T for service build", value) + return data, fmt.Errorf("invalid type %T for service build", value) } } @@ -769,7 +767,7 @@ var transformServiceVolumeConfig TransformerFunc = func(data any) (any, error) { case map[string]any: return data, nil default: - return data, errors.Errorf("invalid type %T for service volume", value) + return data, fmt.Errorf("invalid type %T for service volume", value) } } @@ -800,7 +798,7 @@ var transformStringList TransformerFunc = func(data any) (any, error) { case []any: return value, nil default: - return data, errors.Errorf("invalid type %T for string list", value) + return data, fmt.Errorf("invalid type %T for string list", value) } } @@ -847,7 +845,7 @@ func transformListOrMapping(listOrMapping any, sep string, allowNil bool, allowS } return result } - panic(errors.Errorf("expected a map or a list, got %T: %#v", listOrMapping, listOrMapping)) + panic(fmt.Errorf("expected a map or a list, got %T: %#v", listOrMapping, listOrMapping)) } func transformMappingOrListFunc(sep string, allowNil bool) TransformerFunc { @@ -875,7 +873,7 @@ func transformMappingOrList(mappingOrList any, sep string, allowNil bool) any { } return result } - panic(errors.Errorf("expected a map or a list, got %T: %#v", mappingOrList, mappingOrList)) + panic(fmt.Errorf("expected a map or a list, got %T: %#v", mappingOrList, mappingOrList)) } var transformShellCommand TransformerFunc = func(value any) (any, error) { @@ -892,7 +890,7 @@ var transformHealthCheckTest TransformerFunc = func(data any) (any, error) { case []any: return value, nil default: - return value, errors.Errorf("invalid type %T for healthcheck.test", value) + return value, fmt.Errorf("invalid type %T for healthcheck.test", value) } } @@ -903,7 +901,7 @@ var transformSize TransformerFunc = func(value any) (any, error) { case string: return units.RAMInBytes(value) } - panic(errors.Errorf("invalid type for size %T", value)) + panic(fmt.Errorf("invalid type for size %T", value)) } var transformStringToDuration TransformerFunc = func(value any) (any, error) { @@ -915,7 +913,7 @@ var transformStringToDuration TransformerFunc = func(value any) (any, error) { } return types.Duration(d), nil default: - return value, errors.Errorf("invalid type %T for duration", value) + return value, fmt.Errorf("invalid type %T for duration", value) } } diff --git a/cli/compose/loader/merge.go b/cli/compose/loader/merge.go index 8c0f35db4..4d7d1e029 100644 --- a/cli/compose/loader/merge.go +++ b/cli/compose/loader/merge.go @@ -4,12 +4,12 @@ package loader import ( + "fmt" "reflect" "sort" "dario.cat/mergo" "github.com/docker/cli/cli/compose/types" - "github.com/pkg/errors" ) type specials struct { @@ -29,23 +29,23 @@ func merge(configs []*types.Config) (*types.Config, error) { var err error base.Services, err = mergeServices(base.Services, override.Services) if err != nil { - return base, errors.Wrapf(err, "cannot merge services from %s", override.Filename) + return base, fmt.Errorf("cannot merge services from %s: %w", override.Filename, err) } base.Volumes, err = mergeVolumes(base.Volumes, override.Volumes) if err != nil { - return base, errors.Wrapf(err, "cannot merge volumes from %s", override.Filename) + return base, fmt.Errorf("cannot merge volumes from %s: %w", override.Filename, err) } base.Networks, err = mergeNetworks(base.Networks, override.Networks) if err != nil { - return base, errors.Wrapf(err, "cannot merge networks from %s", override.Filename) + return base, fmt.Errorf("cannot merge networks from %s: %w", override.Filename, err) } base.Secrets, err = mergeSecrets(base.Secrets, override.Secrets) if err != nil { - return base, errors.Wrapf(err, "cannot merge secrets from %s", override.Filename) + return base, fmt.Errorf("cannot merge secrets from %s: %w", override.Filename, err) } base.Configs, err = mergeConfigs(base.Configs, override.Configs) if err != nil { - return base, errors.Wrapf(err, "cannot merge configs from %s", override.Filename) + return base, fmt.Errorf("cannot merge configs from %s: %w", override.Filename, err) } } return base, nil @@ -70,7 +70,7 @@ func mergeServices(base, override []types.ServiceConfig) ([]types.ServiceConfig, for name, overrideService := range overrideServices { if baseService, ok := baseServices[name]; ok { if err := mergo.Merge(&baseService, &overrideService, mergo.WithAppendSlice, mergo.WithOverride, mergo.WithTransformers(specials)); err != nil { - return base, errors.Wrapf(err, "cannot merge service %s", name) + return base, fmt.Errorf("cannot merge service %s: %w", name, err) } baseServices[name] = baseService continue @@ -88,7 +88,7 @@ func mergeServices(base, override []types.ServiceConfig) ([]types.ServiceConfig, func toServiceSecretConfigsMap(s any) (map[any]any, error) { secrets, ok := s.([]types.ServiceSecretConfig) if !ok { - return nil, errors.Errorf("not a serviceSecretConfig: %v", s) + return nil, fmt.Errorf("not a serviceSecretConfig: %v", s) } m := map[any]any{} for _, secret := range secrets { @@ -100,7 +100,7 @@ func toServiceSecretConfigsMap(s any) (map[any]any, error) { func toServiceConfigObjConfigsMap(s any) (map[any]any, error) { secrets, ok := s.([]types.ServiceConfigObjConfig) if !ok { - return nil, errors.Errorf("not a serviceSecretConfig: %v", s) + return nil, fmt.Errorf("not a serviceSecretConfig: %v", s) } m := map[any]any{} for _, secret := range secrets { @@ -112,7 +112,7 @@ func toServiceConfigObjConfigsMap(s any) (map[any]any, error) { func toServicePortConfigsMap(s any) (map[any]any, error) { ports, ok := s.([]types.ServicePortConfig) if !ok { - return nil, errors.Errorf("not a servicePortConfig slice: %v", s) + return nil, fmt.Errorf("not a servicePortConfig slice: %v", s) } m := map[any]any{} for _, p := range ports { @@ -124,7 +124,7 @@ func toServicePortConfigsMap(s any) (map[any]any, error) { func toServiceVolumeConfigsMap(s any) (map[any]any, error) { volumes, ok := s.([]types.ServiceVolumeConfig) if !ok { - return nil, errors.Errorf("not a serviceVolumeConfig slice: %v", s) + return nil, fmt.Errorf("not a serviceVolumeConfig slice: %v", s) } m := map[any]any{} for _, v := range volumes { @@ -211,7 +211,7 @@ func mergeSlice(tomap tomapFn, writeValue writeValueFromMapFn) func(dst, src ref func sliceToMap(tomap tomapFn, v reflect.Value) (map[any]any, error) { // check if valid if !v.IsValid() { - return nil, errors.Errorf("invalid value : %+v", v) + return nil, fmt.Errorf("invalid value : %+v", v) } return tomap(v.Interface()) } diff --git a/cli/compose/schema/schema.go b/cli/compose/schema/schema.go index 1484410da..34a030bf4 100644 --- a/cli/compose/schema/schema.go +++ b/cli/compose/schema/schema.go @@ -11,7 +11,6 @@ import ( "time" "github.com/docker/go-connections/nat" - "github.com/pkg/errors" "github.com/xeipuuv/gojsonschema" ) @@ -80,7 +79,7 @@ func Validate(config map[string]any, version string) error { version = normalizeVersion(version) schemaData, err := schemas.ReadFile("data/config_schema_v" + version + ".json") if err != nil { - return errors.Errorf("unsupported Compose file version: %s", version) + return fmt.Errorf("unsupported Compose file version: %s", version) } schemaLoader := gojsonschema.NewStringLoader(string(schemaData))