Browse code

LCOW: Set correct default shell for platform in builder

Signed-off-by: John Howard <jhoward@microsoft.com>

John Howard authored on 2017/06/21 07:08:58
Showing 6 changed files
... ...
@@ -2,4 +2,6 @@
2 2
 
3 3
 package dockerfile
4 4
 
5
-var defaultShell = []string{"/bin/sh", "-c"}
5
+func defaultShellForPlatform(platform string) []string {
6
+	return []string{"/bin/sh", "-c"}
7
+}
... ...
@@ -1,3 +1,8 @@
1 1
 package dockerfile
2 2
 
3
-var defaultShell = []string{"cmd", "/S", "/C"}
3
+func defaultShellForPlatform(platform string) []string {
4
+	if platform == "linux" {
5
+		return []string{"/bin/sh", "-c"}
6
+	}
7
+	return []string{"cmd", "/S", "/C"}
8
+}
... ...
@@ -399,7 +399,7 @@ func workdir(req dispatchRequest) error {
399 399
 	}
400 400
 
401 401
 	comment := "WORKDIR " + runConfig.WorkingDir
402
-	runConfigWithCommentCmd := copyRunConfig(runConfig, withCmdCommentString(comment))
402
+	runConfigWithCommentCmd := copyRunConfig(runConfig, withCmdCommentString(comment, req.builder.platform))
403 403
 	containerID, err := req.builder.probeAndCreate(req.state, runConfigWithCommentCmd)
