Merge pull request #50292 from thaJeztah/deprecate_strslice

Deprecate api/types/strslice.StrSlice and remove its use
This commit is contained in:
Sebastiaan van Stijn
2025-08-08 14:43:17 +02:00
committed by GitHub
12 changed files with 27 additions and 165 deletions

View File

@@ -4,7 +4,6 @@ import (
"time"
dockerspec "github.com/moby/docker-image-spec/specs-go/v1"
"github.com/moby/moby/api/types/strslice"
)
// MinimumDuration puts a minimum on user configured duration.
@@ -52,13 +51,13 @@ type Config struct {
OpenStdin bool // Open stdin
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
Env []string // List of environment variable to set in the container
Cmd strslice.StrSlice // Command to run when starting the container
Cmd []string // Command to run when starting the container
Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy
ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (meaning treat as a command line) (Windows specific).
Image string // Name of the image as it was passed by the operator (e.g. could be symbolic)
Volumes map[string]struct{} // List of volumes (mounts) used for the container
WorkingDir string // Current directory (PWD) in the command will be launched
Entrypoint strslice.StrSlice // Entrypoint to run when starting the container
Entrypoint []string // Entrypoint to run when starting the container
NetworkDisabled bool `json:",omitempty"` // Is network disabled
// Mac Address of the container.
//
@@ -68,5 +67,5 @@ type Config struct {
Labels map[string]string // List of labels set to this container
StopSignal string `json:",omitempty"` // Signal to stop a container
StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container
Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT
Shell []string `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT
}

View File

@@ -9,7 +9,6 @@ import (
"github.com/moby/moby/api/types/blkiodev"
"github.com/moby/moby/api/types/mount"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/api/types/strslice"
)
// CgroupnsMode represents the cgroup namespace mode of the container
@@ -435,8 +434,8 @@ type HostConfig struct {
Annotations map[string]string `json:",omitempty"` // Arbitrary non-identifying metadata attached to container and provided to the runtime
// Applicable to UNIX platforms
CapAdd strslice.StrSlice // List of kernel capabilities to add to the container
CapDrop strslice.StrSlice // List of kernel capabilities to remove from the container
CapAdd []string // List of kernel capabilities to add to the container
CapDrop []string // List of kernel capabilities to remove from the container
CgroupnsMode CgroupnsMode // Cgroup namespace mode to use for the container
DNS []string `json:"Dns"` // List of DNS server to lookup
DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for

View File

@@ -1,30 +1,6 @@
package strslice
import "encoding/json"
// StrSlice represents a string or an array of strings.
// We need to override the json decoder to accept both options.
type StrSlice []string
// UnmarshalJSON decodes the byte slice whether it's a string or an array of
// strings. This method is needed to implement json.Unmarshaler.
func (e *StrSlice) UnmarshalJSON(b []byte) error {
if len(b) == 0 {
// With no input, we preserve the existing value by returning nil and
// leaving the target alone. This allows defining default values for
// the type.
return nil
}
p := make([]string, 0, 1)
if err := json.Unmarshal(b, &p); err != nil {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
p = append(p, s)
}
*e = p
return nil
}
//
// Deprecated: this type was used for compatibility with deprecated API versions. Use []string instead.
type StrSlice = []string

View File

@@ -1,79 +0,0 @@
package strslice
import (
"encoding/json"
"slices"
"testing"
)
func TestStrSliceMarshalJSON(t *testing.T) {
for _, testcase := range []struct {
input StrSlice
expected string
}{
// MADNESS(stevvooe): No clue why nil would be "" but empty would be
// "null". Had to make a change here that may affect compatibility.
{input: nil, expected: "null"},
{input: StrSlice{}, expected: "[]"},
{input: StrSlice{"/bin/sh", "-c", "echo"}, expected: `["/bin/sh","-c","echo"]`},
} {
data, err := json.Marshal(testcase.input)
if err != nil {
t.Fatal(err)
}
if string(data) != testcase.expected {
t.Fatalf("%#v: expected %v, got %v", testcase.input, testcase.expected, string(data))
}
}
}
func TestStrSliceUnmarshalJSON(t *testing.T) {
parts := map[string][]string{
"": {"default", "values"},
"[]": {},
`["/bin/sh","-c","echo"]`: {"/bin/sh", "-c", "echo"},
}
for input, expected := range parts {
strs := StrSlice{"default", "values"}
if err := strs.UnmarshalJSON([]byte(input)); err != nil {
t.Fatal(err)
}
actual := []string(strs)
if !slices.Equal(actual, expected) {
t.Fatalf("%#v: expected %#v, got %#v", input, expected, actual)
}
}
}
func TestStrSliceUnmarshalString(t *testing.T) {
var actual StrSlice
echo, err := json.Marshal("echo")
if err != nil {
t.Fatal(err)
}
if err := json.Unmarshal(echo, &actual); err != nil {
t.Fatal(err)
}
expected := []string{"echo"}
if !slices.Equal(actual, expected) {
t.Fatalf("expected %#v, got %#v", expected, actual)
}
}
func TestStrSliceUnmarshalSlice(t *testing.T) {
var actual StrSlice
echo, err := json.Marshal([]string{"echo"})
if err != nil {
t.Fatal(err)
}
if err := json.Unmarshal(echo, &actual); err != nil {
t.Fatal(err)
}
expected := []string{"echo"}
if !slices.Equal(actual, expected) {
t.Fatalf("expected %#v, got %#v", expected, actual)
}
}

View File

@@ -152,8 +152,8 @@ func TestContainerCreateCapabilities(t *testing.T) {
if err := json.NewDecoder(req.Body).Decode(&config); err != nil {
return nil, err
}
assert.Check(t, is.DeepEqual([]string(config.HostConfig.CapAdd), expectedCaps))
assert.Check(t, is.DeepEqual([]string(config.HostConfig.CapDrop), expectedCaps))
assert.Check(t, is.DeepEqual(config.HostConfig.CapAdd, expectedCaps))
assert.Check(t, is.DeepEqual(config.HostConfig.CapDrop, expectedCaps))
b, err := json.Marshal(container.CreateResponse{
ID: "container_id",

View File

@@ -265,7 +265,7 @@ func TestCmd(t *testing.T) {
expectedCommand = []string{"/bin/sh", "-c", "./executable"}
}
assert.Check(t, is.DeepEqual([]string(sb.state.runConfig.Cmd), expectedCommand))
assert.Check(t, is.DeepEqual(sb.state.runConfig.Cmd, expectedCommand))
assert.Check(t, sb.state.cmdSet)
}
@@ -319,7 +319,7 @@ func TestEntrypoint(t *testing.T) {
} else {
expectedEntrypoint = []string{"/bin/sh", "-c", "/usr/sbin/nginx"}
}
assert.Check(t, is.DeepEqual([]string(sb.state.runConfig.Entrypoint), expectedEntrypoint))
assert.Check(t, is.DeepEqual(sb.state.runConfig.Entrypoint, expectedEntrypoint))
}
func TestExpose(t *testing.T) {
@@ -410,7 +410,7 @@ func TestShell(t *testing.T) {
assert.NilError(t, err)
expected := shellCmd
assert.Check(t, is.DeepEqual([]string(sb.state.runConfig.Shell), expected))
assert.Check(t, is.DeepEqual(sb.state.runConfig.Shell, expected))
}
func TestPrependEnvOnCmd(t *testing.T) {
@@ -449,7 +449,7 @@ func TestRunWithBuildArgs(t *testing.T) {
imageCache := &mockImageCache{
getCacheFunc: func(parentID string, cfg *container.Config) (string, error) {
// Check the runConfig.Cmd sent to probeCache()
assert.Check(t, is.DeepEqual([]string(cfg.Cmd), cachedCmd))
assert.Check(t, is.DeepEqual(cfg.Cmd, cachedCmd))
assert.Check(t, is.Nil(cfg.Entrypoint))
return "", nil
},
@@ -472,15 +472,15 @@ func TestRunWithBuildArgs(t *testing.T) {
}
mockBackend.containerCreateFunc = func(config backend.ContainerCreateConfig) (container.CreateResponse, error) {
// Check the runConfig.Cmd sent to create()
assert.Check(t, is.DeepEqual([]string(config.Config.Cmd), cmdWithShell))
assert.Check(t, is.DeepEqual(config.Config.Cmd, cmdWithShell))
assert.Check(t, is.Contains(config.Config.Env, "one=two"))
assert.Check(t, is.DeepEqual([]string(config.Config.Entrypoint), []string{""}))
assert.Check(t, is.DeepEqual(config.Config.Entrypoint, []string{""}))
return container.CreateResponse{ID: "12345"}, nil
}
mockBackend.commitFunc = func(cfg backend.CommitConfig) (image.ID, error) {
// Check the runConfig.Cmd sent to commit()
assert.Check(t, is.DeepEqual([]string(cfg.Config.Cmd), origCmd))
assert.Check(t, is.DeepEqual([]string(cfg.ContainerConfig.Cmd), cachedCmd))
assert.Check(t, is.DeepEqual(cfg.Config.Cmd, origCmd))
assert.Check(t, is.DeepEqual(cfg.ContainerConfig.Cmd, cachedCmd))
assert.Check(t, is.Nil(cfg.Config.Entrypoint))
return "", nil
}
@@ -508,7 +508,7 @@ func TestRunWithBuildArgs(t *testing.T) {
assert.NilError(t, dispatch(context.TODO(), sb, runinst))
// Check that runConfig.Cmd has not been modified by run
assert.Check(t, is.DeepEqual([]string(sb.state.runConfig.Cmd), origCmd))
assert.Check(t, is.DeepEqual(sb.state.runConfig.Cmd, origCmd))
}
func TestRunIgnoresHealthcheck(t *testing.T) {

View File

@@ -73,7 +73,7 @@ func TestDecodeCreateRequest(t *testing.T) {
assert.NilError(t, err)
assert.Check(t, is.Equal(req.Image, tc.imgName))
assert.Check(t, is.DeepEqual([]string(req.Entrypoint), tc.entrypoint))
assert.Check(t, is.DeepEqual(req.Entrypoint, tc.entrypoint))
var expected int64 = 4194304
assert.Check(t, is.Equal(req.HostConfig.Memory, expected))

View File

@@ -446,8 +446,8 @@ func TestCreateServiceCapabilities(t *testing.T) {
// verify that the container has the capabilities option set
ctnr, err := apiClient.ContainerInspect(ctx, tasks[0].Status.ContainerStatus.ContainerID)
assert.NilError(t, err)
assert.DeepEqual(t, []string(ctnr.HostConfig.CapAdd), capAdd)
assert.DeepEqual(t, []string(ctnr.HostConfig.CapDrop), capDrop)
assert.DeepEqual(t, ctnr.HostConfig.CapAdd, capAdd)
assert.DeepEqual(t, ctnr.HostConfig.CapDrop, capDrop)
// verify that the task has the capabilities option set in the task object
assert.DeepEqual(t, tasks[0].Spec.ContainerSpec.CapabilityAdd, capAdd)

View File

@@ -4,7 +4,6 @@ import (
"time"
dockerspec "github.com/moby/docker-image-spec/specs-go/v1"
"github.com/moby/moby/api/types/strslice"
)
// MinimumDuration puts a minimum on user configured duration.
@@ -52,13 +51,13 @@ type Config struct {
OpenStdin bool // Open stdin
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
Env []string // List of environment variable to set in the container
Cmd strslice.StrSlice // Command to run when starting the container
Cmd []string // Command to run when starting the container
Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy
ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (meaning treat as a command line) (Windows specific).
Image string // Name of the image as it was passed by the operator (e.g. could be symbolic)
Volumes map[string]struct{} // List of volumes (mounts) used for the container
WorkingDir string // Current directory (PWD) in the command will be launched
Entrypoint strslice.StrSlice // Entrypoint to run when starting the container
Entrypoint []string // Entrypoint to run when starting the container
NetworkDisabled bool `json:",omitempty"` // Is network disabled
// Mac Address of the container.
//
@@ -68,5 +67,5 @@ type Config struct {
Labels map[string]string // List of labels set to this container
StopSignal string `json:",omitempty"` // Signal to stop a container
StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container
Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT
Shell []string `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT
}

View File

@@ -9,7 +9,6 @@ import (
"github.com/moby/moby/api/types/blkiodev"
"github.com/moby/moby/api/types/mount"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/api/types/strslice"
)
// CgroupnsMode represents the cgroup namespace mode of the container
@@ -435,8 +434,8 @@ type HostConfig struct {
Annotations map[string]string `json:",omitempty"` // Arbitrary non-identifying metadata attached to container and provided to the runtime
// Applicable to UNIX platforms
CapAdd strslice.StrSlice // List of kernel capabilities to add to the container
CapDrop strslice.StrSlice // List of kernel capabilities to remove from the container
CapAdd []string // List of kernel capabilities to add to the container
CapDrop []string // List of kernel capabilities to remove from the container
CgroupnsMode CgroupnsMode // Cgroup namespace mode to use for the container
DNS []string `json:"Dns"` // List of DNS server to lookup
DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for

View File

@@ -1,30 +0,0 @@
package strslice
import "encoding/json"
// StrSlice represents a string or an array of strings.
// We need to override the json decoder to accept both options.
type StrSlice []string
// UnmarshalJSON decodes the byte slice whether it's a string or an array of
// strings. This method is needed to implement json.Unmarshaler.
func (e *StrSlice) UnmarshalJSON(b []byte) error {
if len(b) == 0 {
// With no input, we preserve the existing value by returning nil and
// leaving the target alone. This allows defining default values for
// the type.
return nil
}
p := make([]string, 0, 1)
if err := json.Unmarshal(b, &p); err != nil {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
p = append(p, s)
}
*e = p
return nil
}

1
vendor/modules.txt vendored
View File

@@ -963,7 +963,6 @@ github.com/moby/moby/api/types/network
github.com/moby/moby/api/types/plugin
github.com/moby/moby/api/types/registry
github.com/moby/moby/api/types/storage
github.com/moby/moby/api/types/strslice
github.com/moby/moby/api/types/swarm
github.com/moby/moby/api/types/system
github.com/moby/moby/api/types/time