Signed-off-by: Shijiang Wei <mountkin@gmail.com>
| ... | ... |
@@ -20,6 +20,7 @@ import ( |
| 20 | 20 |
"github.com/Sirupsen/logrus" |
| 21 | 21 |
flag "github.com/docker/docker/pkg/mflag" |
| 22 | 22 |
"github.com/docker/docker/pkg/nat" |
| 23 |
+ "github.com/docker/docker/pkg/stringutils" |
|
| 23 | 24 |
"github.com/docker/docker/runconfig" |
| 24 | 25 |
) |
| 25 | 26 |
|
| ... | ... |
@@ -352,7 +353,7 @@ func run(b *builder, args []string, attributes map[string]bool, original string) |
| 352 | 352 |
b.Config.Cmd = config.Cmd |
| 353 | 353 |
runconfig.Merge(b.Config, config) |
| 354 | 354 |
|
| 355 |
- defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd)
|
|
| 355 |
+ defer func(cmd *stringutils.StrSlice) { b.Config.Cmd = cmd }(cmd)
|
|
| 356 | 356 |
|
| 357 | 357 |
logrus.Debugf("[BUILDER] Command to be executed: %v", b.Config.Cmd)
|
| 358 | 358 |
|
| ... | ... |
@@ -405,7 +406,7 @@ func cmd(b *builder, args []string, attributes map[string]bool, original string) |
| 405 | 405 |
} |
| 406 | 406 |
} |
| 407 | 407 |
|
| 408 |
- b.Config.Cmd = runconfig.NewCommand(cmdSlice...) |
|
| 408 |
+ b.Config.Cmd = stringutils.NewStrSlice(cmdSlice...) |
|
| 409 | 409 |
|
| 410 | 410 |
if err := b.commit("", b.Config.Cmd, fmt.Sprintf("CMD %q", cmdSlice)); err != nil {
|
| 411 | 411 |
return err |
| ... | ... |
@@ -436,16 +437,16 @@ func entrypoint(b *builder, args []string, attributes map[string]bool, original |
| 436 | 436 |
switch {
|
| 437 | 437 |
case attributes["json"]: |
| 438 | 438 |
// ENTRYPOINT ["echo", "hi"] |
| 439 |
- b.Config.Entrypoint = runconfig.NewEntrypoint(parsed...) |
|
| 439 |
+ b.Config.Entrypoint = stringutils.NewStrSlice(parsed...) |
|
| 440 | 440 |
case len(parsed) == 0: |
| 441 | 441 |
// ENTRYPOINT [] |
| 442 | 442 |
b.Config.Entrypoint = nil |
| 443 | 443 |
default: |
| 444 | 444 |
// ENTRYPOINT echo hi |
| 445 | 445 |
if runtime.GOOS != "windows" {
|
| 446 |
- b.Config.Entrypoint = runconfig.NewEntrypoint("/bin/sh", "-c", parsed[0])
|
|
| 446 |
+ b.Config.Entrypoint = stringutils.NewStrSlice("/bin/sh", "-c", parsed[0])
|
|
| 447 | 447 |
} else {
|
| 448 |
- b.Config.Entrypoint = runconfig.NewEntrypoint("cmd", "/S /C", parsed[0])
|
|
| 448 |
+ b.Config.Entrypoint = stringutils.NewStrSlice("cmd", "/S /C", parsed[0])
|
|
| 449 | 449 |
} |
| 450 | 450 |
} |
| 451 | 451 |
|
| ... | ... |
@@ -33,6 +33,7 @@ import ( |
| 33 | 33 |
"github.com/docker/docker/pkg/parsers" |
| 34 | 34 |
"github.com/docker/docker/pkg/progressreader" |
| 35 | 35 |
"github.com/docker/docker/pkg/stringid" |
| 36 |
+ "github.com/docker/docker/pkg/stringutils" |
|
| 36 | 37 |
"github.com/docker/docker/pkg/system" |
| 37 | 38 |
"github.com/docker/docker/pkg/tarsum" |
| 38 | 39 |
"github.com/docker/docker/pkg/urlutil" |
| ... | ... |
@@ -73,7 +74,7 @@ func (b *builder) readContext(context io.Reader) (err error) {
|
| 73 | 73 |
return |
| 74 | 74 |
} |
| 75 | 75 |
|
| 76 |
-func (b *builder) commit(id string, autoCmd *runconfig.Command, comment string) error {
|
|
| 76 |
+func (b *builder) commit(id string, autoCmd *stringutils.StrSlice, comment string) error {
|
|
| 77 | 77 |
if b.disableCommit {
|
| 78 | 78 |
return nil |
| 79 | 79 |
} |
| ... | ... |
@@ -84,11 +85,11 @@ func (b *builder) commit(id string, autoCmd *runconfig.Command, comment string) |
| 84 | 84 |
if id == "" {
|
| 85 | 85 |
cmd := b.Config.Cmd |
| 86 | 86 |
if runtime.GOOS != "windows" {
|
| 87 |
- b.Config.Cmd = runconfig.NewCommand("/bin/sh", "-c", "#(nop) "+comment)
|
|
| 87 |
+ b.Config.Cmd = stringutils.NewStrSlice("/bin/sh", "-c", "#(nop) "+comment)
|
|
| 88 | 88 |
} else {
|
| 89 |
- b.Config.Cmd = runconfig.NewCommand("cmd", "/S /C", "REM (nop) "+comment)
|
|
| 89 |
+ b.Config.Cmd = stringutils.NewStrSlice("cmd", "/S /C", "REM (nop) "+comment)
|
|
| 90 | 90 |
} |
| 91 |
- defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd)
|
|
| 91 |
+ defer func(cmd *stringutils.StrSlice) { b.Config.Cmd = cmd }(cmd)
|
|
| 92 | 92 |
|
| 93 | 93 |
hit, err := b.probeCache() |
| 94 | 94 |
if err != nil {
|
| ... | ... |
@@ -215,11 +216,11 @@ func (b *builder) runContextCommand(args []string, allowRemote bool, allowDecomp |
| 215 | 215 |
|
| 216 | 216 |
cmd := b.Config.Cmd |
| 217 | 217 |
if runtime.GOOS != "windows" {
|
| 218 |
- b.Config.Cmd = runconfig.NewCommand("/bin/sh", "-c", fmt.Sprintf("#(nop) %s %s in %s", cmdName, srcHash, dest))
|
|
| 218 |
+ b.Config.Cmd = stringutils.NewStrSlice("/bin/sh", "-c", fmt.Sprintf("#(nop) %s %s in %s", cmdName, srcHash, dest))
|
|
| 219 | 219 |
} else {
|
| 220 |
- b.Config.Cmd = runconfig.NewCommand("cmd", "/S /C", fmt.Sprintf("REM (nop) %s %s in %s", cmdName, srcHash, dest))
|
|
| 220 |
+ b.Config.Cmd = stringutils.NewStrSlice("cmd", "/S /C", fmt.Sprintf("REM (nop) %s %s in %s", cmdName, srcHash, dest))
|
|
| 221 | 221 |
} |
| 222 |
- defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd)
|
|
| 222 |
+ defer func(cmd *stringutils.StrSlice) { b.Config.Cmd = cmd }(cmd)
|
|
| 223 | 223 |
|
| 224 | 224 |
hit, err := b.probeCache() |
| 225 | 225 |
if err != nil {
|
| ... | ... |
@@ -630,7 +631,7 @@ func (b *builder) create() (*daemon.Container, error) {
|
| 630 | 630 |
c.Path = s[0] |
| 631 | 631 |
c.Args = s[1:] |
| 632 | 632 |
} else {
|
| 633 |
- config.Cmd = runconfig.NewCommand() |
|
| 633 |
+ config.Cmd = stringutils.NewStrSlice() |
|
| 634 | 634 |
} |
| 635 | 635 |
|
| 636 | 636 |
return c, nil |
| ... | ... |
@@ -33,6 +33,7 @@ import ( |
| 33 | 33 |
"github.com/docker/docker/pkg/nat" |
| 34 | 34 |
"github.com/docker/docker/pkg/signal" |
| 35 | 35 |
"github.com/docker/docker/pkg/stringid" |
| 36 |
+ "github.com/docker/docker/pkg/stringutils" |
|
| 36 | 37 |
"github.com/docker/docker/pkg/sysinfo" |
| 37 | 38 |
"github.com/docker/docker/pkg/system" |
| 38 | 39 |
"github.com/docker/docker/pkg/truncindex" |
| ... | ... |
@@ -437,7 +438,7 @@ func (daemon *Daemon) generateHostname(id string, config *runconfig.Config) {
|
| 437 | 437 |
} |
| 438 | 438 |
} |
| 439 | 439 |
|
| 440 |
-func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint *runconfig.Entrypoint, configCmd *runconfig.Command) (string, []string) {
|
|
| 440 |
+func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint *stringutils.StrSlice, configCmd *stringutils.StrSlice) (string, []string) {
|
|
| 441 | 441 |
var ( |
| 442 | 442 |
entrypoint string |
| 443 | 443 |
args []string |
| ... | ... |
@@ -14,6 +14,7 @@ import ( |
| 14 | 14 |
"github.com/docker/docker/pkg/ioutils" |
| 15 | 15 |
"github.com/docker/docker/pkg/pools" |
| 16 | 16 |
"github.com/docker/docker/pkg/stringid" |
| 17 |
+ "github.com/docker/docker/pkg/stringutils" |
|
| 17 | 18 |
"github.com/docker/docker/runconfig" |
| 18 | 19 |
) |
| 19 | 20 |
|
| ... | ... |
@@ -139,8 +140,8 @@ func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, erro |
| 139 | 139 |
return "", err |
| 140 | 140 |
} |
| 141 | 141 |
|
| 142 |
- cmd := runconfig.NewCommand(config.Cmd...) |
|
| 143 |
- entrypoint, args := d.getEntrypointAndArgs(runconfig.NewEntrypoint(), cmd) |
|
| 142 |
+ cmd := stringutils.NewStrSlice(config.Cmd...) |
|
| 143 |
+ entrypoint, args := d.getEntrypointAndArgs(stringutils.NewStrSlice(), cmd) |
|
| 144 | 144 |
|
| 145 | 145 |
user := config.User |
| 146 | 146 |
if len(user) == 0 {
|
| 147 | 147 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,71 @@ |
| 0 |
+package stringutils |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "encoding/json" |
|
| 4 |
+ "strings" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+// StrSlice representes a string or an array of strings. |
|
| 8 |
+// We need to override the json decoder to accept both options. |
|
| 9 |
+type StrSlice struct {
|
|
| 10 |
+ parts []string |
|
| 11 |
+} |
|
| 12 |
+ |
|
| 13 |
+// MarshalJSON Marshals (or serializes) the StrSlice into the json format. |
|
| 14 |
+// This method is needed to implement json.Marshaller. |
|
| 15 |
+func (e *StrSlice) MarshalJSON() ([]byte, error) {
|
|
| 16 |
+ if e == nil {
|
|
| 17 |
+ return []byte{}, nil
|
|
| 18 |
+ } |
|
| 19 |
+ return json.Marshal(e.Slice()) |
|
| 20 |
+} |
|
| 21 |
+ |
|
| 22 |
+// UnmarshalJSON decodes the byte slice whether it's a string or an array of strings. |
|
| 23 |
+// This method is needed to implement json.Unmarshaler. |
|
| 24 |
+func (e *StrSlice) UnmarshalJSON(b []byte) error {
|
|
| 25 |
+ if len(b) == 0 {
|
|
| 26 |
+ return nil |
|
| 27 |
+ } |
|
| 28 |
+ |
|
| 29 |
+ p := make([]string, 0, 1) |
|
| 30 |
+ if err := json.Unmarshal(b, &p); err != nil {
|
|
| 31 |
+ var s string |
|
| 32 |
+ if err := json.Unmarshal(b, &s); err != nil {
|
|
| 33 |
+ return err |
|
| 34 |
+ } |
|
| 35 |
+ p = append(p, s) |
|
| 36 |
+ } |
|
| 37 |
+ |
|
| 38 |
+ e.parts = p |
|
| 39 |
+ return nil |
|
| 40 |
+} |
|
| 41 |
+ |
|
| 42 |
+// Len returns the number of parts of the StrSlice. |
|
| 43 |
+func (e *StrSlice) Len() int {
|
|
| 44 |
+ if e == nil {
|
|
| 45 |
+ return 0 |
|
| 46 |
+ } |
|
| 47 |
+ return len(e.parts) |
|
| 48 |
+} |
|
| 49 |
+ |
|
| 50 |
+// Slice gets the parts of the StrSlice as a Slice of string. |
|
| 51 |
+func (e *StrSlice) Slice() []string {
|
|
| 52 |
+ if e == nil {
|
|
| 53 |
+ return nil |
|
| 54 |
+ } |
|
| 55 |
+ return e.parts |
|
| 56 |
+} |
|
| 57 |
+ |
|
| 58 |
+// ToString gets space separated string of all the parts. |
|
| 59 |
+func (e *StrSlice) ToString() string {
|
|
| 60 |
+ s := e.Slice() |
|
| 61 |
+ if s == nil {
|
|
| 62 |
+ return "" |
|
| 63 |
+ } |
|
| 64 |
+ return strings.Join(s, " ") |
|
| 65 |
+} |
|
| 66 |
+ |
|
| 67 |
+// NewStrSlice creates an StrSlice based on the specified parts (as strings). |
|
| 68 |
+func NewStrSlice(parts ...string) *StrSlice {
|
|
| 69 |
+ return &StrSlice{parts}
|
|
| 70 |
+} |
| 0 | 71 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,105 @@ |
| 0 |
+package stringutils |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "encoding/json" |
|
| 4 |
+ "testing" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+func TestStrSliceMarshalJSON(t *testing.T) {
|
|
| 8 |
+ strss := map[*StrSlice]string{
|
|
| 9 |
+ nil: "", |
|
| 10 |
+ &StrSlice{}: "null",
|
|
| 11 |
+ &StrSlice{[]string{"/bin/sh", "-c", "echo"}}: `["/bin/sh","-c","echo"]`,
|
|
| 12 |
+ } |
|
| 13 |
+ |
|
| 14 |
+ for strs, expected := range strss {
|
|
| 15 |
+ data, err := strs.MarshalJSON() |
|
| 16 |
+ if err != nil {
|
|
| 17 |
+ t.Fatal(err) |
|
| 18 |
+ } |
|
| 19 |
+ if string(data) != expected {
|
|
| 20 |
+ t.Fatalf("Expected %v, got %v", expected, string(data))
|
|
| 21 |
+ } |
|
| 22 |
+ } |
|
| 23 |
+} |
|
| 24 |
+ |
|
| 25 |
+func TestStrSliceUnmarshalJSON(t *testing.T) {
|
|
| 26 |
+ parts := map[string][]string{
|
|
| 27 |
+ "": {"default", "values"},
|
|
| 28 |
+ "[]": {},
|
|
| 29 |
+ `["/bin/sh","-c","echo"]`: {"/bin/sh", "-c", "echo"},
|
|
| 30 |
+ } |
|
| 31 |
+ for json, expectedParts := range parts {
|
|
| 32 |
+ strs := &StrSlice{
|
|
| 33 |
+ []string{"default", "values"},
|
|
| 34 |
+ } |
|
| 35 |
+ if err := strs.UnmarshalJSON([]byte(json)); err != nil {
|
|
| 36 |
+ t.Fatal(err) |
|
| 37 |
+ } |
|
| 38 |
+ |
|
| 39 |
+ actualParts := strs.Slice() |
|
| 40 |
+ if len(actualParts) != len(expectedParts) {
|
|
| 41 |
+ t.Fatalf("Expected %v parts, got %v (%v)", len(expectedParts), len(actualParts), expectedParts)
|
|
| 42 |
+ } |
|
| 43 |
+ for index, part := range actualParts {
|
|
| 44 |
+ if part != expectedParts[index] {
|
|
| 45 |
+ t.Fatalf("Expected %v, got %v", expectedParts, actualParts)
|
|
| 46 |
+ break |
|
| 47 |
+ } |
|
| 48 |
+ } |
|
| 49 |
+ } |
|
| 50 |
+} |
|
| 51 |
+ |
|
| 52 |
+func TestStrSliceUnmarshalString(t *testing.T) {
|
|
| 53 |
+ var e *StrSlice |
|
| 54 |
+ echo, err := json.Marshal("echo")
|
|
| 55 |
+ if err != nil {
|
|
| 56 |
+ t.Fatal(err) |
|
| 57 |
+ } |
|
| 58 |
+ if err := json.Unmarshal(echo, &e); err != nil {
|
|
| 59 |
+ t.Fatal(err) |
|
| 60 |
+ } |
|
| 61 |
+ |
|
| 62 |
+ slice := e.Slice() |
|
| 63 |
+ if len(slice) != 1 {
|
|
| 64 |
+ t.Fatalf("expected 1 element after unmarshal: %q", slice)
|
|
| 65 |
+ } |
|
| 66 |
+ |
|
| 67 |
+ if slice[0] != "echo" {
|
|
| 68 |
+ t.Fatalf("expected `echo`, got: %q", slice[0])
|
|
| 69 |
+ } |
|
| 70 |
+} |
|
| 71 |
+ |
|
| 72 |
+func TestStrSliceUnmarshalSlice(t *testing.T) {
|
|
| 73 |
+ var e *StrSlice |
|
| 74 |
+ echo, err := json.Marshal([]string{"echo"})
|
|
| 75 |
+ if err != nil {
|
|
| 76 |
+ t.Fatal(err) |
|
| 77 |
+ } |
|
| 78 |
+ if err := json.Unmarshal(echo, &e); err != nil {
|
|
| 79 |
+ t.Fatal(err) |
|
| 80 |
+ } |
|
| 81 |
+ |
|
| 82 |
+ slice := e.Slice() |
|
| 83 |
+ if len(slice) != 1 {
|
|
| 84 |
+ t.Fatalf("expected 1 element after unmarshal: %q", slice)
|
|
| 85 |
+ } |
|
| 86 |
+ |
|
| 87 |
+ if slice[0] != "echo" {
|
|
| 88 |
+ t.Fatalf("expected `echo`, got: %q", slice[0])
|
|
| 89 |
+ } |
|
| 90 |
+} |
|
| 91 |
+ |
|
| 92 |
+func TestStrSliceToString(t *testing.T) {
|
|
| 93 |
+ slices := map[*StrSlice]string{
|
|
| 94 |
+ NewStrSlice(""): "",
|
|
| 95 |
+ NewStrSlice("one"): "one",
|
|
| 96 |
+ NewStrSlice("one", "two"): "one two",
|
|
| 97 |
+ } |
|
| 98 |
+ for s, expected := range slices {
|
|
| 99 |
+ toString := s.ToString() |
|
| 100 |
+ if toString != expected {
|
|
| 101 |
+ t.Fatalf("Expected %v, got %v", expected, toString)
|
|
| 102 |
+ } |
|
| 103 |
+ } |
|
| 104 |
+} |
| ... | ... |
@@ -4,6 +4,7 @@ import ( |
| 4 | 4 |
"testing" |
| 5 | 5 |
|
| 6 | 6 |
"github.com/docker/docker/pkg/nat" |
| 7 |
+ "github.com/docker/docker/pkg/stringutils" |
|
| 7 | 8 |
) |
| 8 | 9 |
|
| 9 | 10 |
// Just to make life easier |
| ... | ... |
@@ -32,12 +33,12 @@ func TestCompare(t *testing.T) {
|
| 32 | 32 |
volumes3["/test3"] = struct{}{}
|
| 33 | 33 |
envs1 := []string{"ENV1=value1", "ENV2=value2"}
|
| 34 | 34 |
envs2 := []string{"ENV1=value1", "ENV3=value3"}
|
| 35 |
- entrypoint1 := &Entrypoint{parts: []string{"/bin/sh", "-c"}}
|
|
| 36 |
- entrypoint2 := &Entrypoint{parts: []string{"/bin/sh", "-d"}}
|
|
| 37 |
- entrypoint3 := &Entrypoint{parts: []string{"/bin/sh", "-c", "echo"}}
|
|
| 38 |
- cmd1 := &Command{parts: []string{"/bin/sh", "-c"}}
|
|
| 39 |
- cmd2 := &Command{parts: []string{"/bin/sh", "-d"}}
|
|
| 40 |
- cmd3 := &Command{parts: []string{"/bin/sh", "-c", "echo"}}
|
|
| 35 |
+ entrypoint1 := stringutils.NewStrSlice("/bin/sh", "-c")
|
|
| 36 |
+ entrypoint2 := stringutils.NewStrSlice("/bin/sh", "-d")
|
|
| 37 |
+ entrypoint3 := stringutils.NewStrSlice("/bin/sh", "-c", "echo")
|
|
| 38 |
+ cmd1 := stringutils.NewStrSlice("/bin/sh", "-c")
|
|
| 39 |
+ cmd2 := stringutils.NewStrSlice("/bin/sh", "-d")
|
|
| 40 |
+ cmd3 := stringutils.NewStrSlice("/bin/sh", "-c", "echo")
|
|
| 41 | 41 |
labels1 := map[string]string{"LABEL1": "value1", "LABEL2": "value2"}
|
| 42 | 42 |
labels2 := map[string]string{"LABEL1": "value1", "LABEL2": "value3"}
|
| 43 | 43 |
labels3 := map[string]string{"LABEL1": "value1", "LABEL2": "value2", "LABEL3": "value3"}
|
| ... | ... |
@@ -3,132 +3,11 @@ package runconfig |
| 3 | 3 |
import ( |
| 4 | 4 |
"encoding/json" |
| 5 | 5 |
"io" |
| 6 |
- "strings" |
|
| 7 | 6 |
|
| 8 | 7 |
"github.com/docker/docker/pkg/nat" |
| 8 |
+ "github.com/docker/docker/pkg/stringutils" |
|
| 9 | 9 |
) |
| 10 | 10 |
|
| 11 |
-// Entrypoint encapsulates the container entrypoint. |
|
| 12 |
-// It might be represented as a string or an array of strings. |
|
| 13 |
-// We need to override the json decoder to accept both options. |
|
| 14 |
-// The JSON decoder will fail if the api sends an string and |
|
| 15 |
-// we try to decode it into an array of string. |
|
| 16 |
-type Entrypoint struct {
|
|
| 17 |
- parts []string |
|
| 18 |
-} |
|
| 19 |
- |
|
| 20 |
-// MarshalJSON Marshals (or serializes) the Entrypoint into the json format. |
|
| 21 |
-// This method is needed to implement json.Marshaller. |
|
| 22 |
-func (e *Entrypoint) MarshalJSON() ([]byte, error) {
|
|
| 23 |
- if e == nil {
|
|
| 24 |
- return []byte{}, nil
|
|
| 25 |
- } |
|
| 26 |
- return json.Marshal(e.Slice()) |
|
| 27 |
-} |
|
| 28 |
- |
|
| 29 |
-// UnmarshalJSON decodes the entrypoint whether it's a string or an array of strings. |
|
| 30 |
-// This method is needed to implement json.Unmarshaler. |
|
| 31 |
-func (e *Entrypoint) UnmarshalJSON(b []byte) error {
|
|
| 32 |
- if len(b) == 0 {
|
|
| 33 |
- return nil |
|
| 34 |
- } |
|
| 35 |
- |
|
| 36 |
- p := make([]string, 0, 1) |
|
| 37 |
- if err := json.Unmarshal(b, &p); err != nil {
|
|
| 38 |
- var s string |
|
| 39 |
- if err := json.Unmarshal(b, &s); err != nil {
|
|
| 40 |
- return err |
|
| 41 |
- } |
|
| 42 |
- p = append(p, s) |
|
| 43 |
- } |
|
| 44 |
- e.parts = p |
|
| 45 |
- return nil |
|
| 46 |
-} |
|
| 47 |
- |
|
| 48 |
-// Len returns the number of parts of the Entrypoint. |
|
| 49 |
-func (e *Entrypoint) Len() int {
|
|
| 50 |
- if e == nil {
|
|
| 51 |
- return 0 |
|
| 52 |
- } |
|
| 53 |
- return len(e.parts) |
|
| 54 |
-} |
|
| 55 |
- |
|
| 56 |
-// Slice gets the parts of the Entrypoint as a Slice of string. |
|
| 57 |
-func (e *Entrypoint) Slice() []string {
|
|
| 58 |
- if e == nil {
|
|
| 59 |
- return nil |
|
| 60 |
- } |
|
| 61 |
- return e.parts |
|
| 62 |
-} |
|
| 63 |
- |
|
| 64 |
-// NewEntrypoint creates an Entrypoint based on the specified parts (as strings). |
|
| 65 |
-func NewEntrypoint(parts ...string) *Entrypoint {
|
|
| 66 |
- return &Entrypoint{parts}
|
|
| 67 |
-} |
|
| 68 |
- |
|
| 69 |
-// Command encapsulates the container command. |
|
| 70 |
-// It might be represented as a string or an array of strings. |
|
| 71 |
-// We need to override the json decoder to accept both options. |
|
| 72 |
-// The JSON decoder will fail if the api sends an string and |
|
| 73 |
-// we try to decode it into an array of string. |
|
| 74 |
-type Command struct {
|
|
| 75 |
- parts []string |
|
| 76 |
-} |
|
| 77 |
- |
|
| 78 |
-// ToString gets a string representing a Command. |
|
| 79 |
-func (e *Command) ToString() string {
|
|
| 80 |
- return strings.Join(e.parts, " ") |
|
| 81 |
-} |
|
| 82 |
- |
|
| 83 |
-// MarshalJSON Marshals (or serializes) the Command into the json format. |
|
| 84 |
-// This method is needed to implement json.Marshaller. |
|
| 85 |
-func (e *Command) MarshalJSON() ([]byte, error) {
|
|
| 86 |
- if e == nil {
|
|
| 87 |
- return []byte{}, nil
|
|
| 88 |
- } |
|
| 89 |
- return json.Marshal(e.Slice()) |
|
| 90 |
-} |
|
| 91 |
- |
|
| 92 |
-// UnmarshalJSON decodes the entrypoint whether it's a string or an array of strings. |
|
| 93 |
-// This method is needed to implement json.Unmarshaler. |
|
| 94 |
-func (e *Command) UnmarshalJSON(b []byte) error {
|
|
| 95 |
- if len(b) == 0 {
|
|
| 96 |
- return nil |
|
| 97 |
- } |
|
| 98 |
- |
|
| 99 |
- p := make([]string, 0, 1) |
|
| 100 |
- if err := json.Unmarshal(b, &p); err != nil {
|
|
| 101 |
- var s string |
|
| 102 |
- if err := json.Unmarshal(b, &s); err != nil {
|
|
| 103 |
- return err |
|
| 104 |
- } |
|
| 105 |
- p = append(p, s) |
|
| 106 |
- } |
|
| 107 |
- e.parts = p |
|
| 108 |
- return nil |
|
| 109 |
-} |
|
| 110 |
- |
|
| 111 |
-// Len returns the number of parts of the Entrypoint. |
|
| 112 |
-func (e *Command) Len() int {
|
|
| 113 |
- if e == nil {
|
|
| 114 |
- return 0 |
|
| 115 |
- } |
|
| 116 |
- return len(e.parts) |
|
| 117 |
-} |
|
| 118 |
- |
|
| 119 |
-// Slice gets the parts of the Entrypoint as a Slice of string. |
|
| 120 |
-func (e *Command) Slice() []string {
|
|
| 121 |
- if e == nil {
|
|
| 122 |
- return nil |
|
| 123 |
- } |
|
| 124 |
- return e.parts |
|
| 125 |
-} |
|
| 126 |
- |
|
| 127 |
-// NewCommand creates a Command based on the specified parts (as strings). |
|
| 128 |
-func NewCommand(parts ...string) *Command {
|
|
| 129 |
- return &Command{parts}
|
|
| 130 |
-} |
|
| 131 |
- |
|
| 132 | 11 |
// Config contains the configuration data about a container. |
| 133 | 12 |
// It should hold only portable information about the container. |
| 134 | 13 |
// Here, "portable" means "independent from the host we are running on". |
| ... | ... |
@@ -146,12 +25,12 @@ type Config struct {
|
| 146 | 146 |
OpenStdin bool // Open stdin |
| 147 | 147 |
StdinOnce bool // If true, close stdin after the 1 attached client disconnects. |
| 148 | 148 |
Env []string // List of environment variable to set in the container |
| 149 |
- Cmd *Command // Command to run when starting the container |
|
| 149 |
+ Cmd *stringutils.StrSlice // Command to run when starting the container |
|
| 150 | 150 |
Image string // Name of the image as it was passed by the operator (eg. could be symbolic) |
| 151 | 151 |
Volumes map[string]struct{} // List of volumes (mounts) used for the container
|
| 152 | 152 |
VolumeDriver string // Name of the volume driver used to mount volumes |
| 153 | 153 |
WorkingDir string // Current directory (PWD) in the command will be launched |
| 154 |
- Entrypoint *Entrypoint // Entrypoint to run when starting the container |
|
| 154 |
+ Entrypoint *stringutils.StrSlice // Entrypoint to run when starting the container |
|
| 155 | 155 |
NetworkDisabled bool // Is network disabled |
| 156 | 156 |
MacAddress string // Mac Address of the container |
| 157 | 157 |
OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile |
| ... | ... |
@@ -2,124 +2,21 @@ package runconfig |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"bytes" |
| 5 |
- "encoding/json" |
|
| 6 | 5 |
"fmt" |
| 7 | 6 |
"io/ioutil" |
| 8 | 7 |
"testing" |
| 9 |
-) |
|
| 10 |
- |
|
| 11 |
-func TestEntrypointMarshalJSON(t *testing.T) {
|
|
| 12 |
- entrypoints := map[*Entrypoint]string{
|
|
| 13 |
- nil: "", |
|
| 14 |
- &Entrypoint{}: "null",
|
|
| 15 |
- &Entrypoint{[]string{"/bin/sh", "-c", "echo"}}: `["/bin/sh","-c","echo"]`,
|
|
| 16 |
- } |
|
| 17 |
- |
|
| 18 |
- for entrypoint, expected := range entrypoints {
|
|
| 19 |
- data, err := entrypoint.MarshalJSON() |
|
| 20 |
- if err != nil {
|
|
| 21 |
- t.Fatal(err) |
|
| 22 |
- } |
|
| 23 |
- if string(data) != expected {
|
|
| 24 |
- t.Fatalf("Expected %v, got %v", expected, string(data))
|
|
| 25 |
- } |
|
| 26 |
- } |
|
| 27 |
-} |
|
| 28 |
- |
|
| 29 |
-func TestEntrypointUnmarshalJSON(t *testing.T) {
|
|
| 30 |
- parts := map[string][]string{
|
|
| 31 |
- "": {"default", "values"},
|
|
| 32 |
- "[]": {},
|
|
| 33 |
- `["/bin/sh","-c","echo"]`: {"/bin/sh", "-c", "echo"},
|
|
| 34 |
- } |
|
| 35 |
- for json, expectedParts := range parts {
|
|
| 36 |
- entrypoint := &Entrypoint{
|
|
| 37 |
- []string{"default", "values"},
|
|
| 38 |
- } |
|
| 39 |
- if err := entrypoint.UnmarshalJSON([]byte(json)); err != nil {
|
|
| 40 |
- t.Fatal(err) |
|
| 41 |
- } |
|
| 42 |
- |
|
| 43 |
- actualParts := entrypoint.Slice() |
|
| 44 |
- if len(actualParts) != len(expectedParts) {
|
|
| 45 |
- t.Fatalf("Expected %v parts, got %v (%v)", len(expectedParts), len(actualParts), expectedParts)
|
|
| 46 |
- } |
|
| 47 |
- for index, part := range actualParts {
|
|
| 48 |
- if part != expectedParts[index] {
|
|
| 49 |
- t.Fatalf("Expected %v, got %v", expectedParts, actualParts)
|
|
| 50 |
- break |
|
| 51 |
- } |
|
| 52 |
- } |
|
| 53 |
- } |
|
| 54 |
-} |
|
| 55 |
- |
|
| 56 |
-func TestCommandToString(t *testing.T) {
|
|
| 57 |
- commands := map[*Command]string{
|
|
| 58 |
- &Command{[]string{""}}: "",
|
|
| 59 |
- &Command{[]string{"one"}}: "one",
|
|
| 60 |
- &Command{[]string{"one", "two"}}: "one two",
|
|
| 61 |
- } |
|
| 62 |
- for command, expected := range commands {
|
|
| 63 |
- toString := command.ToString() |
|
| 64 |
- if toString != expected {
|
|
| 65 |
- t.Fatalf("Expected %v, got %v", expected, toString)
|
|
| 66 |
- } |
|
| 67 |
- } |
|
| 68 |
-} |
|
| 69 |
- |
|
| 70 |
-func TestCommandMarshalJSON(t *testing.T) {
|
|
| 71 |
- commands := map[*Command]string{
|
|
| 72 |
- nil: "", |
|
| 73 |
- &Command{}: "null",
|
|
| 74 |
- &Command{[]string{"/bin/sh", "-c", "echo"}}: `["/bin/sh","-c","echo"]`,
|
|
| 75 |
- } |
|
| 76 |
- |
|
| 77 |
- for command, expected := range commands {
|
|
| 78 |
- data, err := command.MarshalJSON() |
|
| 79 |
- if err != nil {
|
|
| 80 |
- t.Fatal(err) |
|
| 81 |
- } |
|
| 82 |
- if string(data) != expected {
|
|
| 83 |
- t.Fatalf("Expected %v, got %v", expected, string(data))
|
|
| 84 |
- } |
|
| 85 |
- } |
|
| 86 |
-} |
|
| 87 |
- |
|
| 88 |
-func TestCommandUnmarshalJSON(t *testing.T) {
|
|
| 89 |
- parts := map[string][]string{
|
|
| 90 |
- "": {"default", "values"},
|
|
| 91 |
- "[]": {},
|
|
| 92 |
- `["/bin/sh","-c","echo"]`: {"/bin/sh", "-c", "echo"},
|
|
| 93 |
- } |
|
| 94 |
- for json, expectedParts := range parts {
|
|
| 95 |
- command := &Command{
|
|
| 96 |
- []string{"default", "values"},
|
|
| 97 |
- } |
|
| 98 |
- if err := command.UnmarshalJSON([]byte(json)); err != nil {
|
|
| 99 |
- t.Fatal(err) |
|
| 100 |
- } |
|
| 101 | 8 |
|
| 102 |
- actualParts := command.Slice() |
|
| 103 |
- if len(actualParts) != len(expectedParts) {
|
|
| 104 |
- t.Fatalf("Expected %v parts, got %v (%v)", len(expectedParts), len(actualParts), expectedParts)
|
|
| 105 |
- } |
|
| 106 |
- for index, part := range actualParts {
|
|
| 107 |
- if part != expectedParts[index] {
|
|
| 108 |
- t.Fatalf("Expected %v, got %v", expectedParts, actualParts)
|
|
| 109 |
- break |
|
| 110 |
- } |
|
| 111 |
- } |
|
| 112 |
- } |
|
| 113 |
-} |
|
| 9 |
+ "github.com/docker/docker/pkg/stringutils" |
|
| 10 |
+) |
|
| 114 | 11 |
|
| 115 | 12 |
func TestDecodeContainerConfig(t *testing.T) {
|
| 116 | 13 |
fixtures := []struct {
|
| 117 | 14 |
file string |
| 118 |
- entrypoint *Entrypoint |
|
| 15 |
+ entrypoint *stringutils.StrSlice |
|
| 119 | 16 |
}{
|
| 120 |
- {"fixtures/container_config_1_14.json", NewEntrypoint()},
|
|
| 121 |
- {"fixtures/container_config_1_17.json", NewEntrypoint("bash")},
|
|
| 122 |
- {"fixtures/container_config_1_19.json", NewEntrypoint("bash")},
|
|
| 17 |
+ {"fixtures/container_config_1_14.json", stringutils.NewStrSlice()},
|
|
| 18 |
+ {"fixtures/container_config_1_17.json", stringutils.NewStrSlice("bash")},
|
|
| 19 |
+ {"fixtures/container_config_1_19.json", stringutils.NewStrSlice("bash")},
|
|
| 123 | 20 |
} |
| 124 | 21 |
|
| 125 | 22 |
for _, f := range fixtures {
|
| ... | ... |
@@ -146,83 +43,3 @@ func TestDecodeContainerConfig(t *testing.T) {
|
| 146 | 146 |
} |
| 147 | 147 |
} |
| 148 | 148 |
} |
| 149 |
- |
|
| 150 |
-func TestEntrypointUnmarshalString(t *testing.T) {
|
|
| 151 |
- var e *Entrypoint |
|
| 152 |
- echo, err := json.Marshal("echo")
|
|
| 153 |
- if err != nil {
|
|
| 154 |
- t.Fatal(err) |
|
| 155 |
- } |
|
| 156 |
- if err := json.Unmarshal(echo, &e); err != nil {
|
|
| 157 |
- t.Fatal(err) |
|
| 158 |
- } |
|
| 159 |
- |
|
| 160 |
- slice := e.Slice() |
|
| 161 |
- if len(slice) != 1 {
|
|
| 162 |
- t.Fatalf("expected 1 element after unmarshal: %q", slice)
|
|
| 163 |
- } |
|
| 164 |
- |
|
| 165 |
- if slice[0] != "echo" {
|
|
| 166 |
- t.Fatalf("expected `echo`, got: %q", slice[0])
|
|
| 167 |
- } |
|
| 168 |
-} |
|
| 169 |
- |
|
| 170 |
-func TestEntrypointUnmarshalSlice(t *testing.T) {
|
|
| 171 |
- var e *Entrypoint |
|
| 172 |
- echo, err := json.Marshal([]string{"echo"})
|
|
| 173 |
- if err != nil {
|
|
| 174 |
- t.Fatal(err) |
|
| 175 |
- } |
|
| 176 |
- if err := json.Unmarshal(echo, &e); err != nil {
|
|
| 177 |
- t.Fatal(err) |
|
| 178 |
- } |
|
| 179 |
- |
|
| 180 |
- slice := e.Slice() |
|
| 181 |
- if len(slice) != 1 {
|
|
| 182 |
- t.Fatalf("expected 1 element after unmarshal: %q", slice)
|
|
| 183 |
- } |
|
| 184 |
- |
|
| 185 |
- if slice[0] != "echo" {
|
|
| 186 |
- t.Fatalf("expected `echo`, got: %q", slice[0])
|
|
| 187 |
- } |
|
| 188 |
-} |
|
| 189 |
- |
|
| 190 |
-func TestCommandUnmarshalSlice(t *testing.T) {
|
|
| 191 |
- var e *Command |
|
| 192 |
- echo, err := json.Marshal([]string{"echo"})
|
|
| 193 |
- if err != nil {
|
|
| 194 |
- t.Fatal(err) |
|
| 195 |
- } |
|
| 196 |
- if err := json.Unmarshal(echo, &e); err != nil {
|
|
| 197 |
- t.Fatal(err) |
|
| 198 |
- } |
|
| 199 |
- |
|
| 200 |
- slice := e.Slice() |
|
| 201 |
- if len(slice) != 1 {
|
|
| 202 |
- t.Fatalf("expected 1 element after unmarshal: %q", slice)
|
|
| 203 |
- } |
|
| 204 |
- |
|
| 205 |
- if slice[0] != "echo" {
|
|
| 206 |
- t.Fatalf("expected `echo`, got: %q", slice[0])
|
|
| 207 |
- } |
|
| 208 |
-} |
|
| 209 |
- |
|
| 210 |
-func TestCommandUnmarshalString(t *testing.T) {
|
|
| 211 |
- var e *Command |
|
| 212 |
- echo, err := json.Marshal("echo")
|
|
| 213 |
- if err != nil {
|
|
| 214 |
- t.Fatal(err) |
|
| 215 |
- } |
|
| 216 |
- if err := json.Unmarshal(echo, &e); err != nil {
|
|
| 217 |
- t.Fatal(err) |
|
| 218 |
- } |
|
| 219 |
- |
|
| 220 |
- slice := e.Slice() |
|
| 221 |
- if len(slice) != 1 {
|
|
| 222 |
- t.Fatalf("expected 1 element after unmarshal: %q", slice)
|
|
| 223 |
- } |
|
| 224 |
- |
|
| 225 |
- if slice[0] != "echo" {
|
|
| 226 |
- t.Fatalf("expected `echo`, got: %q", slice[0])
|
|
| 227 |
- } |
|
| 228 |
-} |
| ... | ... |
@@ -9,6 +9,7 @@ import ( |
| 9 | 9 |
flag "github.com/docker/docker/pkg/mflag" |
| 10 | 10 |
"github.com/docker/docker/pkg/nat" |
| 11 | 11 |
"github.com/docker/docker/pkg/parsers" |
| 12 |
+ "github.com/docker/docker/pkg/stringutils" |
|
| 12 | 13 |
"github.com/docker/docker/pkg/units" |
| 13 | 14 |
) |
| 14 | 15 |
|
| ... | ... |
@@ -199,15 +200,15 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe |
| 199 | 199 |
|
| 200 | 200 |
var ( |
| 201 | 201 |
parsedArgs = cmd.Args() |
| 202 |
- runCmd *Command |
|
| 203 |
- entrypoint *Entrypoint |
|
| 202 |
+ runCmd *stringutils.StrSlice |
|
| 203 |
+ entrypoint *stringutils.StrSlice |
|
| 204 | 204 |
image = cmd.Arg(0) |
| 205 | 205 |
) |
| 206 | 206 |
if len(parsedArgs) > 1 {
|
| 207 |
- runCmd = NewCommand(parsedArgs[1:]...) |
|
| 207 |
+ runCmd = stringutils.NewStrSlice(parsedArgs[1:]...) |
|
| 208 | 208 |
} |
| 209 | 209 |
if *flEntrypoint != "" {
|
| 210 |
- entrypoint = NewEntrypoint(*flEntrypoint) |
|
| 210 |
+ entrypoint = stringutils.NewStrSlice(*flEntrypoint) |
|
| 211 | 211 |
} |
| 212 | 212 |
|
| 213 | 213 |
lc, err := parseKeyValueOpts(flLxcOpts) |
| ... | ... |
@@ -486,7 +486,7 @@ func TestParseEntryPoint(t *testing.T) {
|
| 486 | 486 |
if err != nil {
|
| 487 | 487 |
t.Fatal(err) |
| 488 | 488 |
} |
| 489 |
- if config.Entrypoint.Len() != 1 && config.Entrypoint.parts[0] != "anything" {
|
|
| 489 |
+ if config.Entrypoint.Len() != 1 && config.Entrypoint.Slice()[0] != "anything" {
|
|
| 490 | 490 |
t.Fatalf("Expected entrypoint 'anything', got %v", config.Entrypoint)
|
| 491 | 491 |
} |
| 492 | 492 |
} |