Skip to content

Commit

Permalink
abstract the string slice struct to stringutils package
Browse files Browse the repository at this point in the history
Signed-off-by: Shijiang Wei <[email protected]>
  • Loading branch information
mountkin committed Aug 28, 2015
1 parent fdc73cc commit ea4a067
Show file tree
Hide file tree
Showing 11 changed files with 218 additions and 340 deletions.
11 changes: 6 additions & 5 deletions builder/dispatchers.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/Sirupsen/logrus"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/nat"
"github.com/docker/docker/pkg/stringutils"
"github.com/docker/docker/runconfig"
)

Expand Down Expand Up @@ -352,7 +353,7 @@ func run(b *builder, args []string, attributes map[string]bool, original string)
b.Config.Cmd = config.Cmd
runconfig.Merge(b.Config, config)

defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd)
defer func(cmd *stringutils.StrSlice) { b.Config.Cmd = cmd }(cmd)

logrus.Debugf("[BUILDER] Command to be executed: %v", b.Config.Cmd)

Expand Down Expand Up @@ -405,7 +406,7 @@ func cmd(b *builder, args []string, attributes map[string]bool, original string)
}
}

b.Config.Cmd = runconfig.NewCommand(cmdSlice...)
b.Config.Cmd = stringutils.NewStrSlice(cmdSlice...)