404 404
 	if err != nil || containerID == "" {
405 405
 		return err
... ...
@@ -417,7 +417,7 @@ func workdir(req dispatchRequest) error {
417 417
 // the current SHELL which defaults to 'sh -c' under linux or 'cmd /S /C' under
418 418
 // Windows, in the event there is only one argument The difference in processing:
419 419
 //
420
-// RUN echo hi          # sh -c echo hi       (Linux)
420
+// RUN echo hi          # sh -c echo hi       (Linux and LCOW)
421 421
 // RUN echo hi          # cmd /S /C echo hi   (Windows)
422 422
 // RUN [ "echo", "hi" ] # echo hi
423 423
 //
... ...
@@ -433,7 +433,7 @@ func run(req dispatchRequest) error {
433 433
 	stateRunConfig := req.state.runConfig
434 434
 	args := handleJSONArgs(req.args, req.attributes)
435 435
 	if !req.attributes["json"] {
436
-		args = append(getShell(stateRunConfig), args...)
436
+		args = append(getShell(stateRunConfig, req.builder.platform), args...)
437 437
 	}
438 438
 	cmdFromArgs := strslice.StrSlice(args)
439 439
 	buildArgs := req.builder.buildArgs.FilterAllowed(stateRunConfig.Env)
... ...
@@ -518,7 +518,7 @@ func cmd(req dispatchRequest) error {
518 518
 	runConfig := req.state.runConfig
519 519
 	cmdSlice := handleJSONArgs(req.args, req.attributes)
520 520
 	if !req.attributes["json"] {
521
-		cmdSlice = append(getShell(runConfig), cmdSlice...)
521
+		cmdSlice = append(getShell(runConfig, req.builder.platform), cmdSlice...)
522 522
 	}
523 523
 
524 524
 	runConfig.Cmd = strslice.StrSlice(cmdSlice)
... ...
@@ -670,7 +670,7 @@ func entrypoint(req dispatchRequest) error {
670 670
 		runConfig.Entrypoint = nil
671 671
 	default:
672 672
 		// ENTRYPOINT echo hi
673
-		runConfig.Entrypoint = strslice.StrSlice(append(getShell(runConfig), parsed[0]))
673
+		runConfig.Entrypoint = strslice.StrSlice(append(getShell(runConfig, req.builder.platform), parsed[0]))
674 674
 	}
675 675
 
676 676
 	// when setting the entrypoint if a CMD was not explicitly set then
... ...
@@ -474,7 +474,7 @@ func TestRunWithBuildArgs(t *testing.T) {
474 474
 
475 475
 	runConfig := &container.Config{}
476 476
 	origCmd := strslice.StrSlice([]string{"cmd", "in", "from", "image"})
477
-	cmdWithShell := strslice.StrSlice(append(getShell(runConfig), "echo foo"))
477
+	cmdWithShell := strslice.StrSlice(append(getShell(runConfig, runtime.GOOS), "echo foo"))
478 478
 	envVars := []string{"|1", "one=two"}
479 479
 	cachedCmd := strslice.StrSlice(append(envVars, cmdWithShell...))
480 480
 
... ...
@@ -25,7 +25,7 @@ func (b *Builder) commit(dispatchState *dispatchState, comment string) error {
25 25
 		return errors.New("Please provide a source image with `from` prior to commit")
26 26
 	}
27 27
 
28
-	runConfigWithCommentCmd := copyRunConfig(dispatchState.runConfig, withCmdComment(comment))
28
+	runConfigWithCommentCmd := copyRunConfig(dispatchState.runConfig, withCmdComment(comment, b.platform))
29 29
 	hit, err := b.probeCache(dispatchState, runConfigWithCommentCmd)
30 30
 	if err != nil || hit {
31 31
 		return err
... ...
@@ -110,7 +110,7 @@ func (b *Builder) performCopy(state *dispatchState, inst copyInstruction) error
110 110
 	// TODO: should this have been using origPaths instead of srcHash in the comment?
111 111
 	runConfigWithCommentCmd := copyRunConfig(
112 112
 		state.runConfig,
113
-		withCmdCommentString(fmt.Sprintf("%s %s in %s ", inst.cmdName, srcHash, inst.dest)))
113
+		withCmdCommentString(fmt.Sprintf("%s %s in %s ", inst.cmdName, srcHash, inst.dest), b.platform))
114 114
 	hit, err := b.probeCache(state, runConfigWithCommentCmd)
115 115
 	if err != nil || hit {
116 116
 		return err
... ...
@@ -190,9 +190,9 @@ func withCmd(cmd []string) runConfigModifier {
190 190
 
191 191
 // withCmdComment sets Cmd to a nop comment string. See withCmdCommentString for
192 192
 // why there are two almost identical versions of this.
193
-func withCmdComment(comment string) runConfigModifier {
193
+func withCmdComment(comment string, platform string) runConfigModifier {
194 194
 	return func(runConfig *container.Config) {
195
-		runConfig.Cmd = append(getShell(runConfig), "#(nop) ", comment)
195
+		runConfig.Cmd = append(getShell(runConfig, platform), "#(nop) ", comment)
196 196
 	}
197 197
 }
198 198
 
... ...
@@ -200,9 +200,9 @@ func withCmdComment(comment string) runConfigModifier {
200 200
 // A few instructions (workdir, copy, add) used a nop comment that is a single arg
201 201
 // where as all the other instructions used a two arg comment string. This
202 202
 // function implements the single arg version.
203
-func withCmdCommentString(comment string) runConfigModifier {
203
+func withCmdCommentString(comment string, platform string) runConfigModifier {
204 204
 	return func(runConfig *container.Config) {
205
-		runConfig.Cmd = append(getShell(runConfig), "#(nop) "+comment)
205
+		runConfig.Cmd = append(getShell(runConfig, platform), "#(nop) "+comment)
206 206
 	}
207 207
 }
208 208
 
... ...
@@ -229,9 +229,9 @@ func withEntrypointOverride(cmd []string, entrypoint []string) runConfigModifier
229 229
 
230 230
 // getShell is a helper function which gets the right shell for prefixing the
231 231
 // shell-form of RUN, ENTRYPOINT and CMD instructions
232
-func getShell(c *container.Config) []string {
232
+func getShell(c *container.Config, platform string) []string {
233 233
 	if 0 == len(c.Shell) {
234
-		return append([]string{}, defaultShell[:]...)
234
+		return append([]string{}, defaultShellForPlatform(platform)[:]...)
235 235
 	}
236 236
 	return append([]string{}, c.Shell[:]...)
237 237
 }
... ...
@@ -2,6 +2,7 @@ package dockerfile
2 2
 
3 3
 import (
4 4
 	"fmt"
5
+	"runtime"
5 6
 	"testing"
6 7
 
7 8
 	"github.com/docker/docker/api/types"
... ...
@@ -97,9 +98,9 @@ func TestCopyRunConfig(t *testing.T) {
97 97
 		},
98 98
 		{
99 99
 			doc:       "Set the command to a comment",
100
-			modifiers: []runConfigModifier{withCmdComment("comment")},
100
+			modifiers: []runConfigModifier{withCmdComment("comment", runtime.GOOS)},
101 101
 			expected: &container.Config{
102
-				Cmd: append(defaultShell, "#(nop) ", "comment"),
102
+				Cmd: append(defaultShellForPlatform(runtime.GOOS), "#(nop) ", "comment"),
103 103
 				Env: defaultEnv,
104 104
 			},
105 105
 		},