if err := b.commit("", b.Config.Cmd, fmt.Sprintf("CMD %q", cmdSlice)); err != nil {
return err
Expand Down Expand Up @@ -436,16 +437,16 @@ func entrypoint(b *builder, args []string, attributes map[string]bool, original
switch {
case attributes["json"]:
// ENTRYPOINT ["echo", "hi"]
b.Config.Entrypoint = runconfig.NewEntrypoint(parsed...)
b.Config.Entrypoint = stringutils.NewStrSlice(parsed...)
case len(parsed) == 0:
// ENTRYPOINT []
b.Config.Entrypoint = nil
default:
// ENTRYPOINT echo hi
if runtime.GOOS != "windows" {
b.Config.Entrypoint = runconfig.NewEntrypoint("/bin/sh", "-c", parsed[0])
b.Config.Entrypoint = stringutils.NewStrSlice("/bin/sh", "-c", parsed[0])
} else {
b.Config.Entrypoint = runconfig.NewEntrypoint("cmd", "/S /C", parsed[0])
b.Config.Entrypoint = stringutils.NewStrSlice("cmd", "/S /C", parsed[0])
}
}

Expand Down
17 changes: 9 additions & 8 deletions builder/internals.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/progressreader"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/stringutils"
"github.com/docker/docker/pkg/system"
"github.com/docker/docker/pkg/tarsum"
"github.com/docker/docker/pkg/urlutil"
Expand Down Expand Up @@ -73,7 +74,7 @@ func (b *builder) readContext(context io.Reader) (err error) {
return
}

func (b *builder) commit(id string, autoCmd *runconfig.Command, comment string) error {
func (b *builder) commit(id string, autoCmd *stringutils.StrSlice, comment string) error {
if b.disableCommit {
return nil
}
Expand All @@ -84,11 +85,11 @@ func (b *builder) commit(id string, autoCmd *runconfig.Command, comment string)
if id == "" {
cmd := b.Config.Cmd
if runtime.GOOS != "windows" {
b.Config.Cmd = runconfig.NewCommand("/bin/sh", "-c", "#(nop) "+comment)
b.Config.Cmd = stringutils.NewStrSlice("/bin/sh", "-c", "#(nop) "+comment)
} else {
b.Config.Cmd = runconfig.NewCommand("cmd", "/S /C", "REM (nop) "+comment)
b.Config.Cmd = stringutils.NewStrSlice("cmd", "/S /C", "REM (nop) "+comment)
}
defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd)
defer func(cmd *stringutils.StrSlice) { b.Config.Cmd = cmd }(cmd)

hit, err := b.probeCache()
if err != nil {
Expand Down Expand Up @@ -215,11 +216,11 @@ func (b *builder) runContextCommand(args []string, allowRemote bool, allowDecomp

cmd := b.Config.Cmd
if runtime.GOOS != "windows" {
b.Config.Cmd = runconfig.NewCommand("/bin/sh", "-c", fmt.Sprintf("#(nop) %s %s in %s", cmdName, srcHash, dest))
b.Config.Cmd = stringutils.NewStrSlice("/bin/sh", "-c", fmt.Sprintf("#(nop) %s %s in %s", cmdName, srcHash, dest))
} else {
b.Config.Cmd = runconfig.NewCommand("cmd", "/S /C", fmt.Sprintf("REM (nop) %s %s in %s", cmdName, srcHash, dest))
b.Config.Cmd = stringutils.NewStrSlice("cmd", "/S /C", fmt.Sprintf("REM (nop) %s %s in %s", cmdName, srcHash, dest))
}
defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd)
defer func(cmd *stringutils.StrSlice) { b.Config.Cmd = cmd }(cmd)

hit, err := b.probeCache()
if err != nil {
Expand Down Expand Up @@ -630,7 +631,7 @@ func (b *builder) create() (*daemon.Container, error) {
c.Path = s[0]
c.Args = s[1:]
} else {
config.Cmd = runconfig.NewCommand()
config.Cmd = stringutils.NewStrSlice()
}

return c, nil
Expand Down
3 changes: 2 additions & 1 deletion daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/docker/docker/pkg/nat"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/stringutils"
"github.com/docker/docker/pkg/sysinfo"
"github.com/docker/docker/pkg/system"
"github.com/docker/docker/pkg/truncindex"
Expand Down Expand Up @@ -437,7 +438,7 @@ func (daemon *Daemon) generateHostname(id string, config *runconfig.Config) {
}
}

func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint *runconfig.Entrypoint, configCmd *runconfig.Command) (string, []string) {
func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint *stringutils.StrSlice, configCmd *stringutils.StrSlice) (string, []string) {
var (
entrypoint string
args []string
Expand Down
5 changes: 3 additions & 2 deletions daemon/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/pools"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/stringutils"
"github.com/docker/docker/runconfig"
)

Expand Down Expand Up @@ -139,8 +140,8 @@ func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, erro
return "", err
}

cmd := runconfig.NewCommand(config.Cmd...)
entrypoint, args := d.getEntrypointAndArgs(runconfig.NewEntrypoint(), cmd)
cmd := stringutils.NewStrSlice(config.Cmd...)
entrypoint, args := d.getEntrypointAndArgs(stringutils.NewStrSlice(), cmd)

user := config.User
if len(user) == 0 {
Expand Down
71 changes: 71 additions & 0 deletions pkg/stringutils/strslice.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package stringutils

import (
"encoding/json"
"strings"
)

// StrSlice representes a string or an array of strings.
// We need to override the json decoder to accept both options.
type StrSlice struct {
parts []string
}

// MarshalJSON Marshals (or serializes) the StrSlice into the json format.
// This method is needed to implement json.Marshaller.
func (e *StrSlice) MarshalJSON() ([]byte, error) {
if e == nil {
return []byte{}, nil
}
return json.Marshal(e.Slice())
}

// 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 {
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.parts = p
return nil
}

// Len returns the number of parts of the StrSlice.
func (e *StrSlice) Len() int {
if e == nil {
return 0
}
return len(e.parts)
}

// Slice gets the parts of the StrSlice as a Slice of string.
func (e *StrSlice) Slice() []string {
if e == nil {
return nil
}
return e.parts
}

// ToString gets space separated string of all the parts.
func (e *StrSlice) ToString() string {
s := e.Slice()
if s == nil {
return ""
}
return strings.Join(s, " ")
}

// NewStrSlice creates an StrSlice based on the specified parts (as strings).
func NewStrSlice(parts ...string) *StrSlice {
return &StrSlice{parts}
}
105 changes: 105 additions & 0 deletions pkg/stringutils/strslice_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package stringutils

import (
"encoding/json"
"testing"
)

func TestStrSliceMarshalJSON(t *testing.T) {
strss := map[*StrSlice]string{
nil: "",
&StrSlice{}: "null",
&StrSlice{[]string{"/bin/sh", "-c", "echo"}}: `["/bin/sh","-c","echo"]`,
}

for strs, expected := range strss {
data, err := strs.MarshalJSON()
if err != nil {
t.Fatal(err)
}
if string(data) != expected {
t.Fatalf("Expected %v, got %v", expected, string(data))
}
}
}

func TestStrSliceUnmarshalJSON(t *testing.T) {
parts := map[string][]string{
"": {"default", "values"},
"[]": {},
`["/bin/sh","-c","echo"]`: {"/bin/sh", "-c", "echo"},
}
for json, expectedParts := range parts {
strs := &StrSlice{
[]string{"default", "values"},
}
if err := strs.UnmarshalJSON([]byte(json)); err != nil {
t.Fatal(err)
}

actualParts := strs.Slice()
if len(actualParts) != len(expectedParts) {
t.Fatalf("Expected %v parts, got %v (%v)", len(expectedParts), len(actualParts), expectedParts)
}
for index, part := range actualParts {
if part != expectedParts[index] {
t.Fatalf("Expected %v, got %v", expectedParts, actualParts)
break
}
}
}
}

func TestStrSliceUnmarshalString(t *testing.T) {
var e *StrSlice
echo, err := json.Marshal("echo")
if err != nil {
t.Fatal(err)
}
if err := json.Unmarshal(echo, &e); err != nil {
t.Fatal(err)
}

slice := e.Slice()
if len(slice) != 1 {
t.Fatalf("expected 1 element after unmarshal: %q", slice)
}

if slice[0] != "echo" {
t.Fatalf("expected `echo`, got: %q", slice[0])
}
}

func TestStrSliceUnmarshalSlice(t *testing.T) {
var e *StrSlice
echo, err := json.Marshal([]string{"echo"})
if err != nil {
t.Fatal(err)
}
if err := json.Unmarshal(echo, &e); err != nil {
t.Fatal(err)
}

slice := e.Slice()
if len(slice) != 1 {
t.Fatalf("expected 1 element after unmarshal: %q", slice)
}

if slice[0] != "echo" {
t.Fatalf("expected `echo`, got: %q", slice[0])
}
}

func TestStrSliceToString(t *testing.T) {
slices := map[*StrSlice]string{
NewStrSlice(""): "",
NewStrSlice("one"): "one",
NewStrSlice("one", "two"): "one two",
}
for s, expected := range slices {
toString := s.ToString()
if toString != expected {
t.Fatalf("Expected %v, got %v", expected, toString)
}
}
}
13 changes: 7 additions & 6 deletions runconfig/compare_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"testing"

"github.com/docker/docker/pkg/nat"
"github.com/docker/docker/pkg/stringutils"
)

// Just to make life easier
Expand Down Expand Up @@ -32,12 +33,12 @@ func TestCompare(t *testing.T) {
volumes3["/test3"] = struct{}{}
envs1 := []string{"ENV1=value1", "ENV2=value2"}
envs2 := []string{"ENV1=value1", "ENV3=value3"}
entrypoint1 := &Entrypoint{parts: []string{"/bin/sh", "-c"}}
entrypoint2 := &Entrypoint{parts: []string{"/bin/sh", "-d"}}
entrypoint3 := &Entrypoint{parts: []string{"/bin/sh", "-c", "echo"}}
cmd1 := &Command{parts: []string{"/bin/sh", "-c"}}
cmd2 := &Command{parts: []string{"/bin/sh", "-d"}}
cmd3 := &Command{parts: []string{"/bin/sh", "-c", "echo"}}
entrypoint1 := stringutils.NewStrSlice("/bin/sh", "-c")
entrypoint2 := stringutils.NewStrSlice("/bin/sh", "-d")
entrypoint3 := stringutils.NewStrSlice("/bin/sh", "-c", "echo")
cmd1 := stringutils.NewStrSlice("/bin/sh", "-c")
cmd2 := stringutils.NewStrSlice("/bin/sh", "-d")
cmd3 := stringutils.NewStrSlice("/bin/sh", "-c", "echo")
labels1 := map[string]string{"LABEL1": "value1", "LABEL2": "value2"}
labels2 := map[string]string{"LABEL1": "value1", "LABEL2": "value3"}
labels3 := map[string]string{"LABEL1": "value1", "LABEL2": "value2", "LABEL3": "value3"}
Expand Down
Loading

0 comments on commit ea4a067

Please sign in to comment.