integration-cli/docker_cli_build_test.go
6db32fde
 package main
 
 import (
24c00c85
 	"archive/tar"
29be7b43
 	"bytes"
4e74cd49
 	"encoding/json"
6db32fde
 	"fmt"
24c00c85
 	"io/ioutil"
f5b1afae
 	"os"
6db32fde
 	"path/filepath"
fa753e67
 	"reflect"
1150c163
 	"regexp"
d0dc14e5
 	"runtime"
29be7b43
 	"strconv"
f5b1afae
 	"strings"
29be7b43
 	"text/template"
1ce5457d
 	"time"
edcb4145
 
f41230b9
 	"github.com/docker/docker/builder/dockerfile/command"
33968e6c
 	"github.com/docker/docker/integration-cli/checker"
50c4475d
 	"github.com/docker/docker/integration-cli/cli"
 	"github.com/docker/docker/integration-cli/cli/build"
56fb4653
 	"github.com/docker/docker/integration-cli/cli/build/fakecontext"
a582d9dc
 	"github.com/docker/docker/integration-cli/cli/build/fakegit"
56fb4653
 	"github.com/docker/docker/integration-cli/cli/build/fakestorage"
7c35a241
 	"github.com/docker/docker/internal/testutil"
30d5a42c
 	"github.com/docker/docker/pkg/archive"
dc944ea7
 	"github.com/go-check/check"
92427b3a
 	"github.com/gotestyourself/gotestyourself/icmd"
9db68f4d
 	digest "github.com/opencontainers/go-digest"
6db32fde
 )
 
dc944ea7
 func (s *DockerSuite) TestBuildJSONEmptyRun(c *check.C) {
50c4475d
 	cli.BuildCmd(c, "testbuildjsonemptyrun", build.WithDockerfile(`
39343b86
     FROM busybox
     RUN []
c778f4b9
     `))
39343b86
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildShCmdJSONEntrypoint(c *check.C) {
24545c18
 	name := "testbuildshcmdjsonentrypoint"
c778f4b9
 	expected := "/bin/sh -c echo test"
18a771a7
 	if testEnv.OSType == "windows" {
c778f4b9
 		expected = "cmd /S /C echo test"
 	}
24545c18
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`
24545c18
     FROM busybox
563a4d1b
     ENTRYPOINT ["echo"]
24545c18
     CMD echo test
c778f4b9
     `))
5c295460
 	out, _ := dockerCmd(c, "run", "--rm", name)
24545c18
 
c778f4b9
 	if strings.TrimSpace(out) != expected {
 		c.Fatalf("CMD did not contain %q : %q", expected, out)
24545c18
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvironmentReplacementUser(c *check.C) {
563a4d1b
 	// Windows does not support FROM scratch or the USER command
f9a3558a
 	testRequires(c, DaemonIsLinux)
4e74cd49
 	name := "testbuildenvironmentreplacement"
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`
4e74cd49
   FROM scratch
   ENV user foo
   USER ${user}
c778f4b9
   `))
62a856e9
 	res := inspectFieldJSON(c, name, "Config.User")
4e74cd49
 
 	if res != `"foo"` {
dc944ea7
 		c.Fatal("User foo from environment not in Config.User on image")
4e74cd49
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvironmentReplacementVolume(c *check.C) {
4e74cd49
 	name := "testbuildenvironmentreplacement"
 
96c52216
 	var volumePath string
563a4d1b
 
18a771a7
 	if testEnv.OSType == "windows" {
563a4d1b
 		volumePath = "c:/quux"
 	} else {
 		volumePath = "/quux"
 	}
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`
96c52216
   FROM `+minimalBaseImage()+`
563a4d1b
   ENV volume `+volumePath+`
4e74cd49
   VOLUME ${volume}
c778f4b9
   `))
4e74cd49
 
 	var volumes map[string]interface{}
c778f4b9
 	inspectFieldAndUnmarshall(c, name, "Config.Volumes", &volumes)
563a4d1b
 	if _, ok := volumes[volumePath]; !ok {
 		c.Fatal("Volume " + volumePath + " from environment not in Config.Volumes on image")
4e74cd49
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvironmentReplacementExpose(c *check.C) {
563a4d1b
 	// Windows does not support FROM scratch or the EXPOSE command
f9a3558a
 	testRequires(c, DaemonIsLinux)
4e74cd49
 	name := "testbuildenvironmentreplacement"
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`
4e74cd49
   FROM scratch
   ENV port 80
   EXPOSE ${port}
6990f8c6
   ENV ports "  99   100 "
   EXPOSE ${ports}
c778f4b9
   `))
4e74cd49
 
 	var exposedPorts map[string]interface{}
c778f4b9
 	inspectFieldAndUnmarshall(c, name, "Config.ExposedPorts", &exposedPorts)
6990f8c6
 	exp := []int{80, 99, 100}
 	for _, p := range exp {
 		tmp := fmt.Sprintf("%d/tcp", p)
 		if _, ok := exposedPorts[tmp]; !ok {
 			c.Fatalf("Exposed port %d from environment not in Config.ExposedPorts on image", p)
 		}
4e74cd49
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvironmentReplacementWorkdir(c *check.C) {
4e74cd49
 	name := "testbuildenvironmentreplacement"
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`
4e74cd49
   FROM busybox
   ENV MYWORKDIR /work
   RUN mkdir ${MYWORKDIR}
   WORKDIR ${MYWORKDIR}
c778f4b9
   `))
 	res := inspectFieldJSON(c, name, "Config.WorkingDir")
4e74cd49
 
c778f4b9
 	expected := `"/work"`
18a771a7
 	if testEnv.OSType == "windows" {
c778f4b9
 		expected = `"C:\\work"`
 	}
 	if res != expected {
 		c.Fatalf("Workdir /workdir from environment not in Config.WorkingDir on image: %s", res)
4e74cd49
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvironmentReplacementAddCopy(c *check.C) {
4e74cd49
 	name := "testbuildenvironmentreplacement"
 
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `
96c52216
   FROM `+minimalBaseImage()+`
4e74cd49
   ENV baz foo
   ENV quux bar
   ENV dot .
39908fc6
   ENV fee fff
   ENV gee ggg
4e74cd49
 
   ADD ${baz} ${dot}
   COPY ${quux} ${dot}
39908fc6
   ADD ${zzz:-${fee}} ${dot}
   COPY ${zzz:-${gee}} ${dot}
c778f4b9
   `),
56fb4653
 		build.WithFile("foo", "test1"),
 		build.WithFile("bar", "test2"),
 		build.WithFile("fff", "test3"),
 		build.WithFile("ggg", "test4"),
c778f4b9
 	))
4e74cd49
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvironmentReplacementEnv(c *check.C) {
563a4d1b
 	// ENV expansions work differently in Windows
f9a3558a
 	testRequires(c, DaemonIsLinux)
4e74cd49
 	name := "testbuildenvironmentreplacement"
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`
6d66e3e7
   FROM busybox
   ENV foo zzz
4e74cd49
   ENV bar ${foo}
6d66e3e7
   ENV abc1='$foo'
   ENV env1=$foo env2=${foo} env3="$foo" env4="${foo}"
   RUN [ "$abc1" = '$foo' ] && (echo "$abc1" | grep -q foo)
   ENV abc2="\$foo"
   RUN [ "$abc2" = '$foo' ] && (echo "$abc2" | grep -q foo)
   ENV abc3 '$foo'
   RUN [ "$abc3" = '$foo' ] && (echo "$abc3" | grep -q foo)
   ENV abc4 "\$foo"
   RUN [ "$abc4" = '$foo' ] && (echo "$abc4" | grep -q foo)
2fb7c3c4
   ENV foo2="abc\def"
   RUN [ "$foo2" = 'abc\def' ]
   ENV foo3="abc\\def"
   RUN [ "$foo3" = 'abc\def' ]
   ENV foo4='abc\\def'
   RUN [ "$foo4" = 'abc\\def' ]
   ENV foo5='abc\def'
   RUN [ "$foo5" = 'abc\def' ]
c778f4b9
   `))
4e74cd49
 
 	envResult := []string{}
c778f4b9
 	inspectFieldAndUnmarshall(c, name, "Config.Env", &envResult)
4e74cd49
 	found := false
6d66e3e7
 	envCount := 0
4e74cd49
 
 	for _, env := range envResult {
 		parts := strings.SplitN(env, "=", 2)
 		if parts[0] == "bar" {
 			found = true
6d66e3e7
 			if parts[1] != "zzz" {
dc944ea7
 				c.Fatalf("Could not find replaced var for env `bar`: got %q instead of `zzz`", parts[1])
6d66e3e7
 			}
 		} else if strings.HasPrefix(parts[0], "env") {
 			envCount++
 			if parts[1] != "zzz" {
2276de87
 				c.Fatalf("%s should be 'zzz' but instead its %q", parts[0], parts[1])
4e74cd49
 			}
39908fc6
 		} else if strings.HasPrefix(parts[0], "env") {
 			envCount++
 			if parts[1] != "foo" {
dc944ea7
 				c.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1])
39908fc6
 			}
4e74cd49
 		}
 	}
 
 	if !found {
dc944ea7
 		c.Fatal("Never found the `bar` env variable")
4e74cd49
 	}
 
6d66e3e7
 	if envCount != 4 {
dc944ea7
 		c.Fatalf("Didn't find all env vars - only saw %d\n%s", envCount, envResult)
6d66e3e7
 	}
 
4e74cd49
 }
 
c778f4b9
 func (s *DockerSuite) TestBuildHandleEscapesInVolume(c *check.C) {
563a4d1b
 	// The volume paths used in this test are invalid on Windows
f9a3558a
 	testRequires(c, DaemonIsLinux)
be49867c
 	name := "testbuildhandleescapes"
 
c778f4b9
 	testCases := []struct {
 		volumeValue string
 		expected    string
 	}{
 		{
 			volumeValue: "${FOO}",
 			expected:    "bar",
 		},
 		{
 			volumeValue: `\${FOO}`,
 			expected:    "${FOO}",
 		},
 		// this test in particular provides *7* backslashes and expects 6 to come back.
 		// Like above, the first escape is swallowed and the rest are treated as
 		// literals, this one is just less obvious because of all the character noise.
 		{
 			volumeValue: `\\\\\\\${FOO}`,
 			expected:    `\\\${FOO}`,
 		},
be49867c
 	}
 
c778f4b9
 	for _, tc := range testCases {
50c4475d
 		buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`
be49867c
   FROM scratch
   ENV FOO bar
c778f4b9
   VOLUME %s
   `, tc.volumeValue)))
be49867c
 
c778f4b9
 		var result map[string]map[string]struct{}
 		inspectFieldAndUnmarshall(c, name, "Config.Volumes", &result)
 		if _, ok := result[tc.expected]; !ok {
 			c.Fatalf("Could not find volume %s set from env foo in volumes table, got %q", tc.expected, result)
 		}
be49867c
 
c778f4b9
 		// Remove the image for the next iteration
 		dockerCmd(c, "rmi", name)
be49867c
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildOnBuildLowercase(c *check.C) {
a34831f0
 	name := "testbuildonbuildlowercase"
 	name2 := "testbuildonbuildlowercase2"
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`
a34831f0
   FROM busybox
   onbuild run echo quux
c778f4b9
   `))
a34831f0
 
50c4475d
 	result := buildImage(name2, build.WithDockerfile(fmt.Sprintf(`
a34831f0
   FROM %s
c778f4b9
   `, name)))
 	result.Assert(c, icmd.Success)
a34831f0
 
c778f4b9
 	if !strings.Contains(result.Combined(), "quux") {
 		c.Fatalf("Did not receive the expected echo text, got %s", result.Combined())
a34831f0
 	}
 
c778f4b9
 	if strings.Contains(result.Combined(), "ONBUILD ONBUILD") {
 		c.Fatalf("Got an ONBUILD ONBUILD error with no error: got %s", result.Combined())
a34831f0
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvEscapes(c *check.C) {
563a4d1b
 	// ENV expansions work differently in Windows
f9a3558a
 	testRequires(c, DaemonIsLinux)
df0e0c76
 	name := "testbuildenvescapes"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`
df0e0c76
     FROM busybox
     ENV TEST foo
     CMD echo \$
c778f4b9
     `))
df0e0c76
 
5c295460
 	out, _ := dockerCmd(c, "run", "-t", name)
df0e0c76
 	if strings.TrimSpace(out) != "$" {
dc944ea7
 		c.Fatalf("Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q", strings.TrimSpace(out))
df0e0c76
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvOverwrite(c *check.C) {
563a4d1b
 	// ENV expansions work differently in Windows
f9a3558a
 	testRequires(c, DaemonIsLinux)
df0e0c76
 	name := "testbuildenvoverwrite"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`
df0e0c76
     FROM busybox
     ENV TEST foo
4e74cd49
     CMD echo ${TEST}
c778f4b9
     `))
df0e0c76
 
5c295460
 	out, _ := dockerCmd(c, "run", "-e", "TEST=bar", "-t", name)
df0e0c76
 	if strings.TrimSpace(out) != "bar" {
dc944ea7
 		c.Fatalf("Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q", strings.TrimSpace(out))
df0e0c76
 	}
 
 }
 
c778f4b9
 // FIXME(vdemeester) why we disabled cache here ?
dc944ea7
 func (s *DockerSuite) TestBuildOnBuildCmdEntrypointJSON(c *check.C) {
1150c163
 	name1 := "onbuildcmd"
 	name2 := "onbuildgenerated"
 
97f86071
 	cli.BuildCmd(c, name1, build.WithDockerfile(`
1150c163
 FROM busybox
 ONBUILD CMD ["hello world"]
 ONBUILD ENTRYPOINT ["echo"]
c778f4b9
 ONBUILD RUN ["true"]`))
1150c163
 
97f86071
 	cli.BuildCmd(c, name2, build.WithDockerfile(fmt.Sprintf(`FROM %s`, name1)))
1150c163
 
9f738cc5
 	result := cli.DockerCmd(c, "run", name2)
 	result.Assert(c, icmd.Expected{Out: "hello world"})
1150c163
 }
 
c778f4b9
 // FIXME(vdemeester) why we disabled cache here ?
dc944ea7
 func (s *DockerSuite) TestBuildOnBuildEntrypointJSON(c *check.C) {
1150c163
 	name1 := "onbuildcmd"
 	name2 := "onbuildgenerated"
 
50c4475d
 	buildImageSuccessfully(c, name1, build.WithDockerfile(`
1150c163
 FROM busybox
c778f4b9
 ONBUILD ENTRYPOINT ["echo"]`))
1150c163
 
50c4475d
 	buildImageSuccessfully(c, name2, build.WithDockerfile(fmt.Sprintf("FROM %s\nCMD [\"hello world\"]\n", name1)))
1150c163
 
2b95f012
 	out, _ := dockerCmd(c, "run", name2)
1150c163
 	if !regexp.MustCompile(`(?m)^hello world`).MatchString(out) {
dc944ea7
 		c.Fatal("got malformed output from onbuild", out)
1150c163
 	}
 
 }
 
ab121345
 func (s *DockerSuite) TestBuildCacheAdd(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Windows doesn't have httpserver image yet
075e1bc1
 	name := "testbuildtwoimageswithadd"
56fb4653
 	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
075e1bc1
 		"robots.txt": "hello",
 		"index.html": "world",
56fb4653
 	}))
075e1bc1
 	defer server.Close()
2e95bb5f
 
50c4475d
 	cli.BuildCmd(c, name, build.WithDockerfile(fmt.Sprintf(`FROM scratch
c10f6ef4
 		ADD %s/robots.txt /`, server.URL())))
 
50c4475d
 	result := cli.Docker(cli.Build(name), build.WithDockerfile(fmt.Sprintf(`FROM scratch
c10f6ef4
 		ADD %s/index.html /`, server.URL())))
 	result.Assert(c, icmd.Success)
 	if strings.Contains(result.Combined(), "Using cache") {
dc944ea7
 		c.Fatal("2nd build used cache on ADD, it shouldn't")
03a109e4
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildLastModified(c *check.C) {
8eb0af1a
 	// Temporary fix for #30890. TODO @jhowardmsft figure out what
 	// has changed in the master busybox image.
 	testRequires(c, DaemonIsLinux)
 
5c05b5c9
 	name := "testbuildlastmodified"
 
56fb4653
 	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
5c05b5c9
 		"file": "hello",
56fb4653
 	}))
5c05b5c9
 	defer server.Close()
 
 	var out, out2 string
f88c2c04
 	var args []string
 	// Temopray workaround for #35963. Will remove this when that issue fixed
 	if runtime.GOARCH == "amd64" {
 		args = []string{"run", name, "ls", "-le", "/file"}
 	} else {
 		args = []string{"run", name, "ls", "-l", "--full-time", "/file"}
 	}
5c05b5c9
 
 	dFmt := `FROM busybox
443d7313
 ADD %s/file /`
40c8e787
 	dockerfile := fmt.Sprintf(dFmt, server.URL())
5c05b5c9
 
56fb4653
 	cli.BuildCmd(c, name, build.WithoutCache, build.WithDockerfile(dockerfile))
f88c2c04
 	out = cli.DockerCmd(c, args...).Combined()
5c05b5c9
 
 	// Build it again and make sure the mtime of the file didn't change.
 	// Wait a few seconds to make sure the time changed enough to notice
 	time.Sleep(2 * time.Second)
 
56fb4653
 	cli.BuildCmd(c, name, build.WithoutCache, build.WithDockerfile(dockerfile))
f88c2c04
 	out2 = cli.DockerCmd(c, args...).Combined()
5c05b5c9
 
443d7313
 	if out != out2 {
 		c.Fatalf("MTime changed:\nOrigin:%s\nNew:%s", out, out2)
5c05b5c9
 	}
 
 	// Now 'touch' the file and make sure the timestamp DID change this time
 	// Create a new fakeStorage instead of just using Add() to help windows
56fb4653
 	server = fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
5c05b5c9
 		"file": "hello",
56fb4653
 	}))
5c05b5c9
 	defer server.Close()
 
40c8e787
 	dockerfile = fmt.Sprintf(dFmt, server.URL())
56fb4653
 	cli.BuildCmd(c, name, build.WithoutCache, build.WithDockerfile(dockerfile))
f88c2c04
 	out2 = cli.DockerCmd(c, args...).Combined()
5c05b5c9
 
443d7313
 	if out == out2 {
 		c.Fatalf("MTime didn't change:\nOrigin:%s\nNew:%s", out, out2)
5c05b5c9
 	}
 
 }
 
4f3889e4
 // Regression for https://github.com/docker/docker/pull/27805
 // Makes sure that we don't use the cache if the contents of
 // a file in a subfolder of the context is modified and we re-build.
 func (s *DockerSuite) TestBuildModifyFileInFolder(c *check.C) {
 	name := "testbuildmodifyfileinfolder"
 
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(`FROM busybox
4f3889e4
 RUN ["mkdir", "/test"]
56fb4653
 ADD folder/file /test/changetarget`))
4f3889e4
 	defer ctx.Close()
 	if err := ctx.Add("folder/file", "first"); err != nil {
 		c.Fatal(err)
 	}
56fb4653
 	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id1 := getIDByName(c, name)
4f3889e4
 	if err := ctx.Add("folder/file", "second"); err != nil {
 		c.Fatal(err)
 	}
56fb4653
 	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id2 := getIDByName(c, name)
4f3889e4
 	if id1 == id2 {
 		c.Fatal("cache was used even though file contents in folder was changed")
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddSingleFileToRoot(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
56fb4653
 	buildImageSuccessfully(c, "testaddimg", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
682fbe01
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN touch /exists
 RUN chown dockerio.dockerio /exists
 ADD test_file /
 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
1a22418f
 RUN [ $(ls -l /test_file | awk '{print $1}') = '%s' ]
c778f4b9
 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod)),
56fb4653
 		build.WithFile("test_file", "test1")))
91b7d8eb
 }
 
1ce5457d
 // Issue #3960: "ADD src ." hangs
dc944ea7
 func (s *DockerSuite) TestBuildAddSingleFileToWorkdir(c *check.C) {
5e2ea696
 	name := "testaddsinglefiletoworkdir"
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(
 		`FROM busybox
 	       ADD test_file .`),
 		fakecontext.WithFiles(map[string]string{
5e2ea696
 			"test_file": "test1",
56fb4653
 		}))
db7fded1
 	defer ctx.Close()
 
4203230c
 	errChan := make(chan error)
5e2ea696
 	go func() {
56fb4653
 		errChan <- buildImage(name, build.WithExternalBuildContext(ctx)).Error
4203230c
 		close(errChan)
5e2ea696
 	}()
 	select {
88c1bc10
 	case <-time.After(15 * time.Second):
dc944ea7
 		c.Fatal("Build with adding to workdir timed out")
4203230c
 	case err := <-errChan:
 		c.Assert(err, check.IsNil)
1ce5457d
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddSingleFileToExistDir(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
e59327aa
 	cli.BuildCmd(c, "testaddsinglefiletoexistdir", build.WithBuildContext(c,
56fb4653
 		build.WithFile("Dockerfile", `FROM busybox
6bb44b6d
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN mkdir /exists
 RUN touch /exists/exists_file
 RUN chown -R dockerio.dockerio /exists
 ADD test_file /exists/
 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]
c778f4b9
 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
56fb4653
 		build.WithFile("test_file", "test1")))
91b7d8eb
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopyAddMultipleFiles(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
56fb4653
 	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
17b6583a
 		"robots.txt": "hello",
56fb4653
 	}))
17b6583a
 	defer server.Close()
 
56fb4653
 	cli.BuildCmd(c, "testcopymultiplefilestofile", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
e45c9215
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN mkdir /exists
 RUN touch /exists/exists_file
 RUN chown -R dockerio.dockerio /exists
 COPY test_file1 test_file2 /exists/
17b6583a
 ADD test_file3 test_file4 %s/robots.txt /exists/
e45c9215
 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
 RUN [ $(ls -l /exists/test_file1 | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /exists/test_file2 | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /exists/test_file3 | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /exists/test_file4 | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /exists/robots.txt | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
c778f4b9
 `, server.URL())),
56fb4653
 		build.WithFile("test_file1", "test1"),
 		build.WithFile("test_file2", "test2"),
 		build.WithFile("test_file3", "test3"),
 		build.WithFile("test_file3", "test3"),
 		build.WithFile("test_file4", "test4")))
06d95003
 }
 
c778f4b9
 // These tests are mainly for user namespaces to verify that new directories
06d95003
 // are created as the remapped root uid/gid pair
c778f4b9
 func (s *DockerSuite) TestBuildUsernamespaceValidateRemappedRoot(c *check.C) {
 	testRequires(c, DaemonIsLinux)
 	testCases := []string{
 		"ADD . /new_dir",
 		"COPY test_dir /new_dir",
 		"WORKDIR /new_dir",
7a61b9ae
 	}
c778f4b9
 	name := "testbuildusernamespacevalidateremappedroot"
 	for _, tc := range testCases {
e59327aa
 		cli.BuildCmd(c, name, build.WithBuildContext(c,
56fb4653
 			build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
c778f4b9
 %s
 RUN [ $(ls -l / | grep new_dir | awk '{print $3":"$4}') = 'root:root' ]`, tc)),
56fb4653
 			build.WithFile("test_dir/test_file", "test file")))
7a61b9ae
 
e59327aa
 		cli.DockerCmd(c, "rmi", name)
799a6b94
 	}
 }
 
c778f4b9
 func (s *DockerSuite) TestBuildAddAndCopyFileWithWhitespace(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Not currently passing on Windows
abfb7138
 	name := "testaddfilewithwhitespace"
c778f4b9
 
 	for _, command := range []string{"ADD", "COPY"} {
e59327aa
 		cli.BuildCmd(c, name, build.WithBuildContext(c,
56fb4653
 			build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
abfb7138
 RUN mkdir "/test dir"
 RUN mkdir "/test_dir"
c778f4b9
 %s [ "test file1", "/test_file1" ]
 %s [ "test_file2", "/test file2" ]
 %s [ "test file3", "/test file3" ]
 %s [ "test dir/test_file4", "/test_dir/test_file4" ]
 %s [ "test_dir/test_file5", "/test dir/test_file5" ]
 %s [ "test dir/test_file6", "/test dir/test_file6" ]
abfb7138
 RUN [ $(cat "/test_file1") = 'test1' ]
 RUN [ $(cat "/test file2") = 'test2' ]
 RUN [ $(cat "/test file3") = 'test3' ]
 RUN [ $(cat "/test_dir/test_file4") = 'test4' ]
 RUN [ $(cat "/test dir/test_file5") = 'test5' ]
c778f4b9
 RUN [ $(cat "/test dir/test_file6") = 'test6' ]`, command, command, command, command, command, command)),
56fb4653
 			build.WithFile("test file1", "test1"),
 			build.WithFile("test_file2", "test2"),
 			build.WithFile("test file3", "test3"),
 			build.WithFile("test dir/test_file4", "test4"),
 			build.WithFile("test_dir/test_file5", "test5"),
 			build.WithFile("test dir/test_file6", "test6"),
c778f4b9
 		))
abfb7138
 
e59327aa
 		cli.DockerCmd(c, "rmi", name)
abfb7138
 	}
 }
 
c778f4b9
 func (s *DockerSuite) TestBuildCopyFileWithWhitespaceOnWindows(c *check.C) {
 	testRequires(c, DaemonIsWindows)
dfedc9ef
 	dockerfile := `FROM ` + testEnv.PlatformDefaults.BaseImage + `
e79b0b42
 RUN mkdir "C:/test dir"
 RUN mkdir "C:/test_dir"
 COPY [ "test file1", "/test_file1" ]
 COPY [ "test_file2", "/test file2" ]
 COPY [ "test file3", "/test file3" ]
 COPY [ "test dir/test_file4", "/test_dir/test_file4" ]
 COPY [ "test_dir/test_file5", "/test dir/test_file5" ]
 COPY [ "test dir/test_file6", "/test dir/test_file6" ]
 RUN find "test1" "C:/test_file1"
 RUN find "test2" "C:/test file2"
 RUN find "test3" "C:/test file3"
 RUN find "test4" "C:/test_dir/test_file4"
 RUN find "test5" "C:/test dir/test_file5"
 RUN find "test6" "C:/test dir/test_file6"`
 
 	name := "testcopyfilewithwhitespace"
e59327aa
 	cli.BuildCmd(c, name, build.WithBuildContext(c,
56fb4653
 		build.WithFile("Dockerfile", dockerfile),
 		build.WithFile("test file1", "test1"),
 		build.WithFile("test_file2", "test2"),
 		build.WithFile("test file3", "test3"),
 		build.WithFile("test dir/test_file4", "test4"),
 		build.WithFile("test_dir/test_file5", "test5"),
 		build.WithFile("test dir/test_file6", "test6"),
c778f4b9
 	))
abfb7138
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopyWildcard(c *check.C) {
acd40d50
 	name := "testcopywildcard"
56fb4653
 	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
acd40d50
 		"robots.txt": "hello",
 		"index.html": "world",
56fb4653
 	}))
acd40d50
 	defer server.Close()
2e95bb5f
 
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(fmt.Sprintf(`FROM busybox
acd40d50
 	COPY file*.txt /tmp/
 	RUN ls /tmp/file1.txt /tmp/file2.txt
30905664
 	RUN [ "mkdir",  "/tmp1" ]
acd40d50
 	COPY dir* /tmp1/
 	RUN ls /tmp1/dirt /tmp1/nested_file /tmp1/nested_dir/nest_nest_file
30905664
 	RUN [ "mkdir",  "/tmp2" ]
acd40d50
         ADD dir/*dir %s/robots.txt /tmp2/
 	RUN ls /tmp2/nest_nest_file /tmp2/robots.txt
56fb4653
 	`, server.URL())),
 		fakecontext.WithFiles(map[string]string{
acd40d50
 			"file1.txt":                     "test1",
 			"file2.txt":                     "test2",
 			"dir/nested_file":               "nested file",
 			"dir/nested_dir/nest_nest_file": "2 times nested",
 			"dirt": "dirty",
56fb4653
 		}))
82daa438
 	defer ctx.Close()
acd40d50
 
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id1 := getIDByName(c, name)
acd40d50
 
 	// Now make sure we use a cache the 2nd time
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id2 := getIDByName(c, name)
acd40d50
 
 	if id1 != id2 {
dc944ea7
 		c.Fatal("didn't use the cache")
acd40d50
 	}
 
 }
 
82daa438
 func (s *DockerSuite) TestBuildCopyWildcardInName(c *check.C) {
c778f4b9
 	// Run this only on Linux
 	// Below is the original comment (that I don't agree with — vdemeester)
 	// Normally we would do c.Fatal(err) here but given that
 	// the odds of this failing are so rare, it must be because
 	// the OS we're running the client on doesn't support * in
 	// filenames (like windows).  So, instead of failing the test
 	// just let it pass. Then we don't need to explicitly
 	// say which OSs this works on or not.
e47c46c7
 	testRequires(c, DaemonIsLinux, UnixCli)
c778f4b9
 
56fb4653
 	buildImageSuccessfully(c, "testcopywildcardinname", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `FROM busybox
82daa438
 	COPY *.txt /tmp/
 	RUN [ "$(cat /tmp/\*.txt)" = 'hi there' ]
c778f4b9
 	`),
56fb4653
 		build.WithFile("*.txt", "hi there"),
c778f4b9
 	))
82daa438
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopyWildcardCache(c *check.C) {
acd40d50
 	name := "testcopywildcardcache"
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(`FROM busybox
 	COPY file1.txt /tmp/`),
 		fakecontext.WithFiles(map[string]string{
acd40d50
 			"file1.txt": "test1",
56fb4653
 		}))
04ef69a1
 	defer ctx.Close()
acd40d50
 
56fb4653
 	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id1 := getIDByName(c, name)
acd40d50
 
8b3fbac1
 	// Now make sure we use a cache the 2nd time even with wild cards.
 	// Use the same context so the file is the same and the checksum will match
 	ctx.Add("Dockerfile", `FROM busybox
 	COPY file*.txt /tmp/`)
acd40d50
 
56fb4653
 	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id2 := getIDByName(c, name)
acd40d50
 
 	if id1 != id2 {
dc944ea7
 		c.Fatal("didn't use the cache")
acd40d50
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddSingleFileToNonExistingDir(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
56fb4653
 	buildImageSuccessfully(c, "testaddsinglefiletononexistingdir", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `FROM busybox
139b6ed3
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN touch /exists
 RUN chown dockerio.dockerio /exists
 ADD test_file /test_dir/
 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
c778f4b9
 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
56fb4653
 		build.WithFile("test_file", "test1")))
91b7d8eb
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddDirContentToRoot(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
56fb4653
 	buildImageSuccessfully(c, "testadddircontenttoroot", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `FROM busybox
2d802d7f
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN touch /exists
 RUN chown dockerio.dockerio exists
 ADD test_dir /
 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
c778f4b9
 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
56fb4653
 		build.WithFile("test_dir/test_file", "test1")))
91b7d8eb
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddDirContentToExistingDir(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
56fb4653
 	buildImageSuccessfully(c, "testadddircontenttoexistingdir", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `FROM busybox
c58391bb
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN mkdir /exists
 RUN touch /exists/exists_file
 RUN chown -R dockerio.dockerio /exists
 ADD test_dir/ /exists/
 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
c778f4b9
 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]`),
56fb4653
 		build.WithFile("test_dir/test_file", "test1")))
91b7d8eb
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddWholeDirToRoot(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
56fb4653
 	buildImageSuccessfully(c, "testaddwholedirtoroot", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
0c899cef
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN touch /exists
 RUN chown dockerio.dockerio exists
 ADD test_dir /test_dir
 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l / | grep test_dir | awk '{print $1}') = 'drwxr-xr-x' ]
 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
1a22418f
 RUN [ $(ls -l /test_dir/test_file | awk '{print $1}') = '%s' ]
c778f4b9
 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod)),
56fb4653
 		build.WithFile("test_dir/test_file", "test1")))
91b7d8eb
 }
 
c778f4b9
 // Testing #5941 : Having an etc directory in context conflicts with the /etc/mtab
 func (s *DockerSuite) TestBuildAddOrCopyEtcToRootShouldNotConflict(c *check.C) {
56fb4653
 	buildImageSuccessfully(c, "testaddetctoroot", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `FROM `+minimalBaseImage()+`
c778f4b9
 ADD . /`),
56fb4653
 		build.WithFile("etc/test_file", "test1")))
 	buildImageSuccessfully(c, "testcopyetctoroot", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `FROM `+minimalBaseImage()+`
c778f4b9
 COPY . /`),
56fb4653
 		build.WithFile("etc/test_file", "test1")))
56a53c72
 }
 
c778f4b9
 // Testing #9401 : Losing setuid flag after a ADD
dc944ea7
 func (s *DockerSuite) TestBuildAddPreservesFilesSpecialBits(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
56fb4653
 	buildImageSuccessfully(c, "testaddetctoroot", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `FROM busybox
f3cedce3
 ADD suidbin /usr/bin/suidbin
 RUN chmod 4755 /usr/bin/suidbin
 RUN [ $(ls -l /usr/bin/suidbin | awk '{print $1}') = '-rwsr-xr-x' ]
 ADD ./data/ /
c778f4b9
 RUN [ $(ls -l /usr/bin/suidbin | awk '{print $1}') = '-rwsr-xr-x' ]`),
56fb4653
 		build.WithFile("suidbin", "suidbin"),
 		build.WithFile("/data/usr/test_file", "test1")))
f3cedce3
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopySingleFileToRoot(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
56fb4653
 	buildImageSuccessfully(c, "testcopysinglefiletoroot", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
83c5dced
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN touch /exists
 RUN chown dockerio.dockerio /exists
 COPY test_file /
 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
1a22418f
 RUN [ $(ls -l /test_file | awk '{print $1}') = '%s' ]
c778f4b9
 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod)),
56fb4653
 		build.WithFile("test_file", "test1")))
180c2a67
 }
 
 // Issue #3960: "ADD src ." hangs - adapted for COPY
dc944ea7
 func (s *DockerSuite) TestBuildCopySingleFileToWorkdir(c *check.C) {
d41cba6a
 	name := "testcopysinglefiletoworkdir"
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(`FROM busybox
 COPY test_file .`),
 		fakecontext.WithFiles(map[string]string{
d41cba6a
 			"test_file": "test1",
56fb4653
 		}))
db7fded1
 	defer ctx.Close()
 
4203230c
 	errChan := make(chan error)
d41cba6a
 	go func() {
56fb4653
 		errChan <- buildImage(name, build.WithExternalBuildContext(ctx)).Error
4203230c
 		close(errChan)
d41cba6a
 	}()
 	select {
88c1bc10
 	case <-time.After(15 * time.Second):
dc944ea7
 		c.Fatal("Build with adding to workdir timed out")
4203230c
 	case err := <-errChan:
 		c.Assert(err, check.IsNil)
180c2a67
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopySingleFileToExistDir(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
56fb4653
 	buildImageSuccessfully(c, "testcopysinglefiletoexistdir", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `FROM busybox
2248109f
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN mkdir /exists
 RUN touch /exists/exists_file
 RUN chown -R dockerio.dockerio /exists
 COPY test_file /exists/
 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]
c778f4b9
 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
56fb4653
 		build.WithFile("test_file", "test1")))
180c2a67
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopySingleFileToNonExistDir(c *check.C) {
c778f4b9
 	testRequires(c, DaemonIsLinux) // Linux specific
56fb4653
 	buildImageSuccessfully(c, "testcopysinglefiletononexistdir", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `FROM busybox
24d83afd
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN touch /exists
 RUN chown dockerio.dockerio /exists
 COPY test_file /test_dir/
 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
c778f4b9
 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
56fb4653
 		build.WithFile("test_file", "test1")))
180c2a67
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopyDirContentToRoot(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
56fb4653
 	buildImageSuccessfully(c, "testcopydircontenttoroot", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `FROM busybox
832618af
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN touch /exists
 RUN chown dockerio.dockerio exists
 COPY test_dir /
 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
c778f4b9
 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
56fb4653
 		build.WithFile("test_dir/test_file", "test1")))
180c2a67
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopyDirContentToExistDir(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
56fb4653
 	buildImageSuccessfully(c, "testcopydircontenttoexistdir", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `FROM busybox
4a029259
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN mkdir /exists
 RUN touch /exists/exists_file
 RUN chown -R dockerio.dockerio /exists
 COPY test_dir/ /exists/
 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
c778f4b9
 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]`),
56fb4653
 		build.WithFile("test_dir/test_file", "test1")))
180c2a67
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopyWholeDirToRoot(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
56fb4653
 	buildImageSuccessfully(c, "testcopywholedirtoroot", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
6582ea57
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN touch /exists
 RUN chown dockerio.dockerio exists
 COPY test_dir /test_dir
 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l / | grep test_dir | awk '{print $1}') = 'drwxr-xr-x' ]
 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
1a22418f
 RUN [ $(ls -l /test_dir/test_file | awk '{print $1}') = '%s' ]
c778f4b9
 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod)),
56fb4653
 		build.WithFile("test_dir/test_file", "test1")))
180c2a67
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddBadLinks(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Not currently working on Windows
 
 	dockerfile := `
 		FROM scratch
 		ADD links.tar /
 		ADD foo.txt /symlink/
 		`
 	targetFile := "foo.txt"
7496cbbc
 	var (
 		name = "test-link-absolute"
 	)
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile))
7496cbbc
 	defer ctx.Close()
 
 	tempDir, err := ioutil.TempDir("", "test-link-absolute-temp-")
 	if err != nil {
dc944ea7
 		c.Fatalf("failed to create temporary directory: %s", tempDir)
7496cbbc
 	}
 	defer os.RemoveAll(tempDir)
 
d0dc14e5
 	var symlinkTarget string
 	if runtime.GOOS == "windows" {
 		var driveLetter string
 		if abs, err := filepath.Abs(tempDir); err != nil {
dc944ea7
 			c.Fatal(err)
d0dc14e5
 		} else {
 			driveLetter = abs[:1]
 		}
 		tempDirWithoutDrive := tempDir[2:]
 		symlinkTarget = fmt.Sprintf(`%s:\..\..\..\..\..\..\..\..\..\..\..\..%s`, driveLetter, tempDirWithoutDrive)
 	} else {
 		symlinkTarget = fmt.Sprintf("/../../../../../../../../../../../..%s", tempDir)
 	}
 
7496cbbc
 	tarPath := filepath.Join(ctx.Dir, "links.tar")
 	nonExistingFile := filepath.Join(tempDir, targetFile)
 	fooPath := filepath.Join(ctx.Dir, targetFile)
 
 	tarOut, err := os.Create(tarPath)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
7496cbbc
 	}
 
 	tarWriter := tar.NewWriter(tarOut)
 
 	header := &tar.Header{
 		Name:     "symlink",
 		Typeflag: tar.TypeSymlink,
 		Linkname: symlinkTarget,
 		Mode:     0755,
 		Uid:      0,
 		Gid:      0,
 	}
 
 	err = tarWriter.WriteHeader(header)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
7496cbbc
 	}
 
 	tarWriter.Close()
 	tarOut.Close()
 
 	foo, err := os.Create(fooPath)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
7496cbbc
 	}
 	defer foo.Close()
 
 	if _, err := foo.WriteString("test"); err != nil {
dc944ea7
 		c.Fatal(err)
7496cbbc
 	}
 
56fb4653
 	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
7496cbbc
 	if _, err := os.Stat(nonExistingFile); err == nil || err != nil && !os.IsNotExist(err) {
dc944ea7
 		c.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile)
7496cbbc
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddBadLinksVolume(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // ln not implemented on Windows busybox
a57eee22
 	const (
 		dockerfileTemplate = `
 		FROM busybox
 		RUN ln -s /../../../../../../../../%s /x
 		VOLUME /x
 		ADD foo.txt /x/`
 		targetFile = "foo.txt"
 	)
 	var (
 		name       = "test-link-absolute-volume"
 		dockerfile = ""
 	)
 
 	tempDir, err := ioutil.TempDir("", "test-link-absolute-volume-temp-")
 	if err != nil {
dc944ea7
 		c.Fatalf("failed to create temporary directory: %s", tempDir)
a57eee22
 	}
 	defer os.RemoveAll(tempDir)
 
 	dockerfile = fmt.Sprintf(dockerfileTemplate, tempDir)
 	nonExistingFile := filepath.Join(tempDir, targetFile)
 
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile))
a57eee22
 	defer ctx.Close()
 	fooPath := filepath.Join(ctx.Dir, targetFile)
 
 	foo, err := os.Create(fooPath)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
a57eee22
 	}
 	defer foo.Close()
 
 	if _, err := foo.WriteString("test"); err != nil {
dc944ea7
 		c.Fatal(err)
a57eee22
 	}
 
56fb4653
 	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
a57eee22
 	if _, err := os.Stat(nonExistingFile); err == nil || err != nil && !os.IsNotExist(err) {
dc944ea7
 		c.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile)
a57eee22
 	}
 
 }
 
f5b1afae
 // Issue #5270 - ensure we throw a better error than "unexpected EOF"
 // when we can't access files in the context.
dc944ea7
 func (s *DockerSuite) TestBuildWithInaccessibleFilesInContext(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux, UnixCli) // test uses chown/chmod: not available on windows
492a58f0
 
f5b1afae
 	{
51a56399
 		name := "testbuildinaccessiblefiles"
56fb4653
 		ctx := fakecontext.New(c, "",
 			fakecontext.WithDockerfile("FROM scratch\nADD . /foo/"),
 			fakecontext.WithFiles(map[string]string{"fileWithoutReadAccess": "foo"}),
 		)
51a56399
 		defer ctx.Close()
f5b1afae
 		// This is used to ensure we detect inaccessible files early during build in the cli client
51a56399
 		pathToFileWithoutReadAccess := filepath.Join(ctx.Dir, "fileWithoutReadAccess")
f5b1afae
 
c10f6ef4
 		if err := os.Chown(pathToFileWithoutReadAccess, 0, 0); err != nil {
dc944ea7
 			c.Fatalf("failed to chown file to root: %s", err)
b1e3c9e9
 		}
c10f6ef4
 		if err := os.Chmod(pathToFileWithoutReadAccess, 0700); err != nil {
dc944ea7
 			c.Fatalf("failed to chmod file to 700: %s", err)
b1e3c9e9
 		}
c778f4b9
 		result := icmd.RunCmd(icmd.Cmd{
 			Command: []string{"su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name)},
 			Dir:     ctx.Dir,
 		})
 		if result.Error == nil {
 			c.Fatalf("build should have failed: %s %s", result.Error, result.Combined())
f5b1afae
 		}
 
 		// check if we've detected the failure before we started building
c778f4b9
 		if !strings.Contains(result.Combined(), "no permission to read from ") {
 			c.Fatalf("output should've contained the string: no permission to read from but contained: %s", result.Combined())
f5b1afae
 		}
 
f47a61c4
 		if !strings.Contains(result.Combined(), "error checking context") {
 			c.Fatalf("output should've contained the string: error checking context")
f5b1afae
 		}
 	}
 	{
51a56399
 		name := "testbuildinaccessibledirectory"
56fb4653
 		ctx := fakecontext.New(c, "",
 			fakecontext.WithDockerfile("FROM scratch\nADD . /foo/"),
 			fakecontext.WithFiles(map[string]string{"directoryWeCantStat/bar": "foo"}),
 		)
51a56399
 		defer ctx.Close()
f5b1afae
 		// This is used to ensure we detect inaccessible directories early during build in the cli client
51a56399
 		pathToDirectoryWithoutReadAccess := filepath.Join(ctx.Dir, "directoryWeCantStat")
f5b1afae
 		pathToFileInDirectoryWithoutReadAccess := filepath.Join(pathToDirectoryWithoutReadAccess, "bar")
 
c10f6ef4
 		if err := os.Chown(pathToDirectoryWithoutReadAccess, 0, 0); err != nil {
dc944ea7
 			c.Fatalf("failed to chown directory to root: %s", err)
b1e3c9e9
 		}
c10f6ef4
 		if err := os.Chmod(pathToDirectoryWithoutReadAccess, 0444); err != nil {
dc944ea7
 			c.Fatalf("failed to chmod directory to 444: %s", err)
b1e3c9e9
 		}
c10f6ef4
 		if err := os.Chmod(pathToFileInDirectoryWithoutReadAccess, 0700); err != nil {
dc944ea7
 			c.Fatalf("failed to chmod file to 700: %s", err)
b1e3c9e9
 		}
f5b1afae
 
c778f4b9
 		result := icmd.RunCmd(icmd.Cmd{
 			Command: []string{"su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name)},
 			Dir:     ctx.Dir,
 		})
 		if result.Error == nil {
 			c.Fatalf("build should have failed: %s %s", result.Error, result.Combined())
f5b1afae
 		}
 
 		// check if we've detected the failure before we started building
c778f4b9
 		if !strings.Contains(result.Combined(), "can't stat") {
 			c.Fatalf("output should've contained the string: can't access %s", result.Combined())
f5b1afae
 		}
 
f47a61c4
 		if !strings.Contains(result.Combined(), "error checking context") {
 			c.Fatalf("output should've contained the string: error checking context\ngot:%s", result.Combined())
f5b1afae
 		}
 
 	}
 	{
51a56399
 		name := "testlinksok"
56fb4653
 		ctx := fakecontext.New(c, "", fakecontext.WithDockerfile("FROM scratch\nADD . /foo/"))
51a56399
 		defer ctx.Close()
da3d3b97
 
 		target := "../../../../../../../../../../../../../../../../../../../azA"
 		if err := os.Symlink(filepath.Join(ctx.Dir, "g"), target); err != nil {
dc944ea7
 			c.Fatal(err)
51a56399
 		}
da3d3b97
 		defer os.Remove(target)
f5b1afae
 		// This is used to ensure we don't follow links when checking if everything in the context is accessible
 		// This test doesn't require that we run commands as an unprivileged user
56fb4653
 		buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
f5b1afae
 	}
27cca4c7
 	{
51a56399
 		name := "testbuildignoredinaccessible"
56fb4653
 		ctx := fakecontext.New(c, "",
 			fakecontext.WithDockerfile("FROM scratch\nADD . /foo/"),
 			fakecontext.WithFiles(map[string]string{
51a56399
 				"directoryWeCantStat/bar": "foo",
 				".dockerignore":           "directoryWeCantStat",
56fb4653
 			}),
 		)
51a56399
 		defer ctx.Close()
27cca4c7
 		// This is used to ensure we don't try to add inaccessible files when they are ignored by a .dockerignore pattern
51a56399
 		pathToDirectoryWithoutReadAccess := filepath.Join(ctx.Dir, "directoryWeCantStat")
27cca4c7
 		pathToFileInDirectoryWithoutReadAccess := filepath.Join(pathToDirectoryWithoutReadAccess, "bar")
c10f6ef4
 		if err := os.Chown(pathToDirectoryWithoutReadAccess, 0, 0); err != nil {
dc944ea7
 			c.Fatalf("failed to chown directory to root: %s", err)
b1e3c9e9
 		}
c10f6ef4
 		if err := os.Chmod(pathToDirectoryWithoutReadAccess, 0444); err != nil {
bd0ec7ed
 			c.Fatalf("failed to chmod directory to 444: %s", err)
b1e3c9e9
 		}
c10f6ef4
 		if err := os.Chmod(pathToFileInDirectoryWithoutReadAccess, 0700); err != nil {
bd0ec7ed
 			c.Fatalf("failed to chmod file to 700: %s", err)
b1e3c9e9
 		}
27cca4c7
 
6e7405eb
 		result := icmd.RunCmd(icmd.Cmd{
 			Dir: ctx.Dir,
 			Command: []string{"su", "unprivilegeduser", "-c",
 				fmt.Sprintf("%s build -t %s .", dockerBinary, name)},
 		})
 		result.Assert(c, icmd.Expected{})
27cca4c7
 	}
f5b1afae
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildForceRm(c *check.C) {
ecbb0e62
 	containerCountBefore := getContainerCount(c)
1625cbfc
 	name := "testbuildforcerm"
4603a725
 
669c0677
 	r := buildImage(name, cli.WithFlags("--force-rm"), build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `FROM busybox
4603a725
 	RUN true
669c0677
 	RUN thiswillfail`)))
 	if r.ExitCode != 1 && r.ExitCode != 127 { // different on Linux / Windows
 		c.Fatalf("Wrong exit code")
 	}
69dcf767
 
ecbb0e62
 	containerCountAfter := getContainerCount(c)
69dcf767
 	if containerCountBefore != containerCountAfter {
dc944ea7
 		c.Fatalf("--force-rm shouldn't have left containers behind")
69dcf767
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildRm(c *check.C) {
52cf3312
 	name := "testbuildrm"
4603a725
 
c778f4b9
 	testCases := []struct {
 		buildflags                []string
 		shouldLeftContainerBehind bool
 	}{
 		// Default case (i.e. --rm=true)
 		{
 			buildflags:                []string{},
 			shouldLeftContainerBehind: false,
 		},
 		{
 			buildflags:                []string{"--rm"},
 			shouldLeftContainerBehind: false,
 		},
 		{
 			buildflags:                []string{"--rm=false"},
 			shouldLeftContainerBehind: true,
 		},
a691fcb2
 	}
 
c778f4b9
 	for _, tc := range testCases {
ecbb0e62
 		containerCountBefore := getContainerCount(c)
a691fcb2
 
50c4475d
 		buildImageSuccessfully(c, name, cli.WithFlags(tc.buildflags...), build.WithDockerfile(`FROM busybox
c778f4b9
 	RUN echo hello world`))
a691fcb2
 
ecbb0e62
 		containerCountAfter := getContainerCount(c)
c778f4b9
 		if tc.shouldLeftContainerBehind {
 			if containerCountBefore == containerCountAfter {
 				c.Fatalf("flags %v should have left containers behind", tc.buildflags)
 			}
 		} else {
 			if containerCountBefore != containerCountAfter {
 				c.Fatalf("flags %v shouldn't have left containers behind", tc.buildflags)
 			}
a691fcb2
 		}
 
c778f4b9
 		dockerCmd(c, "rmi", name)
a691fcb2
 	}
 }
a5729879
 
dc944ea7
 func (s *DockerSuite) TestBuildWithVolumes(c *check.C) {
4603a725
 	testRequires(c, DaemonIsLinux) // Invalid volume paths on Windows
68bb56a4
 	var (
 		result   map[string]map[string]struct{}
 		name     = "testbuildvolumes"
 		emptyMap = make(map[string]struct{})
a5ca549a
 		expected = map[string]map[string]struct{}{
 			"/test1":  emptyMap,
 			"/test2":  emptyMap,
 			"/test3":  emptyMap,
 			"/test4":  emptyMap,
 			"/test5":  emptyMap,
 			"/test6":  emptyMap,
 			"[/test7": emptyMap,
 			"/test8]": emptyMap,
 		}
68bb56a4
 	)
c778f4b9
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM scratch
bf4d9070
 		VOLUME /test1
a5ca549a
 		VOLUME /test2
     VOLUME /test3 /test4
     VOLUME ["/test5", "/test6"]
     VOLUME [/test7 /test8]
c778f4b9
     `))
68bb56a4
 
c778f4b9
 	inspectFieldAndUnmarshall(c, name, "Config.Volumes", &result)
68bb56a4
 
fa753e67
 	equal := reflect.DeepEqual(&result, &expected)
68bb56a4
 	if !equal {
dc944ea7
 		c.Fatalf("Volumes %s, expected %s", result, expected)
68bb56a4
 	}
 
11f7f0bf
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildMaintainer(c *check.C) {
bf4d9070
 	name := "testbuildmaintainer"
4603a725
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
c778f4b9
         MAINTAINER dockerio`))
 
bf4d9070
 	expected := "dockerio"
62a856e9
 	res := inspectField(c, name, "Author")
bf4d9070
 	if res != expected {
dc944ea7
 		c.Fatalf("Maintainer %s, expected %s", res, expected)
bf4d9070
 	}
3dd4c5f4
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildUser(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
bf4d9070
 	name := "testbuilduser"
 	expected := "dockerio"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
360fb3d4
 		RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 		USER dockerio
c778f4b9
 		RUN [ $(whoami) = 'dockerio' ]`))
62a856e9
 	res := inspectField(c, name, "Config.User")
bf4d9070
 	if res != expected {
dc944ea7
 		c.Fatalf("User %s, expected %s", res, expected)
bf4d9070
 	}
360fb3d4
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildRelativeWorkdir(c *check.C) {
bf4d9070
 	name := "testbuildrelativeworkdir"
4603a725
 
 	var (
 		expected1     string
 		expected2     string
 		expected3     string
 		expected4     string
 		expectedFinal string
 	)
04338010
 
18a771a7
 	if testEnv.OSType == "windows" {
c2d18342
 		expected1 = `C:/`
4603a725
 		expected2 = `C:/test1`
 		expected3 = `C:/test2`
 		expected4 = `C:/test2/test3`
04338010
 		expectedFinal = `C:\test2\test3` // Note inspect is going to return Windows paths, as it's not in busybox
4603a725
 	} else {
 		expected1 = `/`
 		expected2 = `/test1`
 		expected3 = `/test2`
 		expected4 = `/test2/test3`
 		expectedFinal = `/test2/test3`
 	}
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
c2d18342
 		RUN sh -c "[ "$PWD" = "`+expected1+`" ]"
40630ce4
 		WORKDIR test1
c2d18342
 		RUN sh -c "[ "$PWD" = "`+expected2+`" ]"
40630ce4
 		WORKDIR /test2
c2d18342
 		RUN sh -c "[ "$PWD" = "`+expected3+`" ]"
40630ce4
 		WORKDIR test3
c778f4b9
 		RUN sh -c "[ "$PWD" = "`+expected4+`" ]"`))
 
62a856e9
 	res := inspectField(c, name, "Config.WorkingDir")
4603a725
 	if res != expectedFinal {
 		c.Fatalf("Workdir %s, expected %s", res, expectedFinal)
bf4d9070
 	}
40630ce4
 }
 
faab7170
 // #22181 Regression test. Single end-to-end test of using
 // Windows semantics. Most path handling verifications are in unit tests
04338010
 func (s *DockerSuite) TestBuildWindowsWorkdirProcessing(c *check.C) {
 	testRequires(c, DaemonIsWindows)
50c4475d
 	buildImageSuccessfully(c, "testbuildwindowsworkdirprocessing", build.WithDockerfile(`FROM busybox
faab7170
 		WORKDIR C:\\foo
04338010
 		WORKDIR bar
 		RUN sh -c "[ "$PWD" = "C:/foo/bar" ]"
c778f4b9
 		`))
04338010
 }
 
faab7170
 // #22181 Regression test. Most paths handling verifications are in unit test.
 // One functional test for end-to-end
04338010
 func (s *DockerSuite) TestBuildWindowsAddCopyPathProcessing(c *check.C) {
 	testRequires(c, DaemonIsWindows)
7e03ce3f
 	// TODO Windows (@jhowardmsft). Needs a follow-up PR to 22181 to
 	// support backslash such as .\\ being equivalent to ./ and c:\\ being
 	// equivalent to c:/. This is not currently (nor ever has been) supported
 	// by docker on the Windows platform.
56fb4653
 	buildImageSuccessfully(c, "testbuildwindowsaddcopypathprocessing", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `FROM busybox
faab7170
 			# No trailing slash on COPY/ADD
04338010
 			# Results in dir being changed to a file
 			WORKDIR /wc1
 			COPY wc1 c:/wc1
 			WORKDIR /wc2
 			ADD wc2 c:/wc2
 			WORKDIR c:/
286ab6d6
 			RUN sh -c "[ $(cat c:/wc1/wc1) = 'hellowc1' ]"
 			RUN sh -c "[ $(cat c:/wc2/wc2) = 'worldwc2' ]"
04338010
 
fb42e847
 			# Trailing slash on COPY/ADD, Windows-style path.
04338010
 			WORKDIR /wd1
 			COPY wd1 c:/wd1/
 			WORKDIR /wd2
 			ADD wd2 c:/wd2/
 			RUN sh -c "[ $(cat c:/wd1/wd1) = 'hellowd1' ]"
 			RUN sh -c "[ $(cat c:/wd2/wd2) = 'worldwd2' ]"
c778f4b9
 			`),
56fb4653
 		build.WithFile("wc1", "hellowc1"),
 		build.WithFile("wc2", "worldwc2"),
 		build.WithFile("wd1", "hellowd1"),
 		build.WithFile("wd2", "worldwd2"),
c778f4b9
 	))
04338010
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildWorkdirWithEnvVariables(c *check.C) {
2c5b5cfc
 	name := "testbuildworkdirwithenvvariables"
4603a725
 
 	var expected string
18a771a7
 	if testEnv.OSType == "windows" {
04338010
 		expected = `C:\test1\test2`
4603a725
 	} else {
 		expected = `/test1/test2`
 	}
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
2c5b5cfc
 		ENV DIRPATH /test1
 		ENV SUBDIRNAME test2
 		WORKDIR $DIRPATH
c778f4b9
 		WORKDIR $SUBDIRNAME/$MISSING_VAR`))
62a856e9
 	res := inspectField(c, name, "Config.WorkingDir")
2c5b5cfc
 	if res != expected {
dc944ea7
 		c.Fatalf("Workdir %s, expected %s", res, expected)
2c5b5cfc
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildRelativeCopy(c *check.C) {
ea3afdad
 	// cat /test1/test2/foo gets permission denied for the user
 	testRequires(c, NotUserNamespace)
4603a725
 
 	var expected string
18a771a7
 	if testEnv.OSType == "windows" {
4603a725
 		expected = `C:/test1/test2`
 	} else {
 		expected = `/test1/test2`
 	}
 
56fb4653
 	buildImageSuccessfully(c, "testbuildrelativecopy", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `FROM busybox
f21f9f85
 			WORKDIR /test1
 			WORKDIR test2
c778f4b9
 			RUN sh -c "[ "$PWD" = '`+expected+`' ]"
f21f9f85
 			COPY foo ./
4603a725
 			RUN sh -c "[ $(cat /test1/test2/foo) = 'hello' ]"
f21f9f85
 			ADD foo ./bar/baz
4603a725
 			RUN sh -c "[ $(cat /test1/test2/bar/baz) = 'hello' ]"
f21f9f85
 			COPY foo ./bar/baz2
4603a725
 			RUN sh -c "[ $(cat /test1/test2/bar/baz2) = 'hello' ]"
f21f9f85
 			WORKDIR ..
 			COPY foo ./
4603a725
 			RUN sh -c "[ $(cat /test1/foo) = 'hello' ]"
f21f9f85
 			COPY foo /test3/
4603a725
 			RUN sh -c "[ $(cat /test3/foo) = 'hello' ]"
f21f9f85
 			WORKDIR /test4
 			COPY . .
4603a725
 			RUN sh -c "[ $(cat /test4/foo) = 'hello' ]"
f21f9f85
 			WORKDIR /test5/test6
 			COPY foo ../
4603a725
 			RUN sh -c "[ $(cat /test5/foo) = 'hello' ]"
c778f4b9
 			`),
56fb4653
 		build.WithFile("foo", "hello"),
c778f4b9
 	))
f21f9f85
 }
 
e72c0137
 func (s *DockerSuite) TestBuildBlankName(c *check.C) {
 	name := "testbuildblankname"
c778f4b9
 	testCases := []struct {
 		expression     string
 		expectedStderr string
 	}{
 		{
 			expression:     "ENV =",
 			expectedStderr: "ENV names can not be blank",
 		},
 		{
 			expression:     "LABEL =",
 			expectedStderr: "LABEL names can not be blank",
 		},
 		{
 			expression:     "ARG =foo",
 			expectedStderr: "ARG names can not be blank",
 		},
e72c0137
 	}
 
c778f4b9
 	for _, tc := range testCases {
50c4475d
 		buildImage(name, build.WithDockerfile(fmt.Sprintf(`FROM busybox
c778f4b9
 		%s`, tc.expression))).Assert(c, icmd.Expected{
 			ExitCode: 1,
 			Err:      tc.expectedStderr,
 		})
e72c0137
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnv(c *check.C) {
4603a725
 	testRequires(c, DaemonIsLinux) // ENV expansion is different in Windows
bf4d9070
 	name := "testbuildenv"
cb51681a
 	expected := "[PATH=/test:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PORT=2375]"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
cb51681a
 		ENV PATH /test:$PATH
c778f4b9
 		ENV PORT 2375
 		RUN [ $(env | grep PORT) = 'PORT=2375' ]`))
62a856e9
 	res := inspectField(c, name, "Config.Env")
bf4d9070
 	if res != expected {
dc944ea7
 		c.Fatalf("Env %s, expected %s", res, expected)
bf4d9070
 	}
b05be686
 }
 
d3ea7e80
 func (s *DockerSuite) TestBuildPATH(c *check.C) {
4603a725
 	testRequires(c, DaemonIsLinux) // ENV expansion is different in Windows
d3ea7e80
 
 	defPath := "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
 
c778f4b9
 	fn := func(dockerfile string, expected string) {
50c4475d
 		buildImageSuccessfully(c, "testbldpath", build.WithDockerfile(dockerfile))
62a856e9
 		res := inspectField(c, "testbldpath", "Config.Env")
c778f4b9
 		if res != expected {
 			c.Fatalf("Env %q, expected %q for dockerfile:%q", res, expected, dockerfile)
d3ea7e80
 		}
 	}
 
 	tests := []struct{ dockerfile, exp string }{
 		{"FROM scratch\nMAINTAINER me", "[PATH=" + defPath + "]"},
 		{"FROM busybox\nMAINTAINER me", "[PATH=" + defPath + "]"},
 		{"FROM scratch\nENV FOO=bar", "[PATH=" + defPath + " FOO=bar]"},
 		{"FROM busybox\nENV FOO=bar", "[PATH=" + defPath + " FOO=bar]"},
 		{"FROM scratch\nENV PATH=/test", "[PATH=/test]"},
 		{"FROM busybox\nENV PATH=/test", "[PATH=/test]"},
 		{"FROM scratch\nENV PATH=''", "[PATH=]"},
 		{"FROM busybox\nENV PATH=''", "[PATH=]"},
 	}
 
 	for _, test := range tests {
 		fn(test.dockerfile, test.exp)
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildContextCleanup(c *check.C) {
 	testRequires(c, SameHostDaemon)
b686b65c
 
18587469
 	name := "testbuildcontextcleanup"
142b1f8b
 	entries, err := ioutil.ReadDir(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "tmp"))
18587469
 	if err != nil {
dc944ea7
 		c.Fatalf("failed to list contents of tmp dir: %s", err)
18587469
 	}
c778f4b9
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
c778f4b9
         ENTRYPOINT ["/bin/echo"]`))
 
142b1f8b
 	entriesFinal, err := ioutil.ReadDir(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "tmp"))
18587469
 	if err != nil {
dc944ea7
 		c.Fatalf("failed to list contents of tmp dir: %s", err)
18587469
 	}
6151d55e
 	if err = compareDirectoryEntries(entries, entriesFinal); err != nil {
dc944ea7
 		c.Fatalf("context should have been deleted, but wasn't")
18587469
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildContextCleanupFailedBuild(c *check.C) {
 	testRequires(c, SameHostDaemon)
b686b65c
 
31c00390
 	name := "testbuildcontextcleanup"
142b1f8b
 	entries, err := ioutil.ReadDir(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "tmp"))
31c00390
 	if err != nil {
dc944ea7
 		c.Fatalf("failed to list contents of tmp dir: %s", err)
31c00390
 	}
c778f4b9
 
50c4475d
 	buildImage(name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
c778f4b9
 	RUN /non/existing/command`)).Assert(c, icmd.Expected{
 		ExitCode: 1,
 	})
 
142b1f8b
 	entriesFinal, err := ioutil.ReadDir(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "tmp"))
31c00390
 	if err != nil {
dc944ea7
 		c.Fatalf("failed to list contents of tmp dir: %s", err)
31c00390
 	}
6151d55e
 	if err = compareDirectoryEntries(entries, entriesFinal); err != nil {
dc944ea7
 		c.Fatalf("context should have been deleted, but wasn't")
31c00390
 	}
 
 }
 
6151d55e
 // compareDirectoryEntries compares two sets of FileInfo (usually taken from a directory)
 // and returns an error if different.
 func compareDirectoryEntries(e1 []os.FileInfo, e2 []os.FileInfo) error {
 	var (
 		e1Entries = make(map[string]struct{})
 		e2Entries = make(map[string]struct{})
 	)
 	for _, e := range e1 {
 		e1Entries[e.Name()] = struct{}{}
 	}
 	for _, e := range e2 {
 		e2Entries[e.Name()] = struct{}{}
 	}
 	if !reflect.DeepEqual(e1Entries, e2Entries) {
 		return fmt.Errorf("entries differ")
 	}
 	return nil
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCmd(c *check.C) {
bf4d9070
 	name := "testbuildcmd"
53b0d626
 	expected := "[/bin/echo Hello World]"
c778f4b9
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
c778f4b9
         CMD ["/bin/echo", "Hello World"]`))
 
62a856e9
 	res := inspectField(c, name, "Config.Cmd")
bf4d9070
 	if res != expected {
dc944ea7
 		c.Fatalf("Cmd %s, expected %s", res, expected)
bf4d9070
 	}
c58991f3
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildExpose(c *check.C) {
4603a725
 	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
bf4d9070
 	name := "testbuildexpose"
231d362d
 	expected := "map[2375/tcp:{}]"
c778f4b9
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM scratch
c778f4b9
         EXPOSE 2375`))
 
62a856e9
 	res := inspectField(c, name, "Config.ExposedPorts")
bf4d9070
 	if res != expected {
dc944ea7
 		c.Fatalf("Exposed ports %s, expected %s", res, expected)
bf4d9070
 	}
81d16411
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildExposeMorePorts(c *check.C) {
4603a725
 	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
29be7b43
 	// start building docker file with a large number of ports
 	portList := make([]string, 50)
 	line := make([]string, 100)
 	expectedPorts := make([]int, len(portList)*len(line))
 	for i := 0; i < len(portList); i++ {
 		for j := 0; j < len(line); j++ {
 			p := i*len(line) + j + 1
 			line[j] = strconv.Itoa(p)
 			expectedPorts[p-1] = p
 		}
 		if i == len(portList)-1 {
 			portList[i] = strings.Join(line, " ")
 		} else {
 			portList[i] = strings.Join(line, " ") + ` \`
 		}
 	}
 
 	dockerfile := `FROM scratch
 	EXPOSE {{range .}} {{.}}
 	{{end}}`
 	tmpl := template.Must(template.New("dockerfile").Parse(dockerfile))
 	buf := bytes.NewBuffer(nil)
 	tmpl.Execute(buf, portList)
 
 	name := "testbuildexpose"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(buf.String()))
29be7b43
 
 	// check if all the ports are saved inside Config.ExposedPorts
62a856e9
 	res := inspectFieldJSON(c, name, "Config.ExposedPorts")
29be7b43
 	var exposedPorts map[string]interface{}
 	if err := json.Unmarshal([]byte(res), &exposedPorts); err != nil {
dc944ea7
 		c.Fatal(err)
29be7b43
 	}
 
 	for _, p := range expectedPorts {
 		ep := fmt.Sprintf("%d/tcp", p)
 		if _, ok := exposedPorts[ep]; !ok {
dc944ea7
 			c.Errorf("Port(%s) is not exposed", ep)
29be7b43
 		} else {
 			delete(exposedPorts, ep)
 		}
 	}
 	if len(exposedPorts) != 0 {
dc944ea7
 		c.Errorf("Unexpected extra exposed ports %v", exposedPorts)
29be7b43
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildExposeOrder(c *check.C) {
4603a725
 	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
1e7ba09b
 	buildID := func(name, exposed string) string {
50c4475d
 		buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`FROM scratch
c778f4b9
 		EXPOSE %s`, exposed)))
62a856e9
 		id := inspectField(c, name, "Id")
1e7ba09b
 		return id
 	}
 
 	id1 := buildID("testbuildexpose1", "80 2375")
 	id2 := buildID("testbuildexpose2", "2375 80")
 	if id1 != id2 {
dc944ea7
 		c.Errorf("EXPOSE should invalidate the cache only when ports actually changed")
1e7ba09b
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildExposeUpperCaseProto(c *check.C) {
4603a725
 	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
0552f1a0
 	name := "testbuildexposeuppercaseproto"
231d362d
 	expected := "map[5678/udp:{}]"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM scratch
c778f4b9
         EXPOSE 5678/UDP`))
62a856e9
 	res := inspectField(c, name, "Config.ExposedPorts")
0552f1a0
 	if res != expected {
dc944ea7
 		c.Fatalf("Exposed ports %s, expected %s", res, expected)
0552f1a0
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEmptyEntrypointInheritance(c *check.C) {
cdd6e979
 	name := "testbuildentrypointinheritance"
 	name2 := "testbuildentrypointinheritance2"
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
c778f4b9
         ENTRYPOINT ["/bin/echo"]`))
62a856e9
 	res := inspectField(c, name, "Config.Entrypoint")
cdd6e979
 
53b0d626
 	expected := "[/bin/echo]"
cdd6e979
 	if res != expected {
dc944ea7
 		c.Fatalf("Entrypoint %s, expected %s", res, expected)
cdd6e979
 	}
 
50c4475d
 	buildImageSuccessfully(c, name2, build.WithDockerfile(fmt.Sprintf(`FROM %s
c778f4b9
         ENTRYPOINT []`, name)))
62a856e9
 	res = inspectField(c, name2, "Config.Entrypoint")
cdd6e979
 
53b0d626
 	expected = "[]"
cdd6e979
 	if res != expected {
dc944ea7
 		c.Fatalf("Entrypoint %s, expected %s", res, expected)
cdd6e979
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEmptyEntrypoint(c *check.C) {
bf4d9070
 	name := "testbuildentrypoint"
53b0d626
 	expected := "[]"
576416c9
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
c778f4b9
         ENTRYPOINT []`))
 
62a856e9
 	res := inspectField(c, name, "Config.Entrypoint")
bf4d9070
 	if res != expected {
dc944ea7
 		c.Fatalf("Entrypoint %s, expected %s", res, expected)
bf4d9070
 	}
78a847a4
 
576416c9
 }
78a847a4
 
dc944ea7
 func (s *DockerSuite) TestBuildEntrypoint(c *check.C) {
576416c9
 	name := "testbuildentrypoint"
4603a725
 
53b0d626
 	expected := "[/bin/echo]"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
c778f4b9
         ENTRYPOINT ["/bin/echo"]`))
 
62a856e9
 	res := inspectField(c, name, "Config.Entrypoint")
78a847a4
 	if res != expected {
dc944ea7
 		c.Fatalf("Entrypoint %s, expected %s", res, expected)
78a847a4
 	}
 
b25a9b71
 }
 
a5729879
 // #6445 ensure ONBUILD triggers aren't committed to grandchildren
39bcaee4
 func (s *DockerSuite) TestBuildOnBuildLimitedInheritance(c *check.C) {
50c4475d
 	buildImageSuccessfully(c, "testonbuildtrigger1", build.WithDockerfile(`
a5729879
 		FROM busybox
 		RUN echo "GRANDPARENT"
 		ONBUILD RUN echo "ONBUILD PARENT"
c778f4b9
 		`))
a5729879
 	// ONBUILD should be run in second build.
50c4475d
 	buildImage("testonbuildtrigger2", build.WithDockerfile("FROM testonbuildtrigger1")).Assert(c, icmd.Expected{
c778f4b9
 		Out: "ONBUILD PARENT",
 	})
a5729879
 	// ONBUILD should *not* be run in third build.
50c4475d
 	result := buildImage("testonbuildtrigger3", build.WithDockerfile("FROM testonbuildtrigger2"))
c778f4b9
 	result.Assert(c, icmd.Success)
 	if strings.Contains(result.Combined(), "ONBUILD PARENT") {
dc944ea7
 		c.Fatalf("ONBUILD instruction ran in grandchild of ONBUILD parent")
a5729879
 	}
 }
 
c778f4b9
 func (s *DockerSuite) TestBuildSameDockerfileWithAndWithoutCache(c *check.C) {
4603a725
 	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
ae128437
 	name := "testbuildwithcache"
c778f4b9
 	dockerfile := `FROM scratch
ae128437
 		MAINTAINER dockerio
 		EXPOSE 5432
c778f4b9
         ENTRYPOINT ["/bin/echo"]`
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(dockerfile))
c10f6ef4
 	id1 := getIDByName(c, name)
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(dockerfile))
c10f6ef4
 	id2 := getIDByName(c, name)
50c4475d
 	buildImageSuccessfully(c, name, build.WithoutCache, build.WithDockerfile(dockerfile))
c10f6ef4
 	id3 := getIDByName(c, name)
ae128437
 	if id1 != id2 {
dc944ea7
 		c.Fatal("The cache should have been used but hasn't.")
ae128437
 	}
c778f4b9
 	if id1 == id3 {
dc944ea7
 		c.Fatal("The cache should have been invalided but hasn't.")
ae128437
 	}
 }
 
c778f4b9
 // Make sure that ADD/COPY still populate the cache even if they don't use it
dc944ea7
 func (s *DockerSuite) TestBuildConditionalCache(c *check.C) {
6f20b957
 	name := "testbuildconditionalcache"
 
 	dockerfile := `
 		FROM busybox
         ADD foo /tmp/`
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(dockerfile),
 		fakecontext.WithFiles(map[string]string{
 			"foo": "hello",
 		}))
f6e95ef3
 	defer ctx.Close()
6f20b957
 
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id1 := getIDByName(c, name)
6f20b957
 
 	if err := ctx.Add("foo", "bye"); err != nil {
dc944ea7
 		c.Fatalf("Error modifying foo: %s", err)
6f20b957
 	}
 
c778f4b9
 	// Updating a file should invalidate the cache
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id2 := getIDByName(c, name)
6f20b957
 	if id2 == id1 {
dc944ea7
 		c.Fatal("Should not have used the cache")
6f20b957
 	}
 
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id3 := getIDByName(c, name)
6f20b957
 	if id3 != id2 {
dc944ea7
 		c.Fatal("Should have used the cache")
6f20b957
 	}
 }
 
c778f4b9
 func (s *DockerSuite) TestBuildAddMultipleLocalFileWithAndWithoutCache(c *check.C) {
05b8a1eb
 	name := "testbuildaddmultiplelocalfilewithcache"
d9371ee8
 	baseName := name + "-base"
 
 	cli.BuildCmd(c, baseName, build.WithDockerfile(`
05b8a1eb
 		FROM busybox
d9371ee8
 		ENTRYPOINT ["/bin/sh"]
 	`))
 
 	dockerfile := `
 		FROM testbuildaddmultiplelocalfilewithcache-base
05b8a1eb
         MAINTAINER dockerio
         ADD foo Dockerfile /usr/lib/bla/
4603a725
 		RUN sh -c "[ $(cat /usr/lib/bla/foo) = "hello" ]"`
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile), fakecontext.WithFiles(map[string]string{
05b8a1eb
 		"foo": "hello",
56fb4653
 	}))
04ef69a1
 	defer ctx.Close()
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id1 := getIDByName(c, name)
d9371ee8
 	result2 := cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id2 := getIDByName(c, name)
d9371ee8
 	result3 := cli.BuildCmd(c, name, build.WithoutCache, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id3 := getIDByName(c, name)
c778f4b9
 	if id1 != id2 {
d9371ee8
 		c.Fatalf("The cache should have been used but hasn't: %s", result2.Stdout())
ae128437
 	}
c778f4b9
 	if id1 == id3 {
d9371ee8
 		c.Fatalf("The cache should have been invalided but hasn't: %s", result3.Stdout())
ae128437
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopyDirButNotFile(c *check.C) {
cd329d06
 	name := "testbuildcopydirbutnotfile"
da3d3b97
 	name2 := "testbuildcopydirbutnotfile2"
4603a725
 
cd329d06
 	dockerfile := `
4603a725
         FROM ` + minimalBaseImage() + `
cd329d06
         COPY dir /tmp/`
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile), fakecontext.WithFiles(map[string]string{
cd329d06
 		"dir/foo": "hello",
56fb4653
 	}))
04ef69a1
 	defer ctx.Close()
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id1 := getIDByName(c, name)
cd329d06
 	// Check that adding file with similar name doesn't mess with cache
 	if err := ctx.Add("dir_file", "hello2"); err != nil {
dc944ea7
 		c.Fatal(err)
cd329d06
 	}
56fb4653
 	cli.BuildCmd(c, name2, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id2 := getIDByName(c, name2)
cd329d06
 	if id1 != id2 {
dc944ea7
 		c.Fatal("The cache should have been used but wasn't")
cd329d06
 	}
 }
 
ab121345
 func (s *DockerSuite) TestBuildAddCurrentDirWithCache(c *check.C) {
ae128437
 	name := "testbuildaddcurrentdirwithcache"
da3d3b97
 	name2 := name + "2"
 	name3 := name + "3"
 	name4 := name + "4"
ae128437
 	dockerfile := `
eed648ac
         FROM ` + minimalBaseImage() + `
ae128437
         MAINTAINER dockerio
         ADD . /usr/lib/bla`
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile), fakecontext.WithFiles(map[string]string{
ae128437
 		"foo": "hello",
56fb4653
 	}))
04ef69a1
 	defer ctx.Close()
56fb4653
 	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id1 := getIDByName(c, name)
ae128437
 	// Check that adding file invalidate cache of "ADD ."
 	if err := ctx.Add("bar", "hello2"); err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
56fb4653
 	buildImageSuccessfully(c, name2, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id2 := getIDByName(c, name2)
ae128437
 	if id1 == id2 {
dc944ea7
 		c.Fatal("The cache should have been invalided but hasn't.")
ae128437
 	}
 	// Check that changing file invalidate cache of "ADD ."
 	if err := ctx.Add("foo", "hello1"); err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
56fb4653
 	buildImageSuccessfully(c, name3, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id3 := getIDByName(c, name3)
ae128437
 	if id2 == id3 {
dc944ea7
 		c.Fatal("The cache should have been invalided but hasn't.")
ae128437
 	}
0e10507a
 	// Check that changing file to same content with different mtime does not
 	// invalidate cache of "ADD ."
ae128437
 	time.Sleep(1 * time.Second) // wait second because of mtime precision
 	if err := ctx.Add("foo", "hello1"); err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
56fb4653
 	buildImageSuccessfully(c, name4, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id4 := getIDByName(c, name4)
0e10507a
 	if id3 != id4 {
dc944ea7
 		c.Fatal("The cache should have been used but hasn't.")
ae128437
 	}
 }
 
c778f4b9
 // FIXME(vdemeester) this really seems to test the same thing as before (TestBuildAddMultipleLocalFileWithAndWithoutCache)
ab121345
 func (s *DockerSuite) TestBuildAddCurrentDirWithoutCache(c *check.C) {
ae128437
 	name := "testbuildaddcurrentdirwithoutcache"
 	dockerfile := `
eed648ac
         FROM ` + minimalBaseImage() + `
ae128437
         MAINTAINER dockerio
         ADD . /usr/lib/bla`
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile), fakecontext.WithFiles(map[string]string{
ae128437
 		"foo": "hello",
56fb4653
 	}))
04ef69a1
 	defer ctx.Close()
56fb4653
 	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id1 := getIDByName(c, name)
56fb4653
 	buildImageSuccessfully(c, name, build.WithoutCache, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id2 := getIDByName(c, name)
ae128437
 	if id1 == id2 {
dc944ea7
 		c.Fatal("The cache should have been invalided but hasn't.")
ae128437
 	}
 }
 
c778f4b9
 func (s *DockerSuite) TestBuildAddRemoteFileWithAndWithoutCache(c *check.C) {
ae128437
 	name := "testbuildaddremotefilewithcache"
56fb4653
 	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
ae128437
 		"baz": "hello",
56fb4653
 	}))
ae128437
 	defer server.Close()
2e95bb5f
 
c778f4b9
 	dockerfile := fmt.Sprintf(`FROM `+minimalBaseImage()+`
ae128437
         MAINTAINER dockerio
c778f4b9
         ADD %s/baz /usr/lib/baz/quux`, server.URL())
56fb4653
 	cli.BuildCmd(c, name, build.WithDockerfile(dockerfile))
c10f6ef4
 	id1 := getIDByName(c, name)
56fb4653
 	cli.BuildCmd(c, name, build.WithDockerfile(dockerfile))
c10f6ef4
 	id2 := getIDByName(c, name)
56fb4653
 	cli.BuildCmd(c, name, build.WithoutCache, build.WithDockerfile(dockerfile))
c10f6ef4
 	id3 := getIDByName(c, name)
c778f4b9
 
ae128437
 	if id1 != id2 {
dc944ea7
 		c.Fatal("The cache should have been used but hasn't.")
ae128437
 	}
c778f4b9
 	if id1 == id3 {
dc944ea7
 		c.Fatal("The cache should have been invalided but hasn't.")
ae128437
 	}
 }
 
ab121345
 func (s *DockerSuite) TestBuildAddRemoteFileMTime(c *check.C) {
2e482c86
 	name := "testbuildaddremotefilemtime"
da3d3b97
 	name2 := name + "2"
 	name3 := name + "3"
 
2e95bb5f
 	files := map[string]string{"baz": "hello"}
56fb4653
 	server := fakestorage.New(c, "", fakecontext.WithFiles(files))
2e482c86
 	defer server.Close()
 
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(fmt.Sprintf(`FROM `+minimalBaseImage()+`
2e482c86
         MAINTAINER dockerio
56fb4653
         ADD %s/baz /usr/lib/baz/quux`, server.URL())))
2e482c86
 	defer ctx.Close()
 
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id1 := getIDByName(c, name)
56fb4653
 	cli.BuildCmd(c, name2, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id2 := getIDByName(c, name2)
2e482c86
 	if id1 != id2 {
dc944ea7
 		c.Fatal("The cache should have been used but wasn't - #1")
2e482c86
 	}
 
0e10507a
 	// Now create a different server with same contents (causes different mtime)
 	// The cache should still be used
2e95bb5f
 
 	// allow some time for clock to pass as mtime precision is only 1s
 	time.Sleep(2 * time.Second)
 
56fb4653
 	server2 := fakestorage.New(c, "", fakecontext.WithFiles(files))
2e95bb5f
 	defer server2.Close()
2e482c86
 
56fb4653
 	ctx2 := fakecontext.New(c, "", fakecontext.WithDockerfile(fmt.Sprintf(`FROM `+minimalBaseImage()+`
2e95bb5f
         MAINTAINER dockerio
56fb4653
         ADD %s/baz /usr/lib/baz/quux`, server2.URL())))
2e95bb5f
 	defer ctx2.Close()
56fb4653
 	cli.BuildCmd(c, name3, build.WithExternalBuildContext(ctx2))
c10f6ef4
 	id3 := getIDByName(c, name3)
0e10507a
 	if id1 != id3 {
 		c.Fatal("The cache should have been used but wasn't")
2e482c86
 	}
 }
 
c778f4b9
 // FIXME(vdemeester) this really seems to test the same thing as before (combined)
 func (s *DockerSuite) TestBuildAddLocalAndRemoteFilesWithAndWithoutCache(c *check.C) {
ae128437
 	name := "testbuildaddlocalandremotefilewithcache"
56fb4653
 	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
ae128437
 		"baz": "hello",
56fb4653
 	}))
ae128437
 	defer server.Close()
2e95bb5f
 
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(fmt.Sprintf(`FROM `+minimalBaseImage()+`
ae128437
         MAINTAINER dockerio
         ADD foo /usr/lib/bla/bar
56fb4653
         ADD %s/baz /usr/lib/baz/quux`, server.URL())),
 		fakecontext.WithFiles(map[string]string{
ae128437
 			"foo": "hello world",
56fb4653
 		}))
ae128437
 	defer ctx.Close()
56fb4653
 	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id1 := getIDByName(c, name)
56fb4653
 	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id2 := getIDByName(c, name)
56fb4653
 	buildImageSuccessfully(c, name, build.WithoutCache, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id3 := getIDByName(c, name)
ae128437
 	if id1 != id2 {
dc944ea7
 		c.Fatal("The cache should have been used but hasn't.")
ae128437
 	}
c778f4b9
 	if id1 == id3 {
 		c.Fatal("The cache should have been invalidated but hasn't.")
 	}
ae128437
 }
 
dc944ea7
 func testContextTar(c *check.C, compression archive.Compression) {
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(`FROM busybox
d302d929
 ADD foo /foo
56fb4653
 CMD ["cat", "/foo"]`),
 		fakecontext.WithFiles(map[string]string{
d302d929
 			"foo": "bar",
56fb4653
 		}),
d302d929
 	)
04ef69a1
 	defer ctx.Close()
d302d929
 	context, err := archive.Tar(ctx.Dir, compression)
edcb4145
 	if err != nil {
dc944ea7
 		c.Fatalf("failed to build context tar: %v", err)
edcb4145
 	}
d302d929
 	name := "contexttar"
edcb4145
 
56fb4653
 	cli.BuildCmd(c, name, build.WithStdinContext(context))
edcb4145
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildContextTarGzip(c *check.C) {
 	testContextTar(c, archive.Gzip)
edcb4145
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildContextTarNoCompression(c *check.C) {
 	testContextTar(c, archive.Uncompressed)
edcb4145
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildNoContext(c *check.C) {
c778f4b9
 	name := "nocontext"
 	icmd.RunCmd(icmd.Cmd{
 		Command: []string{dockerBinary, "build", "-t", name, "-"},
 		Stdin: strings.NewReader(
 			`FROM busybox
 			CMD ["echo", "ok"]`),
 	}).Assert(c, icmd.Success)
edcb4145
 
dc944ea7
 	if out, _ := dockerCmd(c, "run", "--rm", "nocontext"); out != "ok\n" {
 		c.Fatalf("run produced invalid output: %q, expected %q", out, "ok")
edcb4145
 	}
 }
 
3f6dc81e
 func (s *DockerSuite) TestBuildDockerfileStdin(c *check.C) {
 	name := "stdindockerfile"
 	tmpDir, err := ioutil.TempDir("", "fake-context")
 	c.Assert(err, check.IsNil)
 	err = ioutil.WriteFile(filepath.Join(tmpDir, "foo"), []byte("bar"), 0600)
 	c.Assert(err, check.IsNil)
 
 	icmd.RunCmd(icmd.Cmd{
 		Command: []string{dockerBinary, "build", "-t", name, "-f", "-", tmpDir},
 		Stdin: strings.NewReader(
 			`FROM busybox
 ADD foo /foo
 CMD ["cat", "/foo"]`),
 	}).Assert(c, icmd.Success)
 
 	res := inspectField(c, name, "Config.Cmd")
 	c.Assert(strings.TrimSpace(string(res)), checker.Equals, `[cat /foo]`)
 }
 
 func (s *DockerSuite) TestBuildDockerfileStdinConflict(c *check.C) {
 	name := "stdindockerfiletarcontext"
 	icmd.RunCmd(icmd.Cmd{
 		Command: []string{dockerBinary, "build", "-t", name, "-f", "-", "-"},
 	}).Assert(c, icmd.Expected{
 		ExitCode: 1,
 		Err:      "use stdin for both build context and dockerfile",
 	})
 }
 
 func (s *DockerSuite) TestBuildDockerfileStdinNoExtraFiles(c *check.C) {
 	s.testBuildDockerfileStdinNoExtraFiles(c, false, false)
 }
 
 func (s *DockerSuite) TestBuildDockerfileStdinDockerignore(c *check.C) {
 	s.testBuildDockerfileStdinNoExtraFiles(c, true, false)
 }
 
 func (s *DockerSuite) TestBuildDockerfileStdinDockerignoreIgnored(c *check.C) {
 	s.testBuildDockerfileStdinNoExtraFiles(c, true, true)
 }
 
 func (s *DockerSuite) testBuildDockerfileStdinNoExtraFiles(c *check.C, hasDockerignore, ignoreDockerignore bool) {
 	name := "stdindockerfilenoextra"
 	tmpDir, err := ioutil.TempDir("", "fake-context")
 	c.Assert(err, check.IsNil)
8cd6c30a
 	defer os.RemoveAll(tmpDir)
 
 	writeFile := func(filename, content string) {
 		err = ioutil.WriteFile(filepath.Join(tmpDir, filename), []byte(content), 0600)
3f6dc81e
 		c.Assert(err, check.IsNil)
8cd6c30a
 	}
 
 	writeFile("foo", "bar")
 
 	if hasDockerignore {
 		// Add an empty Dockerfile to verify that it is not added to the image
 		writeFile("Dockerfile", "")
 
3f6dc81e
 		ignores := "Dockerfile\n"
 		if ignoreDockerignore {
 			ignores += ".dockerignore\n"
 		}
8cd6c30a
 		writeFile(".dockerignore", ignores)
3f6dc81e
 	}
 
8cd6c30a
 	result := icmd.RunCmd(icmd.Cmd{
3f6dc81e
 		Command: []string{dockerBinary, "build", "-t", name, "-f", "-", tmpDir},
 		Stdin: strings.NewReader(
 			`FROM busybox
 COPY . /baz`),
8cd6c30a
 	})
 	result.Assert(c, icmd.Success)
3f6dc81e
 
8cd6c30a
 	result = cli.DockerCmd(c, "run", "--rm", name, "ls", "-A", "/baz")
3f6dc81e
 	if hasDockerignore && !ignoreDockerignore {
8cd6c30a
 		c.Assert(result.Stdout(), checker.Equals, ".dockerignore\nfoo\n")
3f6dc81e
 	} else {
8cd6c30a
 		c.Assert(result.Stdout(), checker.Equals, "foo\n")
3f6dc81e
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildWithVolumeOwnership(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
c024c9bd
 	name := "testbuildimg"
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox:latest
c024c9bd
         RUN mkdir /test && chown daemon:daemon /test && chmod 0600 /test
c778f4b9
         VOLUME /test`))
c024c9bd
 
5c295460
 	out, _ := dockerCmd(c, "run", "--rm", "testbuildimg", "ls", "-la", "/test")
c024c9bd
 	if expected := "drw-------"; !strings.Contains(out, expected) {
dc944ea7
 		c.Fatalf("expected %s received %s", expected, out)
c024c9bd
 	}
 	if expected := "daemon   daemon"; !strings.Contains(out, expected) {
dc944ea7
 		c.Fatalf("expected %s received %s", expected, out)
c024c9bd
 	}
 
 }
c5b82f5e
 
 // testing #1405 - config.Cmd does not get cleaned up if
 // utilizing cache
dc944ea7
 func (s *DockerSuite) TestBuildEntrypointRunCleanup(c *check.C) {
c5b82f5e
 	name := "testbuildcmdcleanup"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
c778f4b9
         RUN echo "hello"`))
c5b82f5e
 
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `FROM busybox
c5b82f5e
         RUN echo "hello"
         ADD foo /foo
c778f4b9
         ENTRYPOINT ["/bin/echo"]`),
56fb4653
 		build.WithFile("foo", "hello")))
c778f4b9
 
62a856e9
 	res := inspectField(c, name, "Config.Cmd")
1b6546b8
 	// Cmd must be cleaned up
53b0d626
 	if res != "[]" {
231d362d
 		c.Fatalf("Cmd %s, expected nil", res)
c5b82f5e
 	}
 }
686786f1
 
ab121345
 func (s *DockerSuite) TestBuildAddFileNotFound(c *check.C) {
62d97afa
 	name := "testbuildaddnotfound"
eed648ac
 	expected := "foo: no such file or directory"
 
18a771a7
 	if testEnv.OSType == "windows" {
eed648ac
 		expected = "foo: The system cannot find the file specified"
 	}
 
56fb4653
 	buildImage(name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `FROM `+minimalBaseImage()+`
c778f4b9
         ADD foo /usr/local/bar`),
56fb4653
 		build.WithFile("bar", "hello"))).Assert(c, icmd.Expected{
c778f4b9
 		ExitCode: 1,
 		Err:      expected,
 	})
62d97afa
 }
f1d7ed35
 
dc944ea7
 func (s *DockerSuite) TestBuildInheritance(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
f1d7ed35
 	name := "testbuildinheritance"
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM scratch
c778f4b9
 		EXPOSE 2375`))
62a856e9
 	ports1 := inspectField(c, name, "Config.ExposedPorts")
f1d7ed35
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`FROM %s
c778f4b9
 		ENTRYPOINT ["/bin/echo"]`, name)))
f1d7ed35
 
62a856e9
 	res := inspectField(c, name, "Config.Entrypoint")
53b0d626
 	if expected := "[/bin/echo]"; res != expected {
dc944ea7
 		c.Fatalf("Entrypoint %s, expected %s", res, expected)
f1d7ed35
 	}
62a856e9
 	ports2 := inspectField(c, name, "Config.ExposedPorts")
f1d7ed35
 	if ports1 != ports2 {
dc944ea7
 		c.Fatalf("Ports must be same: %s != %s", ports1, ports2)
f1d7ed35
 	}
 }
d3023f25
 
dc944ea7
 func (s *DockerSuite) TestBuildFails(c *check.C) {
d3023f25
 	name := "testbuildfails"
50c4475d
 	buildImage(name, build.WithDockerfile(`FROM busybox
c778f4b9
 		RUN sh -c "exit 23"`)).Assert(c, icmd.Expected{
 		ExitCode: 23,
 		Err:      "returned a non-zero code: 23",
 	})
d3023f25
 }
08a10f93
 
dc944ea7
 func (s *DockerSuite) TestBuildOnBuild(c *check.C) {
2629e2ec
 	name := "testbuildonbuild"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
c778f4b9
 		ONBUILD RUN touch foobar`))
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`FROM %s
c778f4b9
 		RUN [ -f foobar ]`, name)))
2629e2ec
 }
1e0e8636
 
cc42eeac
 // gh #2446
dc944ea7
 func (s *DockerSuite) TestBuildAddToSymlinkDest(c *check.C) {
fdce2a77
 	makeLink := `ln -s /foo /bar`
18a771a7
 	if testEnv.OSType == "windows" {
fdce2a77
 		makeLink = `mklink /D C:\bar C:\foo`
 	}
cc42eeac
 	name := "testbuildaddtosymlinkdest"
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `
c778f4b9
 		FROM busybox
 		RUN sh -c "mkdir /foo"
 		RUN `+makeLink+`
 		ADD foo /bar/
 		RUN sh -c "[ -f /bar/foo ]"
 		RUN sh -c "[ -f /foo/foo ]"`),
56fb4653
 		build.WithFile("foo", "hello"),
c778f4b9
 	))
cc42eeac
 }
03c5c193
 
dc944ea7
 func (s *DockerSuite) TestBuildEscapeWhitespace(c *check.C) {
e8e3dd32
 	name := "testbuildescapewhitespace"
03c5c193
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`
e8e3dd32
   # ESCAPE=\
03c5c193
   FROM busybox
   MAINTAINER "Docker \
 IO <io@\
 docker.com>"
c778f4b9
   `))
03c5c193
 
62a856e9
 	res := inspectField(c, name, "Author")
d942c59b
 	if res != "\"Docker IO <io@docker.com>\"" {
dc944ea7
 		c.Fatalf("Parsed string did not match the escaped string. Got: %q", res)
03c5c193
 	}
 
 }
9189db3a
 
dc944ea7
 func (s *DockerSuite) TestBuildVerifyIntString(c *check.C) {
d942c59b
 	// Verify that strings that look like ints are still passed as strings
 	name := "testbuildstringing"
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`
c778f4b9
 	FROM busybox
 	MAINTAINER 123`))
d942c59b
 
5c295460
 	out, _ := dockerCmd(c, "inspect", name)
d942c59b
 	if !strings.Contains(out, "\"123\"") {
dc944ea7
 		c.Fatalf("Output does not contain the int as a string:\n%s", out)
d942c59b
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildDockerignore(c *check.C) {
9189db3a
 	name := "testbuilddockerignore"
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `
c778f4b9
 		FROM busybox
 		 ADD . /bla
eed648ac
 		RUN sh -c "[[ -f /bla/src/x.go ]]"
 		RUN sh -c "[[ -f /bla/Makefile ]]"
 		RUN sh -c "[[ ! -e /bla/src/_vendor ]]"
 		RUN sh -c "[[ ! -e /bla/.gitignore ]]"
 		RUN sh -c "[[ ! -e /bla/README.md ]]"
 		RUN sh -c "[[ ! -e /bla/dir/foo ]]"
 		RUN sh -c "[[ ! -e /bla/foo ]]"
 		RUN sh -c "[[ ! -e /bla/.git ]]"
 		RUN sh -c "[[ ! -e v.cc ]]"
 		RUN sh -c "[[ ! -e src/v.cc ]]"
c778f4b9
 		RUN sh -c "[[ ! -e src/_vendor/v.cc ]]"`),
56fb4653
 		build.WithFile("Makefile", "all:"),
 		build.WithFile(".git/HEAD", "ref: foo"),
 		build.WithFile("src/x.go", "package main"),
 		build.WithFile("src/_vendor/v.go", "package main"),
 		build.WithFile("src/_vendor/v.cc", "package main"),
 		build.WithFile("src/v.cc", "package main"),
 		build.WithFile("v.cc", "package main"),
 		build.WithFile("dir/foo", ""),
 		build.WithFile(".gitignore", ""),
 		build.WithFile("README.md", "readme"),
 		build.WithFile(".dockerignore", `
6fd8e485
 .git
 pkg
 .gitignore
 src/_vendor
 *.md
eddb14a4
 **/*.cc
c778f4b9
 dir`),
 	))
9189db3a
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildDockerignoreCleanPaths(c *check.C) {
c0f0f5c9
 	name := "testbuilddockerignorecleanpaths"
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `
c0f0f5c9
         FROM busybox
         ADD . /tmp/
c778f4b9
         RUN sh -c "(! ls /tmp/foo) && (! ls /tmp/foo2) && (! ls /tmp/dir1/foo)"`),
56fb4653
 		build.WithFile("foo", "foo"),
 		build.WithFile("foo2", "foo2"),
 		build.WithFile("dir1/foo", "foo in dir1"),
 		build.WithFile(".dockerignore", "./foo\ndir1//foo\n./dir1/../foo2"),
c778f4b9
 	))
c0f0f5c9
 }
 
6fd8e485
 func (s *DockerSuite) TestBuildDockerignoreExceptions(c *check.C) {
 	name := "testbuilddockerignoreexceptions"
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `
c778f4b9
 		FROM busybox
 		ADD . /bla
eed648ac
 		RUN sh -c "[[ -f /bla/src/x.go ]]"
 		RUN sh -c "[[ -f /bla/Makefile ]]"
 		RUN sh -c "[[ ! -e /bla/src/_vendor ]]"
 		RUN sh -c "[[ ! -e /bla/.gitignore ]]"
 		RUN sh -c "[[ ! -e /bla/README.md ]]"
 		RUN sh -c "[[  -e /bla/dir/dir/foo ]]"
 		RUN sh -c "[[ ! -e /bla/dir/foo1 ]]"
 		RUN sh -c "[[ -f /bla/dir/e ]]"
 		RUN sh -c "[[ -f /bla/dir/e-dir/foo ]]"
 		RUN sh -c "[[ ! -e /bla/foo ]]"
 		RUN sh -c "[[ ! -e /bla/.git ]]"
c778f4b9
 		RUN sh -c "[[ -e /bla/dir/a.cc ]]"`),
56fb4653
 		build.WithFile("Makefile", "all:"),
 		build.WithFile(".git/HEAD", "ref: foo"),
 		build.WithFile("src/x.go", "package main"),
 		build.WithFile("src/_vendor/v.go", "package main"),
 		build.WithFile("dir/foo", ""),
 		build.WithFile("dir/foo1", ""),
 		build.WithFile("dir/dir/f1", ""),
 		build.WithFile("dir/dir/foo", ""),
 		build.WithFile("dir/e", ""),
 		build.WithFile("dir/e-dir/foo", ""),
 		build.WithFile(".gitignore", ""),
 		build.WithFile("README.md", "readme"),
 		build.WithFile("dir/a.cc", "hello"),
 		build.WithFile(".dockerignore", `
6fd8e485
 .git
 pkg
 .gitignore
 src/_vendor
 *.md
 dir
 !dir/e*
eddb14a4
 !dir/dir/foo
 **/*.cc
c778f4b9
 !**/*.cc`),
 	))
6fd8e485
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildDockerignoringDockerfile(c *check.C) {
9189db3a
 	name := "testbuilddockerignoredockerfile"
 	dockerfile := `
c778f4b9
 		FROM busybox
6d801a3c
 		ADD . /tmp/
eed648ac
 		RUN sh -c "! ls /tmp/Dockerfile"
6d801a3c
 		RUN ls /tmp/.dockerignore`
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", dockerfile),
 		build.WithFile(".dockerignore", "Dockerfile\n"),
c778f4b9
 	))
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", dockerfile),
 		build.WithFile(".dockerignore", "./Dockerfile\n"),
c778f4b9
 	))
9189db3a
 }
1d4862b7
 
dc944ea7
 func (s *DockerSuite) TestBuildDockerignoringRenamedDockerfile(c *check.C) {
eb3ea3b4
 	name := "testbuilddockerignoredockerfile"
 	dockerfile := `
c778f4b9
 		FROM busybox
eb3ea3b4
 		ADD . /tmp/
 		RUN ls /tmp/Dockerfile
eed648ac
 		RUN sh -c "! ls /tmp/MyDockerfile"
eb3ea3b4
 		RUN ls /tmp/.dockerignore`
56fb4653
 	buildImageSuccessfully(c, name, cli.WithFlags("-f", "MyDockerfile"), build.WithBuildContext(c,
 		build.WithFile("Dockerfile", "Should not use me"),
 		build.WithFile("MyDockerfile", dockerfile),
 		build.WithFile(".dockerignore", "MyDockerfile\n"),
c778f4b9
 	))
56fb4653
 	buildImageSuccessfully(c, name, cli.WithFlags("-f", "MyDockerfile"), build.WithBuildContext(c,
 		build.WithFile("Dockerfile", "Should not use me"),
 		build.WithFile("MyDockerfile", dockerfile),
 		build.WithFile(".dockerignore", "./MyDockerfile\n"),
c778f4b9
 	))
eb3ea3b4
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildDockerignoringDockerignore(c *check.C) {
6d801a3c
 	name := "testbuilddockerignoredockerignore"
 	dockerfile := `
c778f4b9
 		FROM busybox
6d801a3c
 		ADD . /tmp/
eed648ac
 		RUN sh -c "! ls /tmp/.dockerignore"
6d801a3c
 		RUN ls /tmp/Dockerfile`
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", dockerfile),
 		build.WithFile(".dockerignore", ".dockerignore\n"),
c778f4b9
 	))
6d801a3c
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildDockerignoreTouchDockerfile(c *check.C) {
6d801a3c
 	name := "testbuilddockerignoretouchdockerfile"
 	dockerfile := `
         FROM busybox
 		ADD . /tmp/`
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(dockerfile),
 		fakecontext.WithFiles(map[string]string{
 			".dockerignore": "Dockerfile\n",
 		}))
04ef69a1
 	defer ctx.Close()
6d801a3c
 
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id1 := getIDByName(c, name)
6d801a3c
 
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id2 := getIDByName(c, name)
6d801a3c
 	if id1 != id2 {
dc944ea7
 		c.Fatalf("Didn't use the cache - 1")
6d801a3c
 	}
 
 	// Now make sure touching Dockerfile doesn't invalidate the cache
c10f6ef4
 	if err := ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil {
dc944ea7
 		c.Fatalf("Didn't add Dockerfile: %s", err)
6d801a3c
 	}
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id2 = getIDByName(c, name)
6d801a3c
 	if id1 != id2 {
dc944ea7
 		c.Fatalf("Didn't use the cache - 2")
6d801a3c
 	}
 
 	// One more time but just 'touch' it instead of changing the content
c10f6ef4
 	if err := ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil {
dc944ea7
 		c.Fatalf("Didn't add Dockerfile: %s", err)
6d801a3c
 	}
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	id2 = getIDByName(c, name)
6d801a3c
 	if id1 != id2 {
dc944ea7
 		c.Fatalf("Didn't use the cache - 3")
6d801a3c
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildDockerignoringWholeDir(c *check.C) {
7d97a5f4
 	name := "testbuilddockerignorewholedir"
c778f4b9
 
7d97a5f4
 	dockerfile := `
c778f4b9
 		FROM busybox
7d97a5f4
 		COPY . /
eed648ac
 		RUN sh -c "[[ ! -e /.gitignore ]]"
c778f4b9
 		RUN sh -c "[[ ! -e /Makefile ]]"`
82ea6ed2
 
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", dockerfile),
 		build.WithFile(".dockerignore", "*\n"),
 		build.WithFile("Makefile", "all:"),
 		build.WithFile(".gitignore", ""),
c778f4b9
 	))
 }
82ea6ed2
 
c778f4b9
 func (s *DockerSuite) TestBuildDockerignoringOnlyDotfiles(c *check.C) {
 	name := "testbuilddockerignorewholedir"
82ea6ed2
 
c778f4b9
 	dockerfile := `
 		FROM busybox
 		COPY . /
 		RUN sh -c "[[ ! -e /.gitignore ]]"
 		RUN sh -c "[[ -f /Makefile ]]"`
 
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", dockerfile),
 		build.WithFile(".dockerignore", ".*"),
 		build.WithFile("Makefile", "all:"),
 		build.WithFile(".gitignore", ""),
c778f4b9
 	))
7d97a5f4
 }
 
82ea6ed2
 func (s *DockerSuite) TestBuildDockerignoringBadExclusion(c *check.C) {
eddb14a4
 	name := "testbuilddockerignorebadexclusion"
56fb4653
 	buildImage(name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `
c778f4b9
 		FROM busybox
82ea6ed2
 		COPY . /
eed648ac
 		RUN sh -c "[[ ! -e /.gitignore ]]"
c778f4b9
 		RUN sh -c "[[ -f /Makefile ]]"`),
56fb4653
 		build.WithFile("Makefile", "all:"),
 		build.WithFile(".gitignore", ""),
 		build.WithFile(".dockerignore", "!\n"),
c778f4b9
 	)).Assert(c, icmd.Expected{
 		ExitCode: 1,
f47a61c4
 		Err:      "error checking context: 'illegal exclusion pattern: \"!\"",
82ea6ed2
 	})
 }
 
eddb14a4
 func (s *DockerSuite) TestBuildDockerignoringWildTopDir(c *check.C) {
 	dockerfile := `
c778f4b9
 		FROM busybox
eddb14a4
 		COPY . /
eed648ac
 		RUN sh -c "[[ ! -e /.dockerignore ]]"
 		RUN sh -c "[[ ! -e /Dockerfile ]]"
 		RUN sh -c "[[ ! -e /file1 ]]"
 		RUN sh -c "[[ ! -e /dir ]]"`
eddb14a4
 
 	// All of these should result in ignoring all files
 	for _, variant := range []string{"**", "**/", "**/**", "*"} {
56fb4653
 		buildImageSuccessfully(c, "noname", build.WithBuildContext(c,
 			build.WithFile("Dockerfile", dockerfile),
 			build.WithFile("file1", ""),
 			build.WithFile("dir/file1", ""),
 			build.WithFile(".dockerignore", variant),
c778f4b9
 		))
 
 		dockerCmd(c, "rmi", "noname")
eddb14a4
 	}
 }
 
 func (s *DockerSuite) TestBuildDockerignoringWildDirs(c *check.C) {
 	dockerfile := `
         FROM busybox
 		COPY . /
eed648ac
 		#RUN sh -c "[[ -e /.dockerignore ]]"
c77bb28d
 		RUN sh -c "[[ -e /Dockerfile ]]           && \
 		           [[ ! -e /file0 ]]              && \
 		           [[ ! -e /dir1/file0 ]]         && \
 		           [[ ! -e /dir2/file0 ]]         && \
 		           [[ ! -e /file1 ]]              && \
 		           [[ ! -e /dir1/file1 ]]         && \
 		           [[ ! -e /dir1/dir2/file1 ]]    && \
 		           [[ ! -e /dir1/file2 ]]         && \
 		           [[   -e /dir1/dir2/file2 ]]    && \
 		           [[ ! -e /dir1/dir2/file4 ]]    && \
 		           [[ ! -e /dir1/dir2/file5 ]]    && \
 		           [[ ! -e /dir1/dir2/file6 ]]    && \
 		           [[ ! -e /dir1/dir3/file7 ]]    && \
 		           [[ ! -e /dir1/dir3/file8 ]]    && \
 		           [[   -e /dir1/dir3 ]]          && \
 		           [[   -e /dir1/dir4 ]]          && \
 		           [[ ! -e 'dir1/dir5/fileAA' ]]  && \
 		           [[   -e 'dir1/dir5/fileAB' ]]  && \
 		           [[   -e 'dir1/dir5/fileB' ]]"   # "." in pattern means nothing
eddb14a4
 
 		RUN echo all done!`
 
c778f4b9
 	dockerignore := `
eddb14a4
 **/file0
 **/*file1
 **/dir1/file2
 dir1/**/file4
 **/dir2/file5
 **/dir1/dir2/file6
 dir1/dir3/**
 **/dir4/**
 **/file?A
 **/file\?B
 **/dir5/file.
c778f4b9
 `
eddb14a4
 
56fb4653
 	buildImageSuccessfully(c, "noname", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", dockerfile),
 		build.WithFile(".dockerignore", dockerignore),
 		build.WithFile("dir1/file0", ""),
 		build.WithFile("dir1/dir2/file0", ""),
 		build.WithFile("file1", ""),
 		build.WithFile("dir1/file1", ""),
 		build.WithFile("dir1/dir2/file1", ""),
 		build.WithFile("dir1/file2", ""),
 		build.WithFile("dir1/dir2/file2", ""), // remains
 		build.WithFile("dir1/dir2/file4", ""),
 		build.WithFile("dir1/dir2/file5", ""),
 		build.WithFile("dir1/dir2/file6", ""),
 		build.WithFile("dir1/dir3/file7", ""),
 		build.WithFile("dir1/dir3/file8", ""),
 		build.WithFile("dir1/dir4/file9", ""),
 		build.WithFile("dir1/dir5/fileAA", ""),
 		build.WithFile("dir1/dir5/fileAB", ""),
 		build.WithFile("dir1/dir5/fileB", ""),
c778f4b9
 	))
eddb14a4
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildLineBreak(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
1d4862b7
 	name := "testbuildlinebreak"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM  busybox
1d4862b7
 RUN    sh -c 'echo root:testpass \
 	> /tmp/passwd'
 RUN    mkdir -p /var/run/sshd
eed648ac
 RUN    sh -c "[ "$(cat /tmp/passwd)" = "root:testpass" ]"
c778f4b9
 RUN    sh -c "[ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]"`))
1d4862b7
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEOLInLine(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
1d4862b7
 	name := "testbuildeolinline"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM   busybox
1d4862b7
 RUN    sh -c 'echo root:testpass > /tmp/passwd'
 RUN    echo "foo \n bar"; echo "baz"
 RUN    mkdir -p /var/run/sshd
eed648ac
 RUN    sh -c "[ "$(cat /tmp/passwd)" = "root:testpass" ]"
c778f4b9
 RUN    sh -c "[ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]"`))
1d4862b7
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCommentsShebangs(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
1d4862b7
 	name := "testbuildcomments"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
1d4862b7
 # This is an ordinary comment.
 RUN { echo '#!/bin/sh'; echo 'echo hello world'; } > /hello.sh
 RUN [ ! -x /hello.sh ]
 # comment with line break \
 RUN chmod +x /hello.sh
 RUN [ -x /hello.sh ]
 RUN [ "$(cat /hello.sh)" = $'#!/bin/sh\necho hello world' ]
c778f4b9
 RUN [ "$(/hello.sh)" = "hello world" ]`))
1d4862b7
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildUsersAndGroups(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
1d4862b7
 	name := "testbuildusers"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
1d4862b7
 
 # Make sure our defaults work
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)" = '0:0/root:root' ]
 
 # TODO decide if "args.user = strconv.Itoa(syscall.Getuid())" is acceptable behavior for changeUser in sysvinit instead of "return nil" when "USER" isn't specified (so that we get the proper group list even if that is the empty list, even in the default case of not supplying an explicit USER to run as, which implies USER 0)
 USER root
 RUN [ "$(id -G):$(id -Gn)" = '0 10:root wheel' ]
 
 # Setup dockerio user and group
deeb5c95
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd && \
 	echo 'dockerio:x:1001:' >> /etc/group
1d4862b7
 
 # Make sure we can switch to our user and all the information is exactly as we expect it to be
 USER dockerio
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
 
 # Switch back to root and double check that worked exactly as we might expect it to
 USER root
deeb5c95
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '0:0/root:root/0 10:root wheel' ] && \
6e0666e6
         # Add a "supplementary" group for our dockerio user
deeb5c95
 	echo 'supplementary:x:1002:dockerio' >> /etc/group
1d4862b7
 
 # ... and then go verify that we get it like we expect
 USER dockerio
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ]
 USER 1001
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ]
 
 # super test the new "user:group" syntax
 USER dockerio:dockerio
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
 USER 1001:dockerio
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
 USER dockerio:1001
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
 USER 1001:1001
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
 USER dockerio:supplementary
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ]
 USER dockerio:1002
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ]
 USER 1001:supplementary
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ]
 USER 1001:1002
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ]
 
 # make sure unknown uid/gid still works properly
 USER 1042:1043
c778f4b9
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1042:1043/1042:1043/1043:1043' ]`))
1d4862b7
 }
 
8eb0af1a
 // FIXME(vdemeester) rename this test (and probably "merge" it with the one below TestBuildEnvUsage2)
dc944ea7
 func (s *DockerSuite) TestBuildEnvUsage(c *check.C) {
ea3afdad
 	// /docker/world/hello is not owned by the correct user
 	testRequires(c, NotUserNamespace)
f9a3558a
 	testRequires(c, DaemonIsLinux)
1d4862b7
 	name := "testbuildenvusage"
 	dockerfile := `FROM busybox
4e74cd49
 ENV    HOME /root
cb51681a
 ENV    PATH $HOME/bin:$PATH
 ENV    PATH /tmp:$PATH
 RUN    [ "$PATH" = "/tmp:$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ]
1d4862b7
 ENV    FOO /foo/baz
 ENV    BAR /bar
 ENV    BAZ $BAR
 ENV    FOOPATH $PATH:$FOO
 RUN    [ "$BAR" = "$BAZ" ]
 RUN    [ "$FOOPATH" = "$PATH:/foo/baz" ]
c778f4b9
 ENV    FROM hello/docker/world
1d4862b7
 ENV    TO /docker/world/hello
 ADD    $FROM $TO
cb51681a
 RUN    [ "$(cat $TO)" = "hello" ]
ed3bc3b9
 ENV    abc=def
 ENV    ghi=$abc
 RUN    [ "$ghi" = "def" ]
cb51681a
 `
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", dockerfile),
 		build.WithFile("hello/docker/world", "hello"),
c778f4b9
 	))
1d4862b7
 }
 
8eb0af1a
 // FIXME(vdemeester) rename this test (and probably "merge" it with the one above TestBuildEnvUsage)
dc944ea7
 func (s *DockerSuite) TestBuildEnvUsage2(c *check.C) {
ea3afdad
 	// /docker/world/hello is not owned by the correct user
 	testRequires(c, NotUserNamespace)
f9a3558a
 	testRequires(c, DaemonIsLinux)
1314e158
 	name := "testbuildenvusage2"
 	dockerfile := `FROM busybox
74fafa5d
 ENV    abc=def def="hello world"
 RUN    [ "$abc,$def" = "def,hello world" ]
 ENV    def=hello\ world v1=abc v2="hi there" v3='boogie nights' v4="with'quotes too"
 RUN    [ "$def,$v1,$v2,$v3,$v4" = "hello world,abc,hi there,boogie nights,with'quotes too" ]
1314e158
 ENV    abc=zzz FROM=hello/docker/world
 ENV    abc=zzz TO=/docker/world/hello
 ADD    $FROM $TO
74fafa5d
 RUN    [ "$abc,$(cat $TO)" = "zzz,hello" ]
1314e158
 ENV    abc 'yyy'
6d66e3e7
 RUN    [ $abc = 'yyy' ]
1314e158
 ENV    abc=
 RUN    [ "$abc" = "" ]
ed3bc3b9
 
 # use grep to make sure if the builder substitutes \$foo by mistake
 # we don't get a false positive
 ENV    abc=\$foo
 RUN    [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo)
 ENV    abc \$foo
 RUN    [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo)
 
74fafa5d
 ENV    abc=\'foo\' abc2=\"foo\"
 RUN    [ "$abc,$abc2" = "'foo',\"foo\"" ]
ed3bc3b9
 ENV    abc "foo"
6d66e3e7
 RUN    [ "$abc" = "foo" ]
ed3bc3b9
 ENV    abc 'foo'
6d66e3e7
 RUN    [ "$abc" = 'foo' ]
ed3bc3b9
 ENV    abc \'foo\'
6d66e3e7
 RUN    [ "$abc" = "'foo'" ]
ed3bc3b9
 ENV    abc \"foo\"
6d66e3e7
 RUN    [ "$abc" = '"foo"' ]
 
39908fc6
 ENV    abc=ABC
 RUN    [ "$abc" = "ABC" ]
74fafa5d
 ENV    def1=${abc:-DEF} def2=${ccc:-DEF}
 ENV    def3=${ccc:-${def2}xx} def4=${abc:+ALT} def5=${def2:+${abc}:} def6=${ccc:-\$abc:} def7=${ccc:-\${abc}:}
 RUN    [ "$def1,$def2,$def3,$def4,$def5,$def6,$def7" = 'ABC,DEF,DEFxx,ALT,ABC:,$abc:,${abc:}' ]
39908fc6
 ENV    mypath=${mypath:+$mypath:}/home
 ENV    mypath=${mypath:+$mypath:}/away
 RUN    [ "$mypath" = '/home:/away' ]
 
6d66e3e7
 ENV    e1=bar
74fafa5d
 ENV    e2=$e1 e3=$e11 e4=\$e1 e5=\$e11
6d66e3e7
 RUN    [ "$e0,$e1,$e2,$e3,$e4,$e5" = ',bar,bar,,$e1,$e11' ]
 
 ENV    ee1 bar
 ENV    ee2 $ee1
 ENV    ee3 $ee11
 ENV    ee4 \$ee1
 ENV    ee5 \$ee11
 RUN    [ "$ee1,$ee2,$ee3,$ee4,$ee5" = 'bar,bar,,$ee1,$ee11' ]
 
74fafa5d
 ENV    eee1="foo" eee2='foo'
6d66e3e7
 ENV    eee3 "foo"
 ENV    eee4 'foo'
 RUN    [ "$eee1,$eee2,$eee3,$eee4" = 'foo,foo,foo,foo' ]
 
1314e158
 `
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", dockerfile),
 		build.WithFile("hello/docker/world", "hello"),
c778f4b9
 	))
1314e158
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddScript(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
1d4862b7
 	name := "testbuildaddscript"
 	dockerfile := `
 FROM busybox
 ADD test /test
 RUN ["chmod","+x","/test"]
 RUN ["/test"]
 RUN [ "$(cat /testfile)" = 'test!' ]`
db7fded1
 
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", dockerfile),
 		build.WithFile("test", "#!/bin/sh\necho 'test!' > /testfile"),
c778f4b9
 	))
1d4862b7
 }
cfa4999d
 
dc944ea7
 func (s *DockerSuite) TestBuildAddTar(c *check.C) {
ea3afdad
 	// /test/foo is not owned by the correct user
 	testRequires(c, NotUserNamespace)
fc2631b4
 	name := "testbuildaddtar"
cfa4999d
 
56fb4653
 	ctx := func() *fakecontext.Fake {
5d8e80ba
 		dockerfile := `
 FROM busybox
 ADD test.tar /
 RUN cat /test/foo | grep Hi
 ADD test.tar /test.tar
 RUN cat /test.tar/test/foo | grep Hi
 ADD test.tar /unlikely-to-exist
 RUN cat /unlikely-to-exist/test/foo | grep Hi
 ADD test.tar /unlikely-to-exist-trailing-slash/
 RUN cat /unlikely-to-exist-trailing-slash/test/foo | grep Hi
0adcce10
 RUN sh -c "mkdir /existing-directory" #sh -c is needed on Windows to use the correct mkdir
5d8e80ba
 ADD test.tar /existing-directory
 RUN cat /existing-directory/test/foo | grep Hi
 ADD test.tar /existing-directory-trailing-slash/
 RUN cat /existing-directory-trailing-slash/test/foo | grep Hi`
24c00c85
 		tmpDir, err := ioutil.TempDir("", "fake-context")
b616b8a1
 		c.Assert(err, check.IsNil)
24c00c85
 		testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
 		if err != nil {
dc944ea7
 			c.Fatalf("failed to create test.tar archive: %v", err)
cfa4999d
 		}
24c00c85
 		defer testTar.Close()
 
 		tw := tar.NewWriter(testTar)
 
 		if err := tw.WriteHeader(&tar.Header{
 			Name: "test/foo",
 			Size: 2,
 		}); err != nil {
dc944ea7
 			c.Fatalf("failed to write tar file header: %v", err)
24c00c85
 		}
 		if _, err := tw.Write([]byte("Hi")); err != nil {
dc944ea7
 			c.Fatalf("failed to write tar file content: %v", err)
24c00c85
 		}
 		if err := tw.Close(); err != nil {
dc944ea7
 			c.Fatalf("failed to close tar archive: %v", err)
cfa4999d
 		}
 
5d8e80ba
 		if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
dc944ea7
 			c.Fatalf("failed to open destination dockerfile: %v", err)
24c00c85
 		}
56fb4653
 		return fakecontext.New(c, tmpDir)
24c00c85
 	}()
db7fded1
 	defer ctx.Close()
24c00c85
 
56fb4653
 	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
cfa4999d
 }
5b0d4cf2
 
3243e504
 func (s *DockerSuite) TestBuildAddBrokenTar(c *check.C) {
 	name := "testbuildaddbrokentar"
 
56fb4653
 	ctx := func() *fakecontext.Fake {
3243e504
 		dockerfile := `
 FROM busybox
 ADD test.tar /`
 		tmpDir, err := ioutil.TempDir("", "fake-context")
 		c.Assert(err, check.IsNil)
 		testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
 		if err != nil {
 			c.Fatalf("failed to create test.tar archive: %v", err)
 		}
 		defer testTar.Close()
 
 		tw := tar.NewWriter(testTar)
 
 		if err := tw.WriteHeader(&tar.Header{
 			Name: "test/foo",
 			Size: 2,
 		}); err != nil {
 			c.Fatalf("failed to write tar file header: %v", err)
 		}
 		if _, err := tw.Write([]byte("Hi")); err != nil {
 			c.Fatalf("failed to write tar file content: %v", err)
 		}
 		if err := tw.Close(); err != nil {
 			c.Fatalf("failed to close tar archive: %v", err)
 		}
 
 		// Corrupt the tar by removing one byte off the end
 		stat, err := testTar.Stat()
 		if err != nil {
 			c.Fatalf("failed to stat tar archive: %v", err)
 		}
 		if err := testTar.Truncate(stat.Size() - 1); err != nil {
 			c.Fatalf("failed to truncate tar archive: %v", err)
 		}
 
 		if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
 			c.Fatalf("failed to open destination dockerfile: %v", err)
 		}
56fb4653
 		return fakecontext.New(c, tmpDir)
3243e504
 	}()
 	defer ctx.Close()
 
56fb4653
 	buildImage(name, build.WithExternalBuildContext(ctx)).Assert(c, icmd.Expected{
c10f6ef4
 		ExitCode: 1,
 	})
3243e504
 }
 
 func (s *DockerSuite) TestBuildAddNonTar(c *check.C) {
 	name := "testbuildaddnontar"
 
 	// Should not try to extract test.tar
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `
3243e504
 		FROM busybox
 		ADD test.tar /
c778f4b9
 		RUN test -f /test.tar`),
56fb4653
 		build.WithFile("test.tar", "not_a_tar_file"),
c778f4b9
 	))
3243e504
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddTarXz(c *check.C) {
ea3afdad
 	// /test/foo is not owned by the correct user
 	testRequires(c, NotUserNamespace)
f9a3558a
 	testRequires(c, DaemonIsLinux)
e4ba82d5
 	name := "testbuildaddtarxz"
 
56fb4653
 	ctx := func() *fakecontext.Fake {
e4ba82d5
 		dockerfile := `
 			FROM busybox
 			ADD test.tar.xz /
 			RUN cat /test/foo | grep Hi`
 		tmpDir, err := ioutil.TempDir("", "fake-context")
b616b8a1
 		c.Assert(err, check.IsNil)
e4ba82d5
 		testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
 		if err != nil {
dc944ea7
 			c.Fatalf("failed to create test.tar archive: %v", err)
e4ba82d5
 		}
 		defer testTar.Close()
 
 		tw := tar.NewWriter(testTar)
 
 		if err := tw.WriteHeader(&tar.Header{
 			Name: "test/foo",
 			Size: 2,
 		}); err != nil {
dc944ea7
 			c.Fatalf("failed to write tar file header: %v", err)
e4ba82d5
 		}
 		if _, err := tw.Write([]byte("Hi")); err != nil {
dc944ea7
 			c.Fatalf("failed to write tar file content: %v", err)
e4ba82d5
 		}
 		if err := tw.Close(); err != nil {
dc944ea7
 			c.Fatalf("failed to close tar archive: %v", err)
e4ba82d5
 		}
5c295460
 
ecbb0e62
 		icmd.RunCmd(icmd.Cmd{
 			Command: []string{"xz", "-k", "test.tar"},
 			Dir:     tmpDir,
 		}).Assert(c, icmd.Success)
e4ba82d5
 		if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
dc944ea7
 			c.Fatalf("failed to open destination dockerfile: %v", err)
e4ba82d5
 		}
56fb4653
 		return fakecontext.New(c, tmpDir)
e4ba82d5
 	}()
 
 	defer ctx.Close()
 
56fb4653
 	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
e4ba82d5
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddTarXzGz(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
e4ba82d5
 	name := "testbuildaddtarxzgz"
 
56fb4653
 	ctx := func() *fakecontext.Fake {
e4ba82d5
 		dockerfile := `
 			FROM busybox
 			ADD test.tar.xz.gz /
 			RUN ls /test.tar.xz.gz`
 		tmpDir, err := ioutil.TempDir("", "fake-context")
b616b8a1
 		c.Assert(err, check.IsNil)
e4ba82d5
 		testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
 		if err != nil {
dc944ea7
 			c.Fatalf("failed to create test.tar archive: %v", err)
e4ba82d5
 		}
 		defer testTar.Close()
 
 		tw := tar.NewWriter(testTar)
 
 		if err := tw.WriteHeader(&tar.Header{
 			Name: "test/foo",
 			Size: 2,
 		}); err != nil {
dc944ea7
 			c.Fatalf("failed to write tar file header: %v", err)
e4ba82d5
 		}
 		if _, err := tw.Write([]byte("Hi")); err != nil {
dc944ea7
 			c.Fatalf("failed to write tar file content: %v", err)
e4ba82d5
 		}
 		if err := tw.Close(); err != nil {
dc944ea7
 			c.Fatalf("failed to close tar archive: %v", err)
e4ba82d5
 		}
 
ecbb0e62
 		icmd.RunCmd(icmd.Cmd{
 			Command: []string{"xz", "-k", "test.tar"},
 			Dir:     tmpDir,
 		}).Assert(c, icmd.Success)
e4ba82d5
 
ecbb0e62
 		icmd.RunCmd(icmd.Cmd{
 			Command: []string{"gzip", "test.tar.xz"},
 			Dir:     tmpDir,
 		})
e4ba82d5
 		if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
dc944ea7
 			c.Fatalf("failed to open destination dockerfile: %v", err)
e4ba82d5
 		}
56fb4653
 		return fakecontext.New(c, tmpDir)
e4ba82d5
 	}()
 
 	defer ctx.Close()
 
56fb4653
 	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
e4ba82d5
 }
 
7fb7a477
 func (s *DockerSuite) TestBuildFromGit(c *check.C) {
5b0d4cf2
 	name := "testbuildfromgit"
a582d9dc
 	git := fakegit.New(c, "repo", map[string]string{
5b0d4cf2
 		"Dockerfile": `FROM busybox
c778f4b9
 		ADD first /first
 		RUN [ -f /first ]
 		MAINTAINER docker`,
5b0d4cf2
 		"first": "test git data",
44ffb199
 	}, true)
5b0d4cf2
 	defer git.Close()
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithContextPath(git.RepoURL))
c778f4b9
 
62a856e9
 	res := inspectField(c, name, "Author")
5b0d4cf2
 	if res != "docker" {
dc944ea7
 		c.Fatalf("Maintainer should be docker, got %s", res)
5b0d4cf2
 	}
 }
1b6546b8
 
7fb7a477
 func (s *DockerSuite) TestBuildFromGitWithContext(c *check.C) {
49fd83a2
 	name := "testbuildfromgit"
a582d9dc
 	git := fakegit.New(c, "repo", map[string]string{
49fd83a2
 		"docker/Dockerfile": `FROM busybox
 					ADD first /first
 					RUN [ -f /first ]
 					MAINTAINER docker`,
 		"docker/first": "test git data",
 	}, true)
 	defer git.Close()
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithContextPath(fmt.Sprintf("%s#master:docker", git.RepoURL)))
c778f4b9
 
62a856e9
 	res := inspectField(c, name, "Author")
49fd83a2
 	if res != "docker" {
 		c.Fatalf("Maintainer should be docker, got %s", res)
 	}
 }
 
39bcaee4
 func (s *DockerSuite) TestBuildFromGitWithF(c *check.C) {
d8835404
 	name := "testbuildfromgitwithf"
a582d9dc
 	git := fakegit.New(c, "repo", map[string]string{
d8835404
 		"myApp/myDockerfile": `FROM busybox
 					RUN echo hi from Dockerfile`,
 	}, true)
 	defer git.Close()
 
50c4475d
 	buildImage(name, cli.WithFlags("-f", "myApp/myDockerfile"), build.WithContextPath(git.RepoURL)).Assert(c, icmd.Expected{
c778f4b9
 		Out: "hi from Dockerfile",
 	})
d8835404
 }
 
d48bface
 func (s *DockerSuite) TestBuildFromRemoteTarball(c *check.C) {
 	name := "testbuildfromremotetarball"
 
 	buffer := new(bytes.Buffer)
 	tw := tar.NewWriter(buffer)
 	defer tw.Close()
 
 	dockerfile := []byte(`FROM busybox
 					MAINTAINER docker`)
 	if err := tw.WriteHeader(&tar.Header{
 		Name: "Dockerfile",
 		Size: int64(len(dockerfile)),
 	}); err != nil {
 		c.Fatalf("failed to write tar file header: %v", err)
 	}
 	if _, err := tw.Write(dockerfile); err != nil {
 		c.Fatalf("failed to write tar file content: %v", err)
 	}
 	if err := tw.Close(); err != nil {
 		c.Fatalf("failed to close tar archive: %v", err)
 	}
 
56fb4653
 	server := fakestorage.New(c, "", fakecontext.WithBinaryFiles(map[string]*bytes.Buffer{
d48bface
 		"testT.tar": buffer,
56fb4653
 	}))
d48bface
 	defer server.Close()
 
56fb4653
 	cli.BuildCmd(c, name, build.WithContextPath(server.URL()+"/testT.tar"))
d48bface
 
62a856e9
 	res := inspectField(c, name, "Author")
d48bface
 	if res != "docker" {
 		c.Fatalf("Maintainer should be docker, got %s", res)
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCleanupCmdOnEntrypoint(c *check.C) {
1b6546b8
 	name := "testbuildcmdcleanuponentrypoint"
c778f4b9
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
c778f4b9
 		CMD ["test"]
 		ENTRYPOINT ["echo"]`))
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`FROM %s
c778f4b9
 		ENTRYPOINT ["cat"]`, name)))
 
62a856e9
 	res := inspectField(c, name, "Config.Cmd")
53b0d626
 	if res != "[]" {
231d362d
 		c.Fatalf("Cmd %s, expected nil", res)
1b6546b8
 	}
62a856e9
 	res = inspectField(c, name, "Config.Entrypoint")
53b0d626
 	if expected := "[cat]"; res != expected {
dc944ea7
 		c.Fatalf("Entrypoint %s, expected %s", res, expected)
1b6546b8
 	}
 }
ac107995
 
dc944ea7
 func (s *DockerSuite) TestBuildClearCmd(c *check.C) {
ac107995
 	name := "testbuildclearcmd"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
ac107995
    ENTRYPOINT ["/bin/bash"]
c778f4b9
    CMD []`))
 
62a856e9
 	res := inspectFieldJSON(c, name, "Config.Cmd")
ac107995
 	if res != "[]" {
dc944ea7
 		c.Fatalf("Cmd %s, expected %s", res, "[]")
ac107995
 	}
 }
d1613e1d
 
dc944ea7
 func (s *DockerSuite) TestBuildEmptyCmd(c *check.C) {
b52c3ec4
 	// Skip on Windows. Base image on Windows has a CMD set in the image.
 	testRequires(c, DaemonIsLinux)
45da1274
 
d1613e1d
 	name := "testbuildemptycmd"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile("FROM "+minimalBaseImage()+"\nMAINTAINER quux\n"))
c778f4b9
 
62a856e9
 	res := inspectFieldJSON(c, name, "Config.Cmd")
d1613e1d
 	if res != "null" {
dc944ea7
 		c.Fatalf("Cmd %s, expected %s", res, "null")
d1613e1d
 	}
 }
8edacc67
 
dc944ea7
 func (s *DockerSuite) TestBuildOnBuildOutput(c *check.C) {
8edacc67
 	name := "testbuildonbuildparent"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nONBUILD RUN echo foo\n"))
8edacc67
 
50c4475d
 	buildImage(name, build.WithDockerfile("FROM "+name+"\nMAINTAINER quux\n")).Assert(c, icmd.Expected{
c778f4b9
 		Out: "# Executing 1 build trigger",
 	})
8edacc67
 }
8833d800
 
c778f4b9
 // FIXME(vdemeester) should be a unit test
dc944ea7
 func (s *DockerSuite) TestBuildInvalidTag(c *check.C) {
7c35a241
 	name := "abcd:" + testutil.GenerateRandomAlphaOnlyString(200)
50c4475d
 	buildImage(name, build.WithDockerfile("FROM "+minimalBaseImage()+"\nMAINTAINER quux\n")).Assert(c, icmd.Expected{
c778f4b9
 		ExitCode: 125,
0421f517
 		Err:      "invalid reference format",
c778f4b9
 	})
8833d800
 }
9f142bf9
 
dc944ea7
 func (s *DockerSuite) TestBuildCmdShDashC(c *check.C) {
9f142bf9
 	name := "testbuildcmdshc"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nCMD echo cmd\n"))
9f142bf9
 
62a856e9
 	res := inspectFieldJSON(c, name, "Config.Cmd")
9f142bf9
 	expected := `["/bin/sh","-c","echo cmd"]`
18a771a7
 	if testEnv.OSType == "windows" {
0adcce10
 		expected = `["cmd","/S","/C","echo cmd"]`
 	}
9f142bf9
 	if res != expected {
dc944ea7
 		c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res)
9f142bf9
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCmdSpaces(c *check.C) {
88905793
 	// Test to make sure that when we strcat arrays we take into account
 	// the arg separator to make sure ["echo","hi"] and ["echo hi"] don't
 	// look the same
 	name := "testbuildcmdspaces"
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nCMD [\"echo hi\"]\n"))
c10f6ef4
 	id1 := getIDByName(c, name)
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nCMD [\"echo\", \"hi\"]\n"))
c10f6ef4
 	id2 := getIDByName(c, name)
88905793
 
 	if id1 == id2 {
dc944ea7
 		c.Fatal("Should not have resulted in the same CMD")
88905793
 	}
 
 	// Now do the same with ENTRYPOINT
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nENTRYPOINT [\"echo hi\"]\n"))
c10f6ef4
 	id1 = getIDByName(c, name)
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nENTRYPOINT [\"echo\", \"hi\"]\n"))
c10f6ef4
 	id2 = getIDByName(c, name)
88905793
 
 	if id1 == id2 {
dc944ea7
 		c.Fatal("Should not have resulted in the same ENTRYPOINT")
88905793
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCmdJSONNoShDashC(c *check.C) {
9f142bf9
 	name := "testbuildcmdjson"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nCMD [\"echo\", \"cmd\"]"))
9f142bf9
 
62a856e9
 	res := inspectFieldJSON(c, name, "Config.Cmd")
9f142bf9
 	expected := `["echo","cmd"]`
 	if res != expected {
dc944ea7
 		c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res)
9f142bf9
 	}
 }
9fe1dd31
 
39bcaee4
 func (s *DockerSuite) TestBuildEntrypointCanBeOverriddenByChild(c *check.C) {
50c4475d
 	buildImageSuccessfully(c, "parent", build.WithDockerfile(`
50fa9dff
     FROM busybox
     ENTRYPOINT exit 130
c778f4b9
     `))
50fa9dff
 
c778f4b9
 	icmd.RunCommand(dockerBinary, "run", "parent").Assert(c, icmd.Expected{
 		ExitCode: 130,
 	})
50fa9dff
 
50c4475d
 	buildImageSuccessfully(c, "child", build.WithDockerfile(`
50fa9dff
     FROM parent
     ENTRYPOINT exit 5
c778f4b9
     `))
50fa9dff
 
c778f4b9
 	icmd.RunCommand(dockerBinary, "run", "child").Assert(c, icmd.Expected{
 		ExitCode: 5,
 	})
50fa9dff
 }
 
39bcaee4
 func (s *DockerSuite) TestBuildEntrypointCanBeOverriddenByChildInspect(c *check.C) {
50fa9dff
 	var (
 		name     = "testbuildepinherit"
 		name2    = "testbuildepinherit2"
 		expected = `["/bin/sh","-c","echo quux"]`
 	)
 
18a771a7
 	if testEnv.OSType == "windows" {
0adcce10
 		expected = `["cmd","/S","/C","echo quux"]`
 	}
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nENTRYPOINT /foo/bar"))
 	buildImageSuccessfully(c, name2, build.WithDockerfile(fmt.Sprintf("FROM %s\nENTRYPOINT echo quux", name)))
50fa9dff
 
62a856e9
 	res := inspectFieldJSON(c, name2, "Config.Entrypoint")
50fa9dff
 	if res != expected {
dc944ea7
 		c.Fatalf("Expected value %s not in Config.Entrypoint: %s", expected, res)
50fa9dff
 	}
 
c778f4b9
 	icmd.RunCommand(dockerBinary, "run", name2).Assert(c, icmd.Expected{
 		Out: "quux",
 	})
50fa9dff
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildRunShEntrypoint(c *check.C) {
50fa9dff
 	name := "testbuildentrypoint"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
c778f4b9
                                 ENTRYPOINT echo`))
5c295460
 	dockerCmd(c, "run", "--rm", name)
50fa9dff
 }
24189b2c
 
dc944ea7
 func (s *DockerSuite) TestBuildExoticShellInterpolation(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
24189b2c
 	name := "testbuildexoticshellinterpolation"
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`
24189b2c
 		FROM busybox
f3680e74
 
24189b2c
 		ENV SOME_VAR a.b.c
 
 		RUN [ "$SOME_VAR"       = 'a.b.c' ]
 		RUN [ "${SOME_VAR}"     = 'a.b.c' ]
 		RUN [ "${SOME_VAR%.*}"  = 'a.b'   ]
 		RUN [ "${SOME_VAR%%.*}" = 'a'     ]
 		RUN [ "${SOME_VAR#*.}"  = 'b.c'   ]
 		RUN [ "${SOME_VAR##*.}" = 'c'     ]
 		RUN [ "${SOME_VAR/c/d}" = 'a.b.d' ]
 		RUN [ "${#SOME_VAR}"    = '5'     ]
 
 		RUN [ "${SOME_UNSET_VAR:-$SOME_VAR}" = 'a.b.c' ]
 		RUN [ "${SOME_VAR:+Version: ${SOME_VAR}}" = 'Version: a.b.c' ]
 		RUN [ "${SOME_UNSET_VAR:+${SOME_VAR}}" = '' ]
 		RUN [ "${SOME_UNSET_VAR:-${SOME_VAR:-d.e.f}}" = 'a.b.c' ]
c778f4b9
 	`))
24189b2c
 }
9edf9678
 
dc944ea7
 func (s *DockerSuite) TestBuildVerifySingleQuoteFails(c *check.C) {
9edf9678
 	// This testcase is supposed to generate an error because the
 	// JSON array we're passing in on the CMD uses single quotes instead
 	// of double quotes (per the JSON spec). This means we interpret it
927b334e
 	// as a "string" instead of "JSON array" and pass it on to "sh -c" and
9edf9678
 	// it should barf on it.
 	name := "testbuildsinglequotefails"
c778f4b9
 	expectedExitCode := 2
18a771a7
 	if testEnv.OSType == "windows" {
c778f4b9
 		expectedExitCode = 127
5c295460
 	}
9edf9678
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
c778f4b9
 		CMD [ '/bin/sh', '-c', 'echo hi' ]`))
9edf9678
 
c778f4b9
 	icmd.RunCommand(dockerBinary, "run", "--rm", name).Assert(c, icmd.Expected{
 		ExitCode: expectedExitCode,
 	})
9edf9678
 }
6f09d064
 
dc944ea7
 func (s *DockerSuite) TestBuildVerboseOut(c *check.C) {
6f09d064
 	name := "testbuildverboseout"
0adcce10
 	expected := "\n123\n"
 
18a771a7
 	if testEnv.OSType == "windows" {
0adcce10
 		expected = "\n123\r\n"
 	}
6f09d064
 
50c4475d
 	buildImage(name, build.WithDockerfile(`FROM busybox
c778f4b9
 RUN echo 123`)).Assert(c, icmd.Expected{
 		Out: expected,
 	})
6f09d064
 }
c980fe09
 
dc944ea7
 func (s *DockerSuite) TestBuildWithTabs(c *check.C) {
c980fe09
 	name := "testbuildwithtabs"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nRUN echo\tone\t\ttwo"))
62a856e9
 	res := inspectFieldJSON(c, name, "ContainerConfig.Cmd")
14236945
 	expected1 := `["/bin/sh","-c","echo\tone\t\ttwo"]`
 	expected2 := `["/bin/sh","-c","echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates
18a771a7
 	if testEnv.OSType == "windows" {
0adcce10
 		expected1 = `["cmd","/S","/C","echo\tone\t\ttwo"]`
 		expected2 = `["cmd","/S","/C","echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates
 	}
14236945
 	if res != expected1 && res != expected2 {
dc944ea7
 		c.Fatalf("Missing tabs.\nGot: %s\nExp: %s or %s", res, expected1, expected2)
c980fe09
 	}
 }
5c91bb93
 
dc944ea7
 func (s *DockerSuite) TestBuildLabels(c *check.C) {
cdfdfbfb
 	name := "testbuildlabel"
 	expected := `{"License":"GPL","Vendor":"Acme"}`
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
cdfdfbfb
 		LABEL Vendor=Acme
c778f4b9
                 LABEL License GPL`))
62a856e9
 	res := inspectFieldJSON(c, name, "Config.Labels")
cdfdfbfb
 	if res != expected {
dc944ea7
 		c.Fatalf("Labels %s, expected %s", res, expected)
cdfdfbfb
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildLabelsCache(c *check.C) {
97c573bf
 	name := "testbuildlabelcache"
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
c778f4b9
 		LABEL Vendor=Acme`))
c10f6ef4
 	id1 := getIDByName(c, name)
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
c778f4b9
 		LABEL Vendor=Acme`))
c10f6ef4
 	id2 := getIDByName(c, name)
c778f4b9
 	if id1 != id2 {
c10f6ef4
 		c.Fatalf("Build 2 should have worked & used cache(%s,%s)", id1, id2)
97c573bf
 	}
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
c778f4b9
 		LABEL Vendor=Acme1`))
c10f6ef4
 	id2 = getIDByName(c, name)
c778f4b9
 	if id1 == id2 {
c10f6ef4
 		c.Fatalf("Build 3 should have worked & NOT used cache(%s,%s)", id1, id2)
97c573bf
 	}
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
c778f4b9
 		LABEL Vendor Acme`))
c10f6ef4
 	id2 = getIDByName(c, name)
c778f4b9
 	if id1 != id2 {
c10f6ef4
 		c.Fatalf("Build 4 should have worked & used cache(%s,%s)", id1, id2)
b4beb063
 	}
 
 	// Now make sure the cache isn't used by mistake
50c4475d
 	buildImageSuccessfully(c, name, build.WithoutCache, build.WithDockerfile(`FROM busybox
c778f4b9
        LABEL f1=b1 f2=b2`))
b4beb063
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
c778f4b9
        LABEL f1=b1 f2=b2`))
c10f6ef4
 	id2 = getIDByName(c, name)
c778f4b9
 	if id1 == id2 {
c10f6ef4
 		c.Fatalf("Build 6 should have worked & NOT used the cache(%s,%s)", id1, id2)
97c573bf
 	}
 
 }
 
60b4db7e
 func (s *DockerSuite) TestBuildNotVerboseSuccess(c *check.C) {
 	// This test makes sure that -q works correctly when build is successful:
 	// stdout has only the image ID (long image ID) and stderr is empty.
 	outRegexp := regexp.MustCompile("^(sha256:|)[a-z0-9]{64}\\n$")
50c4475d
 	buildFlags := cli.WithFlags("-q")
60b4db7e
 
 	tt := []struct {
 		Name      string
c778f4b9
 		BuildFunc func(string) *icmd.Result
60b4db7e
 	}{
 		{
 			Name: "quiet_build_stdin_success",
c778f4b9
 			BuildFunc: func(name string) *icmd.Result {
50c4475d
 				return buildImage(name, buildFlags, build.WithDockerfile("FROM busybox"))
60b4db7e
 			},
 		},
 		{
 			Name: "quiet_build_ctx_success",
c778f4b9
 			BuildFunc: func(name string) *icmd.Result {
56fb4653
 				return buildImage(name, buildFlags, build.WithBuildContext(c,
 					build.WithFile("Dockerfile", "FROM busybox"),
 					build.WithFile("quiet_build_success_fctx", "test"),
c778f4b9
 				))
60b4db7e
 			},
 		},
 		{
 			Name: "quiet_build_git_success",
c778f4b9
 			BuildFunc: func(name string) *icmd.Result {
a582d9dc
 				git := fakegit.New(c, "repo", map[string]string{
60b4db7e
 					"Dockerfile": "FROM busybox",
 				}, true)
50c4475d
 				return buildImage(name, buildFlags, build.WithContextPath(git.RepoURL))
60b4db7e
 			},
 		},
 	}
 
 	for _, te := range tt {
c778f4b9
 		result := te.BuildFunc(te.Name)
 		result.Assert(c, icmd.Success)
 		if outRegexp.Find([]byte(result.Stdout())) == nil {
 			c.Fatalf("Test %s expected stdout to match the [%v] regexp, but it is [%v]", te.Name, outRegexp, result.Stdout())
60b4db7e
 		}
a9b3c1d7
 
c778f4b9
 		if result.Stderr() != "" {
 			c.Fatalf("Test %s expected stderr to be empty, but it is [%#v]", te.Name, result.Stderr())
60b4db7e
 		}
 	}
 
 }
 
9ab0aa43
 func (s *DockerSuite) TestBuildNotVerboseFailureWithNonExistImage(c *check.C) {
 	// This test makes sure that -q works correctly when build fails by
 	// comparing between the stderr output in quiet mode and in stdout
 	// and stderr output in verbose mode
 	testRequires(c, Network)
 	testName := "quiet_build_not_exists_image"
c778f4b9
 	dockerfile := "FROM busybox11"
50c4475d
 	quietResult := buildImage(testName, cli.WithFlags("-q"), build.WithDockerfile(dockerfile))
c778f4b9
 	quietResult.Assert(c, icmd.Expected{
 		ExitCode: 1,
 	})
50c4475d
 	result := buildImage(testName, build.WithDockerfile(dockerfile))
c778f4b9
 	result.Assert(c, icmd.Expected{
 		ExitCode: 1,
 	})
 	if quietResult.Stderr() != result.Combined() {
 		c.Fatal(fmt.Errorf("Test[%s] expected that quiet stderr and verbose stdout are equal; quiet [%v], verbose [%v]", testName, quietResult.Stderr(), result.Combined()))
9ab0aa43
 	}
 }
 
60b4db7e
 func (s *DockerSuite) TestBuildNotVerboseFailure(c *check.C) {
 	// This test makes sure that -q works correctly when build fails by
 	// comparing between the stderr output in quiet mode and in stdout
 	// and stderr output in verbose mode
c778f4b9
 	testCases := []struct {
 		testName   string
 		dockerfile string
60b4db7e
 	}{
 		{"quiet_build_no_from_at_the_beginning", "RUN whoami"},
 		{"quiet_build_unknown_instr", "FROMD busybox"},
 	}
 
c778f4b9
 	for _, tc := range testCases {
50c4475d
 		quietResult := buildImage(tc.testName, cli.WithFlags("-q"), build.WithDockerfile(tc.dockerfile))
c778f4b9
 		quietResult.Assert(c, icmd.Expected{
 			ExitCode: 1,
 		})
50c4475d
 		result := buildImage(tc.testName, build.WithDockerfile(tc.dockerfile))
c778f4b9
 		result.Assert(c, icmd.Expected{
 			ExitCode: 1,
 		})
 		if quietResult.Stderr() != result.Combined() {
 			c.Fatal(fmt.Errorf("Test[%s] expected that quiet stderr and verbose stdout are equal; quiet [%v], verbose [%v]", tc.testName, quietResult.Stderr(), result.Combined()))
60b4db7e
 		}
 	}
 }
 
 func (s *DockerSuite) TestBuildNotVerboseFailureRemote(c *check.C) {
 	// This test ensures that when given a wrong URL, stderr in quiet mode and
60f447b6
 	// stderr in verbose mode are identical.
 	// TODO(vdemeester) with cobra, stdout has a carriage return too much so this test should not check stdout
 	URL := "http://something.invalid"
c778f4b9
 	name := "quiet_build_wrong_remote"
50c4475d
 	quietResult := buildImage(name, cli.WithFlags("-q"), build.WithContextPath(URL))
c778f4b9
 	quietResult.Assert(c, icmd.Expected{
 		ExitCode: 1,
 	})
50c4475d
 	result := buildImage(name, build.WithContextPath(URL))
c778f4b9
 	result.Assert(c, icmd.Expected{
 		ExitCode: 1,
 	})
3676bd85
 
 	// An error message should contain name server IP and port, like this:
 	//  "dial tcp: lookup something.invalid on 172.29.128.11:53: no such host"
 	// The IP:port need to be removed in order to not trigger a test failur
 	// when more than one nameserver is configured.
 	// While at it, also strip excessive newlines.
 	normalize := func(msg string) string {
 		return strings.TrimSpace(regexp.MustCompile("[1-9][0-9.]+:[0-9]+").ReplaceAllLiteralString(msg, "<ip:port>"))
 	}
 
 	if normalize(quietResult.Stderr()) != normalize(result.Combined()) {
c778f4b9
 		c.Fatal(fmt.Errorf("Test[%s] expected that quiet stderr and verbose stdout are equal; quiet [%v], verbose [%v]", name, quietResult.Stderr(), result.Combined()))
60b4db7e
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildStderr(c *check.C) {
5c91bb93
 	// This test just makes sure that no non-error output goes
 	// to stderr
 	name := "testbuildstderr"
50c4475d
 	result := buildImage(name, build.WithDockerfile("FROM busybox\nRUN echo one"))
c778f4b9
 	result.Assert(c, icmd.Success)
4a8b3cad
 
d45c652e
 	// Windows to non-Windows should have a security warning
18a771a7
 	if runtime.GOOS == "windows" && testEnv.OSType != "windows" && !strings.Contains(result.Stdout(), "SECURITY WARNING:") {
c778f4b9
 		c.Fatalf("Stdout contains unexpected output: %q", result.Stdout())
d45c652e
 	}
 
 	// Stderr should always be empty
c778f4b9
 	if result.Stderr() != "" {
 		c.Fatalf("Stderr should have been empty, instead it's: %q", result.Stderr())
5c91bb93
 	}
 }
cfc24769
 
dc944ea7
 func (s *DockerSuite) TestBuildChownSingleFile(c *check.C) {
c778f4b9
 	testRequires(c, UnixCli, DaemonIsLinux) // test uses chown: not available on windows
492a58f0
 
cfc24769
 	name := "testbuildchownsinglefile"
 
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(`
cfc24769
 FROM busybox
 COPY test /
 RUN ls -l /test
 RUN [ $(ls -l /test | awk '{print $3":"$4}') = 'root:root' ]
56fb4653
 `),
 		fakecontext.WithFiles(map[string]string{
 			"test": "test",
 		}))
cfc24769
 	defer ctx.Close()
 
 	if err := os.Chown(filepath.Join(ctx.Dir, "test"), 4242, 4242); err != nil {
dc944ea7
 		c.Fatal(err)
cfc24769
 	}
 
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
cfc24769
 }
0e71a48d
 
dc944ea7
 func (s *DockerSuite) TestBuildSymlinkBreakout(c *check.C) {
0e71a48d
 	name := "testbuildsymlinkbreakout"
 	tmpdir, err := ioutil.TempDir("", name)
b616b8a1
 	c.Assert(err, check.IsNil)
0e71a48d
 	defer os.RemoveAll(tmpdir)
 	ctx := filepath.Join(tmpdir, "context")
 	if err := os.MkdirAll(ctx, 0755); err != nil {
dc944ea7
 		c.Fatal(err)
0e71a48d
 	}
 	if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte(`
 	from busybox
 	add symlink.tar /
 	add inject /symlink/
 	`), 0644); err != nil {
dc944ea7
 		c.Fatal(err)
0e71a48d
 	}
 	inject := filepath.Join(ctx, "inject")
 	if err := ioutil.WriteFile(inject, nil, 0644); err != nil {
dc944ea7
 		c.Fatal(err)
0e71a48d
 	}
 	f, err := os.Create(filepath.Join(ctx, "symlink.tar"))
 	if err != nil {
dc944ea7
 		c.Fatal(err)
0e71a48d
 	}
 	w := tar.NewWriter(f)
 	w.WriteHeader(&tar.Header{
 		Name:     "symlink2",
 		Typeflag: tar.TypeSymlink,
 		Linkname: "/../../../../../../../../../../../../../../",
 		Uid:      os.Getuid(),
 		Gid:      os.Getgid(),
 	})
 	w.WriteHeader(&tar.Header{
 		Name:     "symlink",
 		Typeflag: tar.TypeSymlink,
 		Linkname: filepath.Join("symlink2", tmpdir),
 		Uid:      os.Getuid(),
 		Gid:      os.Getgid(),
 	})
 	w.Close()
 	f.Close()
c10f6ef4
 
56fb4653
 	buildImageSuccessfully(c, name, build.WithoutCache, build.WithExternalBuildContext(fakecontext.New(c, ctx)))
0e71a48d
 	if _, err := os.Lstat(filepath.Join(tmpdir, "inject")); err == nil {
dc944ea7
 		c.Fatal("symlink breakout - inject")
0e71a48d
 	} else if !os.IsNotExist(err) {
dc944ea7
 		c.Fatalf("unexpected error: %v", err)
0e71a48d
 	}
 }
af202195
 
dc944ea7
 func (s *DockerSuite) TestBuildXZHost(c *check.C) {
ea3afdad
 	// /usr/local/sbin/xz gets permission denied for the user
 	testRequires(c, NotUserNamespace)
f9a3558a
 	testRequires(c, DaemonIsLinux)
af202195
 	name := "testbuildxzhost"
 
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `
af202195
 FROM busybox
 ADD xz /usr/local/sbin/
 RUN chmod 755 /usr/local/sbin/xz
 ADD test.xz /
c778f4b9
 RUN [ ! -e /injected ]`),
56fb4653
 		build.WithFile("test.xz", "\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00"+"\x21\x01\x16\x00\x00\x00\x74\x2f\xe5\xa3\x01\x00\x3f\xfd"+"\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00\x21"),
 		build.WithFile("xz", "#!/bin/sh\ntouch /injected"),
c778f4b9
 	))
af202195
 }
4856ec07
 
dc944ea7
 func (s *DockerSuite) TestBuildVolumesRetainContents(c *check.C) {
ea3afdad
 	// /foo/file gets permission denied for the user
 	testRequires(c, NotUserNamespace)
0adcce10
 	testRequires(c, DaemonIsLinux) // TODO Windows: Issue #20127
4856ec07
 	var (
 		name     = "testbuildvolumescontent"
 		expected = "some text"
0adcce10
 		volName  = "/foo"
4856ec07
 	)
0adcce10
 
18a771a7
 	if testEnv.OSType == "windows" {
0adcce10
 		volName = "C:/foo"
 	}
 
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `
4856ec07
 FROM busybox
 COPY content /foo/file
0adcce10
 VOLUME `+volName+`
c778f4b9
 CMD cat /foo/file`),
56fb4653
 		build.WithFile("content", expected),
c778f4b9
 	))
4856ec07
 
5c295460
 	out, _ := dockerCmd(c, "run", "--rm", name)
4856ec07
 	if out != expected {
dc944ea7
 		c.Fatalf("expected file contents for /foo/file to be %q but received %q", expected, out)
4856ec07
 	}
 
 }
eb3ea3b4
 
8eb0af1a
 // FIXME(vdemeester) part of this should be unit test, other part should be clearer
dc944ea7
 func (s *DockerSuite) TestBuildRenamedDockerfile(c *check.C) {
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithFiles(map[string]string{
 		"Dockerfile":       "FROM busybox\nRUN echo from Dockerfile",
 		"files/Dockerfile": "FROM busybox\nRUN echo from files/Dockerfile",
 		"files/dFile":      "FROM busybox\nRUN echo from files/dFile",
 		"dFile":            "FROM busybox\nRUN echo from dFile",
 		"files/dFile2":     "FROM busybox\nRUN echo from files/dFile2",
 	}))
04ef69a1
 	defer ctx.Close()
eb3ea3b4
 
eeaa6c96
 	cli.Docker(cli.Args("build", "-t", "test1", "."), cli.InDir(ctx.Dir)).Assert(c, icmd.Expected{
 		Out: "from Dockerfile",
 	})
eb3ea3b4
 
eeaa6c96
 	cli.Docker(cli.Args("build", "-f", filepath.Join("files", "Dockerfile"), "-t", "test2", "."), cli.InDir(ctx.Dir)).Assert(c, icmd.Expected{
 		Out: "from files/Dockerfile",
 	})
eb3ea3b4
 
eeaa6c96
 	cli.Docker(cli.Args("build", fmt.Sprintf("--file=%s", filepath.Join("files", "dFile")), "-t", "test3", "."), cli.InDir(ctx.Dir)).Assert(c, icmd.Expected{
 		Out: "from files/dFile",
 	})
eb3ea3b4
 
eeaa6c96
 	cli.Docker(cli.Args("build", "--file=dFile", "-t", "test4", "."), cli.InDir(ctx.Dir)).Assert(c, icmd.Expected{
 		Out: "from dFile",
 	})
eb3ea3b4
 
51e721ab
 	dirWithNoDockerfile, err := ioutil.TempDir(os.TempDir(), "test5")
 	c.Assert(err, check.IsNil)
967d85a2
 	nonDockerfileFile := filepath.Join(dirWithNoDockerfile, "notDockerfile")
 	if _, err = os.Create(nonDockerfileFile); err != nil {
dc944ea7
 		c.Fatal(err)
967d85a2
 	}
eeaa6c96
 	cli.Docker(cli.Args("build", fmt.Sprintf("--file=%s", nonDockerfileFile), "-t", "test5", "."), cli.InDir(ctx.Dir)).Assert(c, icmd.Expected{
 		ExitCode: 1,
f47a61c4
 		Err:      fmt.Sprintf("unable to prepare context: the Dockerfile (%s) must be within the build context", nonDockerfileFile),
eeaa6c96
 	})
eb3ea3b4
 
eeaa6c96
 	cli.Docker(cli.Args("build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test6", ".."), cli.InDir(filepath.Join(ctx.Dir, "files"))).Assert(c, icmd.Expected{
 		Out: "from Dockerfile",
 	})
eb3ea3b4
 
eeaa6c96
 	cli.Docker(cli.Args("build", "-f", filepath.Join(ctx.Dir, "files", "Dockerfile"), "-t", "test7", ".."), cli.InDir(filepath.Join(ctx.Dir, "files"))).Assert(c, icmd.Expected{
 		Out: "from files/Dockerfile",
 	})
eb3ea3b4
 
eeaa6c96
 	cli.Docker(cli.Args("build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test8", "."), cli.InDir(filepath.Join(ctx.Dir, "files"))).Assert(c, icmd.Expected{
 		ExitCode: 1,
 		Err:      "must be within the build context",
 	})
eb3ea3b4
 
c42d2625
 	tmpDir := os.TempDir()
eeaa6c96
 	cli.Docker(cli.Args("build", "-t", "test9", ctx.Dir), cli.InDir(tmpDir)).Assert(c, icmd.Expected{
 		Out: "from Dockerfile",
 	})
eb3ea3b4
 
eeaa6c96
 	cli.Docker(cli.Args("build", "-f", "dFile2", "-t", "test10", "."), cli.InDir(filepath.Join(ctx.Dir, "files"))).Assert(c, icmd.Expected{
 		Out: "from files/dFile2",
 	})
eb3ea3b4
 }
568f86eb
 
dc944ea7
 func (s *DockerSuite) TestBuildFromMixedcaseDockerfile(c *check.C) {
 	testRequires(c, UnixCli) // Dockerfile overwrites dockerfile on windows
f9a3558a
 	testRequires(c, DaemonIsLinux)
15924f23
 
c778f4b9
 	// If Dockerfile is not present, use dockerfile
56fb4653
 	buildImage("test1", build.WithBuildContext(c,
 		build.WithFile("dockerfile", `FROM busybox
c778f4b9
 	RUN echo from dockerfile`),
 	)).Assert(c, icmd.Expected{
 		Out: "from dockerfile",
 	})
15924f23
 
c778f4b9
 	// Prefer Dockerfile in place of dockerfile
56fb4653
 	buildImage("test1", build.WithBuildContext(c,
 		build.WithFile("dockerfile", `FROM busybox
c778f4b9
 	RUN echo from dockerfile`),
56fb4653
 		build.WithFile("Dockerfile", `FROM busybox
c778f4b9
 	RUN echo from Dockerfile`),
 	)).Assert(c, icmd.Expected{
 		Out: "from Dockerfile",
 	})
15924f23
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildFromURLWithF(c *check.C) {
56fb4653
 	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{"baz": `FROM busybox
15924f23
 RUN echo from baz
 COPY * /tmp/
56fb4653
 RUN find /tmp/`}))
15924f23
 	defer server.Close()
 
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(`FROM busybox
 	RUN echo from Dockerfile`))
04ef69a1
 	defer ctx.Close()
15924f23
 
 	// Make sure that -f is ignored and that we don't use the Dockerfile
 	// that's in the current dir
56fb4653
 	result := cli.BuildCmd(c, "test1", cli.WithFlags("-f", "baz", server.URL()+"/baz"), func(cmd *icmd.Cmd) func() {
c778f4b9
 		cmd.Dir = ctx.Dir
 		return nil
 	})
15924f23
 
c778f4b9
 	if !strings.Contains(result.Combined(), "from baz") ||
 		strings.Contains(result.Combined(), "/tmp/baz") ||
 		!strings.Contains(result.Combined(), "/tmp/Dockerfile") {
 		c.Fatalf("Missing proper output: %s", result.Combined())
15924f23
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildFromStdinWithF(c *check.C) {
0adcce10
 	testRequires(c, DaemonIsLinux) // TODO Windows: This test is flaky; no idea why
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(`FROM busybox
 RUN echo "from Dockerfile"`))
04ef69a1
 	defer ctx.Close()
15924f23
 
 	// Make sure that -f is ignored and that we don't use the Dockerfile
 	// that's in the current dir
56fb4653
 	result := cli.BuildCmd(c, "test1", cli.WithFlags("-f", "baz", "-"), func(cmd *icmd.Cmd) func() {
c778f4b9
 		cmd.Dir = ctx.Dir
 		cmd.Stdin = strings.NewReader(`FROM busybox
0adcce10
 RUN echo "from baz"
15924f23
 COPY * /tmp/
0adcce10
 RUN sh -c "find /tmp/" # sh -c is needed on Windows to use the correct find`)
c778f4b9
 		return nil
 	})
15924f23
 
c778f4b9
 	if !strings.Contains(result.Combined(), "from baz") ||
 		strings.Contains(result.Combined(), "/tmp/baz") ||
 		!strings.Contains(result.Combined(), "/tmp/Dockerfile") {
 		c.Fatalf("Missing proper output: %s", result.Combined())
15924f23
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildFromOfficialNames(c *check.C) {
568f86eb
 	name := "testbuildfromofficial"
 	fromNames := []string{
 		"busybox",
 		"docker.io/busybox",
 		"index.docker.io/busybox",
 		"library/busybox",
 		"docker.io/library/busybox",
 		"index.docker.io/library/busybox",
 	}
 	for idx, fromName := range fromNames {
 		imgName := fmt.Sprintf("%s%d", name, idx)
50c4475d
 		buildImageSuccessfully(c, imgName, build.WithDockerfile("FROM "+fromName))
c778f4b9
 		dockerCmd(c, "rmi", imgName)
568f86eb
 	}
 }
73d5baf5
 
dc944ea7
 func (s *DockerSuite) TestBuildDockerfileOutsideContext(c *check.C) {
c778f4b9
 	testRequires(c, UnixCli, DaemonIsLinux) // uses os.Symlink: not implemented in windows at the time of writing (go-1.4.2)
492a58f0
 
73d5baf5
 	name := "testbuilddockerfileoutsidecontext"
 	tmpdir, err := ioutil.TempDir("", name)
b616b8a1
 	c.Assert(err, check.IsNil)
73d5baf5
 	defer os.RemoveAll(tmpdir)
 	ctx := filepath.Join(tmpdir, "context")
 	if err := os.MkdirAll(ctx, 0755); err != nil {
dc944ea7
 		c.Fatal(err)
73d5baf5
 	}
c42d2625
 	if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte("FROM scratch\nENV X Y"), 0644); err != nil {
dc944ea7
 		c.Fatal(err)
73d5baf5
 	}
 	wd, err := os.Getwd()
 	if err != nil {
dc944ea7
 		c.Fatal(err)
73d5baf5
 	}
 	defer os.Chdir(wd)
 	if err := os.Chdir(ctx); err != nil {
dc944ea7
 		c.Fatal(err)
73d5baf5
 	}
c42d2625
 	if err := ioutil.WriteFile(filepath.Join(tmpdir, "outsideDockerfile"), []byte("FROM scratch\nENV x y"), 0644); err != nil {
dc944ea7
 		c.Fatal(err)
73d5baf5
 	}
4581240e
 	if err := os.Symlink(filepath.Join("..", "outsideDockerfile"), filepath.Join(ctx, "dockerfile1")); err != nil {
dc944ea7
 		c.Fatal(err)
73d5baf5
 	}
 	if err := os.Symlink(filepath.Join(tmpdir, "outsideDockerfile"), filepath.Join(ctx, "dockerfile2")); err != nil {
dc944ea7
 		c.Fatal(err)
73d5baf5
 	}
4581240e
 
73d5baf5
 	for _, dockerfilePath := range []string{
4581240e
 		filepath.Join("..", "outsideDockerfile"),
73d5baf5
 		filepath.Join(ctx, "dockerfile1"),
 		filepath.Join(ctx, "dockerfile2"),
 	} {
d7022f2b
 		result := dockerCmdWithResult("build", "-t", name, "--no-cache", "-f", dockerfilePath, ".")
92427b3a
 		result.Assert(c, icmd.Expected{
d7022f2b
 			Err:      "must be within the build context",
 			ExitCode: 1,
 		})
73d5baf5
 		deleteImages(name)
 	}
 
 	os.Chdir(tmpdir)
 
 	// Path to Dockerfile should be resolved relative to working directory, not relative to context.
 	// There is a Dockerfile in the context, but since there is no Dockerfile in the current directory, the following should fail
693ba98c
 	out, _, err := dockerCmdWithError("build", "-t", name, "--no-cache", "-f", "Dockerfile", ctx)
73d5baf5
 	if err == nil {
dc944ea7
 		c.Fatalf("Expected error. Out: %s", out)
73d5baf5
 	}
 }
3859c485
 
c778f4b9
 // FIXME(vdemeester) should be a unit test
dc944ea7
 func (s *DockerSuite) TestBuildSpaces(c *check.C) {
3859c485
 	// Test to make sure that leading/trailing spaces on a command
 	// doesn't change the error msg we get
 	name := "testspaces"
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile("FROM busybox\nCOPY\n"))
3859c485
 	defer ctx.Close()
 
56fb4653
 	result1 := cli.Docker(cli.Build(name), build.WithExternalBuildContext(ctx))
c10f6ef4
 	result1.Assert(c, icmd.Expected{
 		ExitCode: 1,
 	})
3859c485
 
d1e9d07c
 	ctx.Add("Dockerfile", "FROM busybox\nCOPY    ")
56fb4653
 	result2 := cli.Docker(cli.Build(name), build.WithExternalBuildContext(ctx))
c10f6ef4
 	result2.Assert(c, icmd.Expected{
 		ExitCode: 1,
 	})
3859c485
 
28a34dff
 	removeLogTimestamps := func(s string) string {
 		return regexp.MustCompile(`time="(.*?)"`).ReplaceAllString(s, `time=[TIMESTAMP]`)
 	}
 
3859c485
 	// Skip over the times
c10f6ef4
 	e1 := removeLogTimestamps(result1.Error.Error())
 	e2 := removeLogTimestamps(result2.Error.Error())
3859c485
 
 	// Ignore whitespace since that's what were verifying doesn't change stuff
 	if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) {
c10f6ef4
 		c.Fatalf("Build 2's error wasn't the same as build 1's\n1:%s\n2:%s", result1.Error, result2.Error)
3859c485
 	}
 
d1e9d07c
 	ctx.Add("Dockerfile", "FROM busybox\n   COPY")
56fb4653
 	result2 = cli.Docker(cli.Build(name), build.WithoutCache, build.WithExternalBuildContext(ctx))
c10f6ef4
 	result2.Assert(c, icmd.Expected{
 		ExitCode: 1,
 	})
3859c485
 
 	// Skip over the times
c10f6ef4
 	e1 = removeLogTimestamps(result1.Error.Error())
 	e2 = removeLogTimestamps(result2.Error.Error())
3859c485
 
 	// Ignore whitespace since that's what were verifying doesn't change stuff
 	if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) {
c10f6ef4
 		c.Fatalf("Build 3's error wasn't the same as build 1's\n1:%s\n3:%s", result1.Error, result2.Error)
3859c485
 	}
 
d1e9d07c
 	ctx.Add("Dockerfile", "FROM busybox\n   COPY    ")
56fb4653
 	result2 = cli.Docker(cli.Build(name), build.WithoutCache, build.WithExternalBuildContext(ctx))
c10f6ef4
 	result2.Assert(c, icmd.Expected{
 		ExitCode: 1,
 	})
3859c485
 
 	// Skip over the times
c10f6ef4
 	e1 = removeLogTimestamps(result1.Error.Error())
 	e2 = removeLogTimestamps(result2.Error.Error())
3859c485
 
 	// Ignore whitespace since that's what were verifying doesn't change stuff
 	if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) {
c10f6ef4
 		c.Fatalf("Build 4's error wasn't the same as build 1's\n1:%s\n4:%s", result1.Error, result2.Error)
3859c485
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildSpacesWithQuotes(c *check.C) {
3859c485
 	// Test to make sure that spaces in quotes aren't lost
 	name := "testspacesquotes"
 
 	dockerfile := `FROM busybox
 RUN echo "  \
   foo  "`
 
c778f4b9
 	expected := "\n    foo  \n"
6482410c
 	// Windows uses the builtin echo, which preserves quotes
18a771a7
 	if testEnv.OSType == "windows" {
c778f4b9
 		expected = "\"    foo  \""
3859c485
 	}
 
50c4475d
 	buildImage(name, build.WithDockerfile(dockerfile)).Assert(c, icmd.Expected{
c778f4b9
 		Out: expected,
 	})
3859c485
 }
c73e3bf4
 
 // #4393
dc944ea7
 func (s *DockerSuite) TestBuildVolumeFileExistsinContainer(c *check.C) {
0adcce10
 	testRequires(c, DaemonIsLinux) // TODO Windows: This should error out
50c4475d
 	buildImage("docker-test-errcreatevolumewithfile", build.WithDockerfile(`
c73e3bf4
 	FROM busybox
 	RUN touch /foo
 	VOLUME /foo
c778f4b9
 	`)).Assert(c, icmd.Expected{
 		ExitCode: 1,
 		Err:      "file exists",
 	})
c73e3bf4
 }
e4f02abb
 
c778f4b9
 // FIXME(vdemeester) should be a unit test
dc944ea7
 func (s *DockerSuite) TestBuildMissingArgs(c *check.C) {
d1e9d07c
 	// Test to make sure that all Dockerfile commands (except the ones listed
 	// in skipCmds) will generate an error if no args are provided.
 	// Note: INSERT is deprecated so we exclude it because of that.
 	skipCmds := map[string]struct{}{
 		"CMD":        {},
 		"RUN":        {},
 		"ENTRYPOINT": {},
 		"INSERT":     {},
e4f02abb
 	}
 
18a771a7
 	if testEnv.OSType == "windows" {
0adcce10
 		skipCmds = map[string]struct{}{
 			"CMD":        {},
 			"RUN":        {},
 			"ENTRYPOINT": {},
 			"INSERT":     {},
 			"STOPSIGNAL": {},
 			"ARG":        {},
 			"USER":       {},
 			"EXPOSE":     {},
 		}
 	}
 
6ecf2386
 	for cmd := range command.Commands {
d1e9d07c
 		cmd = strings.ToUpper(cmd)
 		if _, ok := skipCmds[cmd]; ok {
 			continue
 		}
ccde3a1f
 		var dockerfile string
e4f02abb
 		if cmd == "FROM" {
 			dockerfile = cmd
 		} else {
 			// Add FROM to make sure we don't complain about it missing
 			dockerfile = "FROM busybox\n" + cmd
 		}
 
50c4475d
 		buildImage("args", build.WithDockerfile(dockerfile)).Assert(c, icmd.Expected{
c778f4b9
 			ExitCode: 1,
 			Err:      cmd + " requires",
 		})
e4f02abb
 	}
 
 }
1654dfdf
 
dc944ea7
 func (s *DockerSuite) TestBuildEmptyScratch(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
50c4475d
 	buildImage("sc", build.WithDockerfile("FROM scratch")).Assert(c, icmd.Expected{
c778f4b9
 		ExitCode: 1,
 		Err:      "No image was generated",
 	})
1654dfdf
 }
0826ac15
 
dc944ea7
 func (s *DockerSuite) TestBuildDotDotFile(c *check.C) {
56fb4653
 	buildImageSuccessfully(c, "sc", build.WithBuildContext(c,
 		build.WithFile("Dockerfile", "FROM busybox\n"),
 		build.WithFile("..gitme", ""),
c778f4b9
 	))
0826ac15
 }
92c35358
 
dc944ea7
 func (s *DockerSuite) TestBuildRUNoneJSON(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // No hello-world Windows image
645f8a32
 	name := "testbuildrunonejson"
 
50c4475d
 	buildImage(name, build.WithDockerfile(`FROM hello-world:frozen
c778f4b9
 RUN [ "/hello" ]`)).Assert(c, icmd.Expected{
 		Out: "Hello from Docker",
 	})
645f8a32
 }
e6ae89a4
 
dc944ea7
 func (s *DockerSuite) TestBuildEmptyStringVolume(c *check.C) {
8071bf39
 	name := "testbuildemptystringvolume"
 
50c4475d
 	buildImage(name, build.WithDockerfile(`
8071bf39
   FROM busybox
   ENV foo=""
   VOLUME $foo
c778f4b9
   `)).Assert(c, icmd.Expected{
 		ExitCode: 1,
 	})
8071bf39
 }
f40dd69c
 
9dbe12b7
 func (s *DockerSuite) TestBuildContainerWithCgroupParent(c *check.C) {
c778f4b9
 	testRequires(c, SameHostDaemon, DaemonIsLinux)
f40dd69c
 
 	cgroupParent := "test"
 	data, err := ioutil.ReadFile("/proc/self/cgroup")
 	if err != nil {
9dbe12b7
 		c.Fatalf("failed to read '/proc/self/cgroup - %v", err)
f40dd69c
 	}
e8bd6718
 	selfCgroupPaths := ParseCgroupPaths(string(data))
f40dd69c
 	_, found := selfCgroupPaths["memory"]
 	if !found {
0d09439a
 		c.Fatalf("unable to find self memory cgroup path. CgroupsPath: %v", selfCgroupPaths)
f40dd69c
 	}
c10f6ef4
 	result := buildImage("buildcgroupparent",
50c4475d
 		cli.WithFlags("--cgroup-parent", cgroupParent),
 		build.WithDockerfile(`
f40dd69c
 FROM busybox
 RUN cat /proc/self/cgroup
c778f4b9
 `))
 	result.Assert(c, icmd.Success)
 	m, err := regexp.MatchString(fmt.Sprintf("memory:.*/%s/.*", cgroupParent), result.Combined())
0d09439a
 	c.Assert(err, check.IsNil)
 	if !m {
c778f4b9
 		c.Fatalf("There is no expected memory cgroup with parent /%s/: %s", cgroupParent, result.Combined())
0d09439a
 	}
f40dd69c
 }
08b7f30f
 
c778f4b9
 // FIXME(vdemeester) could be a unit test
08b7f30f
 func (s *DockerSuite) TestBuildNoDupOutput(c *check.C) {
 	// Check to make sure our build output prints the Dockerfile cmd
 	// property - there was a bug that caused it to be duplicated on the
 	// Step X  line
 	name := "testbuildnodupoutput"
50c4475d
 	result := buildImage(name, build.WithDockerfile(`
08b7f30f
   FROM busybox
c778f4b9
   RUN env`))
 	result.Assert(c, icmd.Success)
35418c14
 	exp := "\nStep 2/2 : RUN env\n"
c778f4b9
 	if !strings.Contains(result.Combined(), exp) {
 		c.Fatalf("Bad output\nGot:%s\n\nExpected to contain:%s\n", result.Combined(), exp)
17d6c6c7
 	}
 }
 
 // GH15826
c778f4b9
 // FIXME(vdemeester) could be a unit test
17d6c6c7
 func (s *DockerSuite) TestBuildStartsFromOne(c *check.C) {
 	// Explicit check to ensure that build starts from step 1 rather than 0
 	name := "testbuildstartsfromone"
50c4475d
 	result := buildImage(name, build.WithDockerfile(`FROM busybox`))
c778f4b9
 	result.Assert(c, icmd.Success)
35418c14
 	exp := "\nStep 1/1 : FROM busybox\n"
c778f4b9
 	if !strings.Contains(result.Combined(), exp) {
 		c.Fatalf("Bad output\nGot:%s\n\nExpected to contain:%s\n", result.Combined(), exp)
08b7f30f
 	}
 }
 
54662eae
 func (s *DockerSuite) TestBuildRUNErrMsg(c *check.C) {
 	// Test to make sure the bad command is quoted with just "s and
 	// not as a Go []string
 	name := "testbuildbadrunerrmsg"
5fc0de26
 	shell := "/bin/sh -c"
c778f4b9
 	exitCode := 127
18a771a7
 	if testEnv.OSType == "windows" {
5fc0de26
 		shell = "cmd /S /C"
 		// architectural - Windows has to start the container to determine the exe is bad, Linux does not
c778f4b9
 		exitCode = 1
54662eae
 	}
c778f4b9
 	exp := fmt.Sprintf(`The command '%s badEXE a1 \& a2	a3' returned a non-zero code: %d`, shell, exitCode)
 
50c4475d
 	buildImage(name, build.WithDockerfile(`
c778f4b9
   FROM busybox
   RUN badEXE a1 \& a2	a3`)).Assert(c, icmd.Expected{
 		ExitCode: exitCode,
 		Err:      exp,
 	})
54662eae
 }
871d2b96
 
 func (s *DockerTrustSuite) TestTrustedBuild(c *check.C) {
 	repoName := s.setupTrustedImage(c, "trusted-build")
 	dockerFile := fmt.Sprintf(`
   FROM %s
   RUN []
     `, repoName)
 
 	name := "testtrustedbuild"
 
50c4475d
 	buildImage(name, trustedBuild, build.WithDockerfile(dockerFile)).Assert(c, icmd.Expected{
c778f4b9
 		Out: fmt.Sprintf("FROM %s@sha", repoName[:len(repoName)-7]),
 	})
871d2b96
 
bb2e6c72
 	// We should also have a tag reference for the image.
c778f4b9
 	dockerCmd(c, "inspect", repoName)
bb2e6c72
 
 	// We should now be able to remove the tag reference.
c778f4b9
 	dockerCmd(c, "rmi", repoName)
871d2b96
 }
 
 func (s *DockerTrustSuite) TestTrustedBuildUntrustedTag(c *check.C) {
 	repoName := fmt.Sprintf("%v/dockercli/build-untrusted-tag:latest", privateRegistryURL)
 	dockerFile := fmt.Sprintf(`
   FROM %s
   RUN []
     `, repoName)
 
 	name := "testtrustedbuilduntrustedtag"
 
50c4475d
 	buildImage(name, trustedBuild, build.WithDockerfile(dockerFile)).Assert(c, icmd.Expected{
c778f4b9
 		ExitCode: 1,
 		Err:      "does not have trust data for",
 	})
871d2b96
 }
01d570ad
 
 func (s *DockerTrustSuite) TestBuildContextDirIsSymlink(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
01d570ad
 	tempDir, err := ioutil.TempDir("", "test-build-dir-is-symlink-")
b616b8a1
 	c.Assert(err, check.IsNil)
01d570ad
 	defer os.RemoveAll(tempDir)
 
 	// Make a real context directory in this temp directory with a simple
 	// Dockerfile.
 	realContextDirname := filepath.Join(tempDir, "context")
 	if err := os.Mkdir(realContextDirname, os.FileMode(0755)); err != nil {
 		c.Fatal(err)
 	}
 
 	if err = ioutil.WriteFile(
 		filepath.Join(realContextDirname, "Dockerfile"),
 		[]byte(`
 			FROM busybox
 			RUN echo hello world
 		`),
 		os.FileMode(0644),
 	); err != nil {
 		c.Fatal(err)
 	}
 
 	// Make a symlink to the real context directory.
 	contextSymlinkName := filepath.Join(tempDir, "context_link")
 	if err := os.Symlink(realContextDirname, contextSymlinkName); err != nil {
 		c.Fatal(err)
 	}
 
 	// Executing the build with the symlink as the specified context should
 	// *not* fail.
c778f4b9
 	dockerCmd(c, "build", contextSymlinkName)
01d570ad
 }
d45fcc6c
 
623ccc2f
 func (s *DockerTrustSuite) TestTrustedBuildTagFromReleasesRole(c *check.C) {
 	testRequires(c, NotaryHosting)
 
 	latestTag := s.setupTrustedImage(c, "trusted-build-releases-role")
 	repoName := strings.TrimSuffix(latestTag, ":latest")
 
 	// Now create the releases role
 	s.notaryCreateDelegation(c, repoName, "targets/releases", s.not.keys[0].Public)
 	s.notaryImportKey(c, repoName, "targets/releases", s.not.keys[0].Private)
 	s.notaryPublish(c, repoName)
 
 	// push a different tag to the releases role
 	otherTag := fmt.Sprintf("%s:other", repoName)
b0ba39d4
 	cli.DockerCmd(c, "tag", "busybox", otherTag)
623ccc2f
 
b0ba39d4
 	cli.Docker(cli.Args("push", otherTag), trustedCmd).Assert(c, icmd.Success)
623ccc2f
 	s.assertTargetInRoles(c, repoName, "other", "targets/releases")
 	s.assertTargetNotInRoles(c, repoName, "other", "targets")
 
b0ba39d4
 	cli.DockerCmd(c, "rmi", otherTag)
623ccc2f
 
 	dockerFile := fmt.Sprintf(`
   FROM %s
   RUN []
     `, otherTag)
 	name := "testtrustedbuildreleasesrole"
b0ba39d4
 	cli.BuildCmd(c, name, trustedCmd, build.WithDockerfile(dockerFile)).Assert(c, icmd.Expected{
c778f4b9
 		Out: fmt.Sprintf("FROM %s@sha", repoName),
 	})
623ccc2f
 }
 
 func (s *DockerTrustSuite) TestTrustedBuildTagIgnoresOtherDelegationRoles(c *check.C) {
 	testRequires(c, NotaryHosting)
 
 	latestTag := s.setupTrustedImage(c, "trusted-build-releases-role")
 	repoName := strings.TrimSuffix(latestTag, ":latest")
 
 	// Now create a non-releases delegation role
 	s.notaryCreateDelegation(c, repoName, "targets/other", s.not.keys[0].Public)
 	s.notaryImportKey(c, repoName, "targets/other", s.not.keys[0].Private)
 	s.notaryPublish(c, repoName)
 
 	// push a different tag to the other role
 	otherTag := fmt.Sprintf("%s:other", repoName)
b0ba39d4
 	cli.DockerCmd(c, "tag", "busybox", otherTag)
623ccc2f
 
b0ba39d4
 	cli.Docker(cli.Args("push", otherTag), trustedCmd).Assert(c, icmd.Success)
623ccc2f
 	s.assertTargetInRoles(c, repoName, "other", "targets/other")
 	s.assertTargetNotInRoles(c, repoName, "other", "targets")
 
b0ba39d4
 	cli.DockerCmd(c, "rmi", otherTag)
623ccc2f
 
 	dockerFile := fmt.Sprintf(`
   FROM %s
   RUN []
     `, otherTag)
 
 	name := "testtrustedbuildotherrole"
b0ba39d4
 	cli.Docker(cli.Build(name), trustedCmd, build.WithDockerfile(dockerFile)).Assert(c, icmd.Expected{
c778f4b9
 		ExitCode: 1,
 	})
623ccc2f
 }
 
d45fcc6c
 // Issue #15634: COPY fails when path starts with "null"
 func (s *DockerSuite) TestBuildNullStringInAddCopyVolume(c *check.C) {
 	name := "testbuildnullstringinaddcopyvolume"
5fc0de26
 	volName := "nullvolume"
18a771a7
 	if testEnv.OSType == "windows" {
5fc0de26
 		volName = `C:\\nullvolume`
 	}
 
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `
d45fcc6c
 		FROM busybox
8e5bb8fd
 
d45fcc6c
 		ADD null /
 		COPY nullfile /
5fc0de26
 		VOLUME `+volName+`
c778f4b9
 		`),
56fb4653
 		build.WithFile("null", "test1"),
 		build.WithFile("nullfile", "test2"),
c778f4b9
 	))
d45fcc6c
 }
3781cde6
 
 func (s *DockerSuite) TestBuildStopSignal(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support STOPSIGNAL yet
a252516e
 	imgName := "test_build_stop_signal"
50c4475d
 	buildImageSuccessfully(c, imgName, build.WithDockerfile(`FROM busybox
c778f4b9
 		 STOPSIGNAL SIGKILL`))
a252516e
 	res := inspectFieldJSON(c, imgName, "Config.StopSignal")
 	if res != `"SIGKILL"` {
 		c.Fatalf("Signal %s, expected SIGKILL", res)
 	}
 
 	containerName := "test-container-stop-signal"
 	dockerCmd(c, "run", "-d", "--name", containerName, imgName, "top")
 	res = inspectFieldJSON(c, containerName, "Config.StopSignal")
3781cde6
 	if res != `"SIGKILL"` {
 		c.Fatalf("Signal %s, expected SIGKILL", res)
 	}
 }
54240f8d
 
 func (s *DockerSuite) TestBuildBuildTimeArg(c *check.C) {
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
6b5c83bf
 	var dockerfile string
18a771a7
 	if testEnv.OSType == "windows" {
6b5c83bf
 		// Bugs in Windows busybox port - use the default base image and native cmd stuff
 		dockerfile = fmt.Sprintf(`FROM `+minimalBaseImage()+`
 			ARG %s
 			RUN echo %%%s%%
 			CMD setlocal enableextensions && if defined %s (echo %%%s%%)`, envKey, envKey, envKey, envKey)
 	} else {
 		dockerfile = fmt.Sprintf(`FROM busybox
 			ARG %s
 			RUN echo $%s
 			CMD echo $%s`, envKey, envKey, envKey)
 
54240f8d
 	}
c10f6ef4
 	buildImage(imgName,
50c4475d
 		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
 		build.WithDockerfile(dockerfile),
c778f4b9
 	).Assert(c, icmd.Expected{
 		Out: envVal,
 	})
54240f8d
 
 	containerName := "bldargCont"
6b5c83bf
 	out, _ := dockerCmd(c, "run", "--name", containerName, imgName)
 	out = strings.Trim(out, " \r\n'")
 	if out != "" {
54240f8d
 		c.Fatalf("run produced invalid output: %q, expected empty string", out)
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgHistory(c *check.C) {
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
 	envDef := "bar1"
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s=%s`, envKey, envDef)
c10f6ef4
 	buildImage(imgName,
50c4475d
 		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
 		build.WithDockerfile(dockerfile),
c778f4b9
 	).Assert(c, icmd.Expected{
 		Out: envVal,
 	})
54240f8d
 
 	out, _ := dockerCmd(c, "history", "--no-trunc", imgName)
 	outputTabs := strings.Split(out, "\n")[1]
 	if !strings.Contains(outputTabs, envDef) {
 		c.Fatalf("failed to find arg default in image history output: %q expected: %q", outputTabs, envDef)
 	}
 }
 
89a2a885
 func (s *DockerSuite) TestBuildTimeArgHistoryExclusions(c *check.C) {
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
 	proxy := "HTTP_PROXY=http://user:password@proxy.example.com"
 	explicitProxyKey := "http_proxy"
 	explicitProxyVal := "http://user:password@someproxy.example.com"
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s
 		ARG %s
 		RUN echo "Testing Build Args!"`, envKey, explicitProxyKey)
 
721e1736
 	buildImage := func(imgName string) string {
 		cli.BuildCmd(c, imgName,
 			cli.WithFlags("--build-arg", "https_proxy=https://proxy.example.com",
 				"--build-arg", fmt.Sprintf("%s=%s", envKey, envVal),
 				"--build-arg", fmt.Sprintf("%s=%s", explicitProxyKey, explicitProxyVal),
 				"--build-arg", proxy),
 			build.WithDockerfile(dockerfile),
 		)
 		return getIDByName(c, imgName)
 	}
 
 	origID := buildImage(imgName)
 	result := cli.DockerCmd(c, "history", "--no-trunc", imgName)
 	out := result.Stdout()
 
89a2a885
 	if strings.Contains(out, proxy) {
 		c.Fatalf("failed to exclude proxy settings from history!")
 	}
1076ab58
 	if strings.Contains(out, "https_proxy") {
 		c.Fatalf("failed to exclude proxy settings from history!")
 	}
9f738cc5
 	result.Assert(c, icmd.Expected{Out: fmt.Sprintf("%s=%s", envKey, envVal)})
 	result.Assert(c, icmd.Expected{Out: fmt.Sprintf("%s=%s", explicitProxyKey, explicitProxyVal)})
721e1736
 
 	cacheID := buildImage(imgName + "-two")
 	c.Assert(origID, checker.Equals, cacheID)
89a2a885
 }
 
54240f8d
 func (s *DockerSuite) TestBuildBuildTimeArgCacheHit(c *check.C) {
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s
 		RUN echo $%s`, envKey, envKey)
c778f4b9
 	buildImageSuccessfully(c, imgName,
50c4475d
 		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
 		build.WithDockerfile(dockerfile),
c778f4b9
 	)
c10f6ef4
 	origImgID := getIDByName(c, imgName)
54240f8d
 
 	imgNameCache := "bldargtestcachehit"
c778f4b9
 	buildImageSuccessfully(c, imgNameCache,
50c4475d
 		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
 		build.WithDockerfile(dockerfile),
c778f4b9
 	)
c10f6ef4
 	newImgID := getIDByName(c, imgName)
c778f4b9
 	if newImgID != origImgID {
54240f8d
 		c.Fatalf("build didn't use cache! expected image id: %q built image id: %q", origImgID, newImgID)
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgCacheMissExtraArg(c *check.C) {
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
 	extraEnvKey := "foo1"
 	extraEnvVal := "bar1"
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s
 		ARG %s
 		RUN echo $%s`, envKey, extraEnvKey, envKey)
c778f4b9
 	buildImageSuccessfully(c, imgName,
50c4475d
 		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
 		build.WithDockerfile(dockerfile),
c778f4b9
 	)
c10f6ef4
 	origImgID := getIDByName(c, imgName)
54240f8d
 
 	imgNameCache := "bldargtestcachemiss"
c778f4b9
 	buildImageSuccessfully(c, imgNameCache,
50c4475d
 		cli.WithFlags(
c778f4b9
 			"--build-arg", fmt.Sprintf("%s=%s", envKey, envVal),
 			"--build-arg", fmt.Sprintf("%s=%s", extraEnvKey, extraEnvVal),
 		),
50c4475d
 		build.WithDockerfile(dockerfile),
c778f4b9
 	)
c10f6ef4
 	newImgID := getIDByName(c, imgNameCache)
c778f4b9
 
 	if newImgID == origImgID {
54240f8d
 		c.Fatalf("build used cache, expected a miss!")
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgCacheMissSameArgDiffVal(c *check.C) {
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
 	newEnvVal := "bar1"
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s
 		RUN echo $%s`, envKey, envKey)
c778f4b9
 	buildImageSuccessfully(c, imgName,
50c4475d
 		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
 		build.WithDockerfile(dockerfile),
c778f4b9
 	)
c10f6ef4
 	origImgID := getIDByName(c, imgName)
54240f8d
 
 	imgNameCache := "bldargtestcachemiss"
c778f4b9
 	buildImageSuccessfully(c, imgNameCache,
50c4475d
 		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, newEnvVal)),
 		build.WithDockerfile(dockerfile),
c778f4b9
 	)
c10f6ef4
 	newImgID := getIDByName(c, imgNameCache)
c778f4b9
 	if newImgID == origImgID {
54240f8d
 		c.Fatalf("build used cache, expected a miss!")
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgOverrideArgDefinedBeforeEnv(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
39bcaee4
 	envValOverride := "barOverride"
54240f8d
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s
 		ENV %s %s
 		RUN echo $%s
 		CMD echo $%s
39bcaee4
         `, envKey, envKey, envValOverride, envKey, envKey)
54240f8d
 
c10f6ef4
 	result := buildImage(imgName,
50c4475d
 		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
 		build.WithDockerfile(dockerfile),
c778f4b9
 	)
 	result.Assert(c, icmd.Success)
39bcaee4
 	if strings.Count(result.Combined(), envValOverride) != 2 {
 		c.Fatalf("failed to access environment variable in output: %q expected: %q", result.Combined(), envValOverride)
54240f8d
 	}
 
 	containerName := "bldargCont"
39bcaee4
 	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); !strings.Contains(out, envValOverride) {
 		c.Fatalf("run produced invalid output: %q, expected %q", out, envValOverride)
54240f8d
 	}
 }
 
c778f4b9
 // FIXME(vdemeester) might be useful to merge with the one above ?
54240f8d
 func (s *DockerSuite) TestBuildBuildTimeArgOverrideEnvDefinedBeforeArg(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
39bcaee4
 	envValOverride := "barOverride"
54240f8d
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ENV %s %s
 		ARG %s
 		RUN echo $%s
 		CMD echo $%s
39bcaee4
         `, envKey, envValOverride, envKey, envKey, envKey)
c10f6ef4
 	result := buildImage(imgName,
50c4475d
 		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
 		build.WithDockerfile(dockerfile),
c778f4b9
 	)
 	result.Assert(c, icmd.Success)
39bcaee4
 	if strings.Count(result.Combined(), envValOverride) != 2 {
 		c.Fatalf("failed to access environment variable in output: %q expected: %q", result.Combined(), envValOverride)
54240f8d
 	}
 
 	containerName := "bldargCont"
39bcaee4
 	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); !strings.Contains(out, envValOverride) {
 		c.Fatalf("run produced invalid output: %q, expected %q", out, envValOverride)
54240f8d
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgExpansion(c *check.C) {
 	imgName := "bldvarstest"
 
 	wdVar := "WDIR"
 	wdVal := "/tmp/"
 	addVar := "AFILE"
 	addVal := "addFile"
 	copyVar := "CFILE"
 	copyVal := "copyFile"
 	envVar := "foo"
 	envVal := "bar"
 	exposeVar := "EPORT"
 	exposeVal := "9999"
 	userVar := "USER"
 	userVal := "testUser"
 	volVar := "VOL"
 	volVal := "/testVol/"
669c0677
 	if DaemonIsWindows() {
 		volVal = "C:\\testVol"
 		wdVal = "C:\\tmp"
 	}
c778f4b9
 
 	buildImageSuccessfully(c, imgName,
50c4475d
 		cli.WithFlags(
c778f4b9
 			"--build-arg", fmt.Sprintf("%s=%s", wdVar, wdVal),
 			"--build-arg", fmt.Sprintf("%s=%s", addVar, addVal),
 			"--build-arg", fmt.Sprintf("%s=%s", copyVar, copyVal),
 			"--build-arg", fmt.Sprintf("%s=%s", envVar, envVal),
 			"--build-arg", fmt.Sprintf("%s=%s", exposeVar, exposeVal),
 			"--build-arg", fmt.Sprintf("%s=%s", userVar, userVal),
 			"--build-arg", fmt.Sprintf("%s=%s", volVar, volVal),
 		),
56fb4653
 		build.WithBuildContext(c,
 			build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
54240f8d
 		ARG %s
 		WORKDIR ${%s}
 		ARG %s
 		ADD ${%s} testDir/
 		ARG %s
 		COPY $%s testDir/
 		ARG %s
 		ENV %s=${%s}
 		ARG %s
 		EXPOSE $%s
 		ARG %s
 		USER $%s
 		ARG %s
 		VOLUME ${%s}`,
c778f4b9
 				wdVar, wdVar, addVar, addVar, copyVar, copyVar, envVar, envVar,
 				envVar, exposeVar, exposeVar, userVar, userVar, volVar, volVar)),
56fb4653
 			build.WithFile(addVal, "some stuff"),
 			build.WithFile(copyVal, "some stuff"),
c778f4b9
 		),
 	)
54240f8d
 
c778f4b9
 	res := inspectField(c, imgName, "Config.WorkingDir")
669c0677
 	c.Check(filepath.ToSlash(res), check.Equals, filepath.ToSlash(wdVal))
54240f8d
 
c778f4b9
 	var resArr []string
 	inspectFieldAndUnmarshall(c, imgName, "Config.Env", &resArr)
54240f8d
 
 	found := false
 	for _, v := range resArr {
 		if fmt.Sprintf("%s=%s", envVar, envVal) == v {
 			found = true
 			break
 		}
 	}
 	if !found {
 		c.Fatalf("Config.Env value mismatch. Expected <key=value> to exist: %s=%s, got: %v",
 			envVar, envVal, resArr)
 	}
 
c778f4b9
 	var resMap map[string]interface{}
 	inspectFieldAndUnmarshall(c, imgName, "Config.ExposedPorts", &resMap)
54240f8d
 	if _, ok := resMap[fmt.Sprintf("%s/tcp", exposeVal)]; !ok {
 		c.Fatalf("Config.ExposedPorts value mismatch. Expected exposed port: %s/tcp, got: %v", exposeVal, resMap)
 	}
 
62a856e9
 	res = inspectField(c, imgName, "Config.User")
54240f8d
 	if res != userVal {
 		c.Fatalf("Config.User value mismatch. Expected: %s, got: %s", userVal, res)
 	}
 
c778f4b9
 	inspectFieldAndUnmarshall(c, imgName, "Config.Volumes", &resMap)
54240f8d
 	if _, ok := resMap[volVal]; !ok {
 		c.Fatalf("Config.Volumes value mismatch. Expected volume: %s, got: %v", volVal, resMap)
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgExpansionOverride(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldvarstest"
 	envKey := "foo"
 	envVal := "bar"
 	envKey1 := "foo1"
39bcaee4
 	envValOverride := "barOverride"
54240f8d
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s
 		ENV %s %s
 		ENV %s ${%s}
 		RUN echo $%s
39bcaee4
 		CMD echo $%s`, envKey, envKey, envValOverride, envKey1, envKey, envKey1, envKey1)
c10f6ef4
 	result := buildImage(imgName,
50c4475d
 		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
 		build.WithDockerfile(dockerfile),
c778f4b9
 	)
 	result.Assert(c, icmd.Success)
39bcaee4
 	if strings.Count(result.Combined(), envValOverride) != 2 {
 		c.Fatalf("failed to access environment variable in output: %q expected: %q", result.Combined(), envValOverride)
54240f8d
 	}
 
 	containerName := "bldargCont"
39bcaee4
 	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); !strings.Contains(out, envValOverride) {
 		c.Fatalf("run produced invalid output: %q, expected %q", out, envValOverride)
54240f8d
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgUntrustedDefinedAfterUse(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
 	dockerfile := fmt.Sprintf(`FROM busybox
 		RUN echo $%s
 		ARG %s
 		CMD echo $%s`, envKey, envKey, envKey)
c10f6ef4
 	result := buildImage(imgName,
50c4475d
 		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
 		build.WithDockerfile(dockerfile),
c778f4b9
 	)
 	result.Assert(c, icmd.Success)
 	if strings.Contains(result.Combined(), envVal) {
 		c.Fatalf("able to access environment variable in output: %q expected to be missing", result.Combined())
54240f8d
 	}
 
 	containerName := "bldargCont"
 	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); out != "\n" {
 		c.Fatalf("run produced invalid output: %q, expected empty string", out)
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgBuiltinArg(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support --build-arg
54240f8d
 	imgName := "bldargtest"
 	envKey := "HTTP_PROXY"
 	envVal := "bar"
 	dockerfile := fmt.Sprintf(`FROM busybox
 		RUN echo $%s
 		CMD echo $%s`, envKey, envKey)
 
c10f6ef4
 	result := buildImage(imgName,
50c4475d
 		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
 		build.WithDockerfile(dockerfile),
c778f4b9
 	)
 	result.Assert(c, icmd.Success)
 	if !strings.Contains(result.Combined(), envVal) {
 		c.Fatalf("failed to access environment variable in output: %q expected: %q", result.Combined(), envVal)
54240f8d
 	}
 	containerName := "bldargCont"
 	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); out != "\n" {
 		c.Fatalf("run produced invalid output: %q, expected empty string", out)
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgDefaultOverride(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
39bcaee4
 	envValOverride := "barOverride"
54240f8d
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s=%s
 		ENV %s $%s
 		RUN echo $%s
 		CMD echo $%s`, envKey, envVal, envKey, envKey, envKey, envKey)
c10f6ef4
 	result := buildImage(imgName,
39bcaee4
 		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envValOverride)),
50c4475d
 		build.WithDockerfile(dockerfile),
c778f4b9
 	)
 	result.Assert(c, icmd.Success)
39bcaee4
 	if strings.Count(result.Combined(), envValOverride) != 1 {
 		c.Fatalf("failed to access environment variable in output: %q expected: %q", result.Combined(), envValOverride)
54240f8d
 	}
 
 	containerName := "bldargCont"
39bcaee4
 	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); !strings.Contains(out, envValOverride) {
 		c.Fatalf("run produced invalid output: %q, expected %q", out, envValOverride)
54240f8d
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgUnconsumedArg(c *check.C) {
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
 	dockerfile := fmt.Sprintf(`FROM busybox
 		RUN echo $%s
 		CMD echo $%s`, envKey, envKey)
f150f420
 	warnStr := "[Warning] One or more build-args"
c10f6ef4
 	buildImage(imgName,
50c4475d
 		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
 		build.WithDockerfile(dockerfile),
c778f4b9
 	).Assert(c, icmd.Expected{
 		Out: warnStr,
 	})
54240f8d
 }
 
cdb8ea90
 func (s *DockerSuite) TestBuildBuildTimeArgEnv(c *check.C) {
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
c778f4b9
 	dockerfile := `FROM busybox
cdb8ea90
 		ARG FOO1=fromfile
 		ARG FOO2=fromfile
 		ARG FOO3=fromfile
 		ARG FOO4=fromfile
 		ARG FOO5
 		ARG FOO6
8f37715a
 		ARG FO10
cdb8ea90
 		RUN env
 		RUN [ "$FOO1" == "fromcmd" ]
 		RUN [ "$FOO2" == "" ]
 		RUN [ "$FOO3" == "fromenv" ]
 		RUN [ "$FOO4" == "fromfile" ]
 		RUN [ "$FOO5" == "fromcmd" ]
 		# The following should not exist at all in the env
 		RUN [ "$(env | grep FOO6)" == "" ]
 		RUN [ "$(env | grep FOO7)" == "" ]
 		RUN [ "$(env | grep FOO8)" == "" ]
 		RUN [ "$(env | grep FOO9)" == "" ]
8f37715a
 		RUN [ "$FO10" == "" ]
c778f4b9
 	    `
c10f6ef4
 	result := buildImage("testbuildtimeargenv",
50c4475d
 		cli.WithFlags(
c778f4b9
 			"--build-arg", fmt.Sprintf("FOO1=fromcmd"),
 			"--build-arg", fmt.Sprintf("FOO2="),
 			"--build-arg", fmt.Sprintf("FOO3"), // set in env
 			"--build-arg", fmt.Sprintf("FOO4"), // not set in env
 			"--build-arg", fmt.Sprintf("FOO5=fromcmd"),
 			// FOO6 is not set at all
 			"--build-arg", fmt.Sprintf("FOO7=fromcmd"), // should produce a warning
 			"--build-arg", fmt.Sprintf("FOO8="), // should produce a warning
 			"--build-arg", fmt.Sprintf("FOO9"), // should produce a warning
8f37715a
 			"--build-arg", fmt.Sprintf("FO10"), // not set in env, empty value
c778f4b9
 		),
50c4475d
 		cli.WithEnvironmentVariables(append(os.Environ(),
c778f4b9
 			"FOO1=fromenv",
 			"FOO2=fromenv",
 			"FOO3=fromenv")...),
56fb4653
 		build.WithBuildContext(c,
 			build.WithFile("Dockerfile", dockerfile),
c778f4b9
 		),
 	)
 	result.Assert(c, icmd.Success)
cdb8ea90
 
 	// Now check to make sure we got a warning msg about unused build-args
c778f4b9
 	i := strings.Index(result.Combined(), "[Warning]")
cdb8ea90
 	if i < 0 {
c778f4b9
 		c.Fatalf("Missing the build-arg warning in %q", result.Combined())
cdb8ea90
 	}
 
c778f4b9
 	out := result.Combined()[i:] // "out" should contain just the warning message now
cdb8ea90
 
 	// These were specified on a --build-arg but no ARG was in the Dockerfile
 	c.Assert(out, checker.Contains, "FOO7")
 	c.Assert(out, checker.Contains, "FOO8")
 	c.Assert(out, checker.Contains, "FOO9")
 }
 
54240f8d
 func (s *DockerSuite) TestBuildBuildTimeArgQuotedValVariants(c *check.C) {
 	imgName := "bldargtest"
 	envKey := "foo"
 	envKey1 := "foo1"
 	envKey2 := "foo2"
 	envKey3 := "foo3"
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s=""
 		ARG %s=''
 		ARG %s="''"
 		ARG %s='""'
 		RUN [ "$%s" != "$%s" ]
 		RUN [ "$%s" != "$%s" ]
 		RUN [ "$%s" != "$%s" ]
 		RUN [ "$%s" != "$%s" ]
 		RUN [ "$%s" != "$%s" ]`, envKey, envKey1, envKey2, envKey3,
 		envKey, envKey2, envKey, envKey3, envKey1, envKey2, envKey1, envKey3,
 		envKey2, envKey3)
50c4475d
 	buildImageSuccessfully(c, imgName, build.WithDockerfile(dockerfile))
54240f8d
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgEmptyValVariants(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	envKey1 := "foo1"
 	envKey2 := "foo2"
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s=
 		ARG %s=""
 		ARG %s=''
 		RUN [ "$%s" == "$%s" ]
 		RUN [ "$%s" == "$%s" ]
 		RUN [ "$%s" == "$%s" ]`, envKey, envKey1, envKey2, envKey, envKey1, envKey1, envKey2, envKey, envKey2)
50c4475d
 	buildImageSuccessfully(c, imgName, build.WithDockerfile(dockerfile))
54240f8d
 }
 
39bcaee4
 func (s *DockerSuite) TestBuildBuildTimeArgDefinitionWithNoEnvInjection(c *check.C) {
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s
 		RUN env`, envKey)
 
239c53bf
 	result := cli.BuildCmd(c, imgName, build.WithDockerfile(dockerfile))
c778f4b9
 	result.Assert(c, icmd.Success)
 	if strings.Count(result.Combined(), envKey) != 1 {
 		c.Fatalf("unexpected number of occurrences of the arg in output: %q expected: 1", result.Combined())
54240f8d
 	}
 }
8e5bb8fd
 
e90b7c06
 func (s *DockerSuite) TestBuildMultiStageArg(c *check.C) {
09f308ce
 	imgName := "multifrombldargtest"
 	dockerfile := `FROM busybox
     ARG foo=abc
     LABEL multifromtest=1
     RUN env > /out
     FROM busybox
     ARG bar=def
     RUN env > /out`
 
239c53bf
 	result := cli.BuildCmd(c, imgName, build.WithDockerfile(dockerfile))
09f308ce
 	result.Assert(c, icmd.Success)
 
239c53bf
 	result = cli.DockerCmd(c, "images", "-q", "-f", "label=multifromtest=1")
09f308ce
 	parentID := strings.TrimSpace(result.Stdout())
 
239c53bf
 	result = cli.DockerCmd(c, "run", "--rm", parentID, "cat", "/out")
09f308ce
 	c.Assert(result.Stdout(), checker.Contains, "foo=abc")
 
239c53bf
 	result = cli.DockerCmd(c, "run", "--rm", imgName, "cat", "/out")
09f308ce
 	c.Assert(result.Stdout(), checker.Not(checker.Contains), "foo")
 	c.Assert(result.Stdout(), checker.Contains, "bar=def")
 }
 
e90b7c06
 func (s *DockerSuite) TestBuildMultiStageGlobalArg(c *check.C) {
239c53bf
 	imgName := "multifrombldargtest"
 	dockerfile := `ARG tag=nosuchtag
      FROM busybox:${tag}
      LABEL multifromtest=1
      RUN env > /out
      FROM busybox:${tag}
      ARG tag
      RUN env > /out`
 
 	result := cli.BuildCmd(c, imgName,
 		build.WithDockerfile(dockerfile),
 		cli.WithFlags("--build-arg", fmt.Sprintf("tag=latest")))
 	result.Assert(c, icmd.Success)
 
 	result = cli.DockerCmd(c, "images", "-q", "-f", "label=multifromtest=1")
 	parentID := strings.TrimSpace(result.Stdout())
 
 	result = cli.DockerCmd(c, "run", "--rm", parentID, "cat", "/out")
 	c.Assert(result.Stdout(), checker.Not(checker.Contains), "tag")
 
 	result = cli.DockerCmd(c, "run", "--rm", imgName, "cat", "/out")
 	c.Assert(result.Stdout(), checker.Contains, "tag=latest")
 }
 
e90b7c06
 func (s *DockerSuite) TestBuildMultiStageUnusedArg(c *check.C) {
09f308ce
 	imgName := "multifromunusedarg"
 	dockerfile := `FROM busybox
     ARG foo
     FROM busybox
     ARG bar
     RUN env > /out`
 
239c53bf
 	result := cli.BuildCmd(c, imgName,
 		build.WithDockerfile(dockerfile),
 		cli.WithFlags("--build-arg", fmt.Sprintf("baz=abc")))
09f308ce
 	result.Assert(c, icmd.Success)
 	c.Assert(result.Combined(), checker.Contains, "[Warning]")
 	c.Assert(result.Combined(), checker.Contains, "[baz] were not consumed")
 
239c53bf
 	result = cli.DockerCmd(c, "run", "--rm", imgName, "cat", "/out")
09f308ce
 	c.Assert(result.Stdout(), checker.Not(checker.Contains), "bar")
 	c.Assert(result.Stdout(), checker.Not(checker.Contains), "baz")
 }
 
8e5bb8fd
 func (s *DockerSuite) TestBuildNoNamedVolume(c *check.C) {
5fc0de26
 	volName := "testname:/foo"
 
18a771a7
 	if testEnv.OSType == "windows" {
5fc0de26
 		volName = "testname:C:\\foo"
 	}
 	dockerCmd(c, "run", "-v", volName, "busybox", "sh", "-c", "touch /foo/oops")
8e5bb8fd
 
 	dockerFile := `FROM busybox
5fc0de26
 	VOLUME ` + volName + `
8e5bb8fd
 	RUN ls /foo/oops
 	`
50c4475d
 	buildImage("test", build.WithDockerfile(dockerFile)).Assert(c, icmd.Expected{
c778f4b9
 		ExitCode: 1,
 	})
8e5bb8fd
 }
2968fa44
 
 func (s *DockerSuite) TestBuildTagEvent(c *check.C) {
55053d35
 	since := daemonUnixTime(c)
2968fa44
 
 	dockerFile := `FROM busybox
 	RUN echo events
 	`
50c4475d
 	buildImageSuccessfully(c, "test", build.WithDockerfile(dockerFile))
2968fa44
 
55053d35
 	until := daemonUnixTime(c)
 	out, _ := dockerCmd(c, "events", "--since", since, "--until", until, "--filter", "type=image")
72f1881d
 	events := strings.Split(strings.TrimSpace(out), "\n")
 	actions := eventActionsByIDAndType(c, events, "test:latest", "image")
 	var foundTag bool
 	for _, a := range actions {
 		if a == "tag" {
 			foundTag = true
 			break
af51df20
 		}
 	}
 
72f1881d
 	c.Assert(foundTag, checker.True, check.Commentf("No tag event found:\n%s", out))
2968fa44
 }
c2eb37f9
 
 // #15780
 func (s *DockerSuite) TestBuildMultipleTags(c *check.C) {
 	dockerfile := `
 	FROM busybox
 	MAINTAINER test-15780
 	`
50c4475d
 	buildImageSuccessfully(c, "tag1", cli.WithFlags("-t", "tag2:v2", "-t", "tag1:latest", "-t", "tag1"), build.WithDockerfile(dockerfile))
c2eb37f9
 
c10f6ef4
 	id1 := getIDByName(c, "tag1")
 	id2 := getIDByName(c, "tag2:v2")
c2eb37f9
 	c.Assert(id1, check.Equals, id2)
 }
47da59f7
 
 // #17290
 func (s *DockerSuite) TestBuildCacheBrokenSymlink(c *check.C) {
 	name := "testbuildbrokensymlink"
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(`
47da59f7
 	FROM busybox
56fb4653
 	COPY . ./`),
 		fakecontext.WithFiles(map[string]string{
47da59f7
 			"foo": "bar",
56fb4653
 		}))
47da59f7
 	defer ctx.Close()
 
c10f6ef4
 	err := os.Symlink(filepath.Join(ctx.Dir, "nosuchfile"), filepath.Join(ctx.Dir, "asymlink"))
47da59f7
 	c.Assert(err, checker.IsNil)
 
 	// warm up cache
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
47da59f7
 
 	// add new file to context, should invalidate cache
 	err = ioutil.WriteFile(filepath.Join(ctx.Dir, "newfile"), []byte("foo"), 0644)
 	c.Assert(err, checker.IsNil)
 
56fb4653
 	result := cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	if strings.Contains(result.Combined(), "Using cache") {
 		c.Fatal("2nd build used cache on ADD, it shouldn't")
 	}
47da59f7
 }
 
 func (s *DockerSuite) TestBuildFollowSymlinkToFile(c *check.C) {
 	name := "testbuildbrokensymlink"
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(`
47da59f7
 	FROM busybox
56fb4653
 	COPY asymlink target`),
 		fakecontext.WithFiles(map[string]string{
47da59f7
 			"foo": "bar",
56fb4653
 		}))
47da59f7
 	defer ctx.Close()
 
c10f6ef4
 	err := os.Symlink("foo", filepath.Join(ctx.Dir, "asymlink"))
47da59f7
 	c.Assert(err, checker.IsNil)
 
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
47da59f7
 
56fb4653
 	out := cli.DockerCmd(c, "run", "--rm", name, "cat", "target").Combined()
47da59f7
 	c.Assert(out, checker.Matches, "bar")
 
 	// change target file should invalidate cache
 	err = ioutil.WriteFile(filepath.Join(ctx.Dir, "foo"), []byte("baz"), 0644)
 	c.Assert(err, checker.IsNil)
 
56fb4653
 	result := cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	c.Assert(result.Combined(), checker.Not(checker.Contains), "Using cache")
47da59f7
 
56fb4653
 	out = cli.DockerCmd(c, "run", "--rm", name, "cat", "target").Combined()
47da59f7
 	c.Assert(out, checker.Matches, "baz")
 }
 
 func (s *DockerSuite) TestBuildFollowSymlinkToDir(c *check.C) {
 	name := "testbuildbrokensymlink"
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(`
47da59f7
 	FROM busybox
56fb4653
 	COPY asymlink /`),
 		fakecontext.WithFiles(map[string]string{
47da59f7
 			"foo/abc": "bar",
 			"foo/def": "baz",
56fb4653
 		}))
47da59f7
 	defer ctx.Close()
 
c10f6ef4
 	err := os.Symlink("foo", filepath.Join(ctx.Dir, "asymlink"))
47da59f7
 	c.Assert(err, checker.IsNil)
 
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
47da59f7
 
56fb4653
 	out := cli.DockerCmd(c, "run", "--rm", name, "cat", "abc", "def").Combined()
47da59f7
 	c.Assert(out, checker.Matches, "barbaz")
 
 	// change target file should invalidate cache
 	err = ioutil.WriteFile(filepath.Join(ctx.Dir, "foo/def"), []byte("bax"), 0644)
 	c.Assert(err, checker.IsNil)
 
56fb4653
 	result := cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
c10f6ef4
 	c.Assert(result.Combined(), checker.Not(checker.Contains), "Using cache")
47da59f7
 
56fb4653
 	out = cli.DockerCmd(c, "run", "--rm", name, "cat", "abc", "def").Combined()
47da59f7
 	c.Assert(out, checker.Matches, "barbax")
 
 }
 
 // TestBuildSymlinkBasename tests that target file gets basename from symlink,
 // not from the target file.
 func (s *DockerSuite) TestBuildSymlinkBasename(c *check.C) {
 	name := "testbuildbrokensymlink"
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(`
47da59f7
 	FROM busybox
56fb4653
 	COPY asymlink /`),
 		fakecontext.WithFiles(map[string]string{
47da59f7
 			"foo": "bar",
56fb4653
 		}))
47da59f7
 	defer ctx.Close()
 
c10f6ef4
 	err := os.Symlink("foo", filepath.Join(ctx.Dir, "asymlink"))
47da59f7
 	c.Assert(err, checker.IsNil)
 
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
47da59f7
 
56fb4653
 	out := cli.DockerCmd(c, "run", "--rm", name, "cat", "asymlink").Combined()
47da59f7
 	c.Assert(out, checker.Matches, "bar")
 }
86faf1e1
 
 // #17827
 func (s *DockerSuite) TestBuildCacheRootSource(c *check.C) {
 	name := "testbuildrootsource"
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(`
86faf1e1
 	FROM busybox
56fb4653
 	COPY / /data`),
 		fakecontext.WithFiles(map[string]string{
86faf1e1
 			"foo": "bar",
56fb4653
 		}))
86faf1e1
 	defer ctx.Close()
 
 	// warm up cache
56fb4653
 	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
86faf1e1
 
 	// change file, should invalidate cache
c10f6ef4
 	err := ioutil.WriteFile(filepath.Join(ctx.Dir, "foo"), []byte("baz"), 0644)
86faf1e1
 	c.Assert(err, checker.IsNil)
 
56fb4653
 	result := cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
86faf1e1
 
c10f6ef4
 	c.Assert(result.Combined(), checker.Not(checker.Contains), "Using cache")
86faf1e1
 }
167cc429
 
 // #19375
 func (s *DockerSuite) TestBuildFailsGitNotCallable(c *check.C) {
50c4475d
 	buildImage("gitnotcallable", cli.WithEnvironmentVariables("PATH="),
 		build.WithContextPath("github.com/docker/v1.10-migrator.git")).Assert(c, icmd.Expected{
c778f4b9
 		ExitCode: 1,
 		Err:      "unable to prepare context: unable to find 'git': ",
 	})
167cc429
 
50c4475d
 	buildImage("gitnotcallable", cli.WithEnvironmentVariables("PATH="),
 		build.WithContextPath("https://github.com/docker/v1.10-migrator.git")).Assert(c, icmd.Expected{
c778f4b9
 		ExitCode: 1,
 		Err:      "unable to prepare context: unable to find 'git': ",
 	})
167cc429
 }
67912303
 
 // TestBuildWorkdirWindowsPath tests that a Windows style path works as a workdir
 func (s *DockerSuite) TestBuildWorkdirWindowsPath(c *check.C) {
 	testRequires(c, DaemonIsWindows)
 	name := "testbuildworkdirwindowspath"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`
dfedc9ef
 	FROM `+testEnv.PlatformDefaults.BaseImage+`
67912303
 	RUN mkdir C:\\work
 	WORKDIR C:\\work
 	RUN if "%CD%" NEQ "C:\work" exit -1
c778f4b9
 	`))
67912303
 }
6fed46ae
 
fc214b44
 func (s *DockerSuite) TestBuildLabel(c *check.C) {
 	name := "testbuildlabel"
 	testLabel := "foo"
 
50c4475d
 	buildImageSuccessfully(c, name, cli.WithFlags("--label", testLabel),
 		build.WithDockerfile(`
fc214b44
   FROM `+minimalBaseImage()+`
   LABEL default foo
c778f4b9
 `))
fc214b44
 
 	var labels map[string]string
c778f4b9
 	inspectFieldAndUnmarshall(c, name, "Config.Labels", &labels)
fc214b44
 	if _, ok := labels[testLabel]; !ok {
 		c.Fatal("label not found in image")
 	}
 }
 
1a85c8eb
 func (s *DockerSuite) TestBuildLabelOneNode(c *check.C) {
 	name := "testbuildlabel"
50c4475d
 	buildImageSuccessfully(c, name, cli.WithFlags("--label", "foo=bar"),
 		build.WithDockerfile("FROM busybox"))
1a85c8eb
 
 	var labels map[string]string
c778f4b9
 	inspectFieldAndUnmarshall(c, name, "Config.Labels", &labels)
1a85c8eb
 	v, ok := labels["foo"]
 	if !ok {
 		c.Fatal("label `foo` not found in image")
 	}
 	c.Assert(v, checker.Equals, "bar")
 }
 
fc214b44
 func (s *DockerSuite) TestBuildLabelCacheCommit(c *check.C) {
 	name := "testbuildlabelcachecommit"
 	testLabel := "foo"
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`
fc214b44
   FROM `+minimalBaseImage()+`
   LABEL default foo
c778f4b9
   `))
50c4475d
 	buildImageSuccessfully(c, name, cli.WithFlags("--label", testLabel),
 		build.WithDockerfile(`
fc214b44
   FROM `+minimalBaseImage()+`
   LABEL default foo
c778f4b9
   `))
fc214b44
 
 	var labels map[string]string
c778f4b9
 	inspectFieldAndUnmarshall(c, name, "Config.Labels", &labels)
fc214b44
 	if _, ok := labels[testLabel]; !ok {
 		c.Fatal("label not found in image")
 	}
 }
 
 func (s *DockerSuite) TestBuildLabelMultiple(c *check.C) {
 	name := "testbuildlabelmultiple"
 	testLabels := map[string]string{
 		"foo": "bar",
 		"123": "456",
 	}
 	labelArgs := []string{}
 	for k, v := range testLabels {
 		labelArgs = append(labelArgs, "--label", k+"="+v)
 	}
 
50c4475d
 	buildImageSuccessfully(c, name, cli.WithFlags(labelArgs...),
 		build.WithDockerfile(`
fc214b44
   FROM `+minimalBaseImage()+`
   LABEL default foo
c778f4b9
 `))
fc214b44
 
 	var labels map[string]string
c778f4b9
 	inspectFieldAndUnmarshall(c, name, "Config.Labels", &labels)
fc214b44
 	for k, v := range testLabels {
 		if x, ok := labels[k]; !ok || x != v {
 			c.Fatalf("label %s=%s not found in image", k, v)
 		}
 	}
 }
 
1b5c2e1d
 func (s *DockerRegistryAuthHtpasswdSuite) TestBuildFromAuthenticatedRegistry(c *check.C) {
4300e5e8
 	dockerCmd(c, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL)
6fed46ae
 	baseImage := privateRegistryURL + "/baseimage"
 
50c4475d
 	buildImageSuccessfully(c, baseImage, build.WithDockerfile(`
6fed46ae
 	FROM busybox
 	ENV env1 val1
c778f4b9
 	`))
6fed46ae
 
 	dockerCmd(c, "push", baseImage)
 	dockerCmd(c, "rmi", baseImage)
 
50c4475d
 	buildImageSuccessfully(c, baseImage, build.WithDockerfile(fmt.Sprintf(`
6fed46ae
 	FROM %s
 	ENV env2 val2
c778f4b9
 	`, baseImage)))
6fed46ae
 }
44152144
 
1b5c2e1d
 func (s *DockerRegistryAuthHtpasswdSuite) TestBuildWithExternalAuth(c *check.C) {
44152144
 	osPath := os.Getenv("PATH")
 	defer os.Setenv("PATH", osPath)
 
 	workingDir, err := os.Getwd()
 	c.Assert(err, checker.IsNil)
 	absolute, err := filepath.Abs(filepath.Join(workingDir, "fixtures", "auth"))
 	c.Assert(err, checker.IsNil)
 	testPath := fmt.Sprintf("%s%c%s", osPath, filepath.ListSeparator, absolute)
 
 	os.Setenv("PATH", testPath)
 
 	repoName := fmt.Sprintf("%v/dockercli/busybox:authtest", privateRegistryURL)
 
 	tmp, err := ioutil.TempDir("", "integration-cli-")
 	c.Assert(err, checker.IsNil)
 
 	externalAuthConfig := `{ "credsStore": "shell-test" }`
 
 	configPath := filepath.Join(tmp, "config.json")
 	err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
 	c.Assert(err, checker.IsNil)
 
4300e5e8
 	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL)
44152144
 
 	b, err := ioutil.ReadFile(configPath)
 	c.Assert(err, checker.IsNil)
 	c.Assert(string(b), checker.Not(checker.Contains), "\"auth\":")
 
 	dockerCmd(c, "--config", tmp, "tag", "busybox", repoName)
 	dockerCmd(c, "--config", tmp, "push", repoName)
 
 	// make sure the image is pulled when building
 	dockerCmd(c, "rmi", repoName)
 
c778f4b9
 	icmd.RunCmd(icmd.Cmd{
 		Command: []string{dockerBinary, "--config", tmp, "build", "-"},
 		Stdin:   strings.NewReader(fmt.Sprintf("FROM %s", repoName)),
 	}).Assert(c, icmd.Success)
44152144
 }
5844736c
 
 // Test cases in #22036
 func (s *DockerSuite) TestBuildLabelsOverride(c *check.C) {
 	// Command line option labels will always override
 	name := "scratchy"
 	expected := `{"bar":"from-flag","foo":"from-flag"}`
50c4475d
 	buildImageSuccessfully(c, name, cli.WithFlags("--label", "foo=from-flag", "--label", "bar=from-flag"),
 		build.WithDockerfile(`FROM `+minimalBaseImage()+`
c778f4b9
                 LABEL foo=from-dockerfile`))
5844736c
 	res := inspectFieldJSON(c, name, "Config.Labels")
 	if res != expected {
 		c.Fatalf("Labels %s, expected %s", res, expected)
 	}
 
 	name = "from"
 	expected = `{"foo":"from-dockerfile"}`
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
c778f4b9
                 LABEL foo from-dockerfile`))
5844736c
 	res = inspectFieldJSON(c, name, "Config.Labels")
 	if res != expected {
 		c.Fatalf("Labels %s, expected %s", res, expected)
 	}
 
 	// Command line option label will override even via `FROM`
 	name = "new"
 	expected = `{"bar":"from-dockerfile2","foo":"new"}`
50c4475d
 	buildImageSuccessfully(c, name, cli.WithFlags("--label", "foo=new"),
 		build.WithDockerfile(`FROM from
c778f4b9
                 LABEL bar from-dockerfile2`))
5844736c
 	res = inspectFieldJSON(c, name, "Config.Labels")
 	if res != expected {
 		c.Fatalf("Labels %s, expected %s", res, expected)
 	}
 
 	// Command line option without a value set (--label foo, --label bar=)
 	// will be treated as --label foo="", --label bar=""
 	name = "scratchy2"
 	expected = `{"bar":"","foo":""}`
50c4475d
 	buildImageSuccessfully(c, name, cli.WithFlags("--label", "foo", "--label", "bar="),
 		build.WithDockerfile(`FROM `+minimalBaseImage()+`
c778f4b9
                 LABEL foo=from-dockerfile`))
5844736c
 	res = inspectFieldJSON(c, name, "Config.Labels")
 	if res != expected {
 		c.Fatalf("Labels %s, expected %s", res, expected)
 	}
 
 	// Command line option without a value set (--label foo, --label bar=)
 	// will be treated as --label foo="", --label bar=""
 	// This time is for inherited images
 	name = "new2"
 	expected = `{"bar":"","foo":""}`
50c4475d
 	buildImageSuccessfully(c, name, cli.WithFlags("--label", "foo=", "--label", "bar"),
 		build.WithDockerfile(`FROM from
c778f4b9
                 LABEL bar from-dockerfile2`))
5844736c
 	res = inspectFieldJSON(c, name, "Config.Labels")
 	if res != expected {
 		c.Fatalf("Labels %s, expected %s", res, expected)
 	}
 
 	// Command line option labels with only `FROM`
 	name = "scratchy"
 	expected = `{"bar":"from-flag","foo":"from-flag"}`
50c4475d
 	buildImageSuccessfully(c, name, cli.WithFlags("--label", "foo=from-flag", "--label", "bar=from-flag"),
 		build.WithDockerfile(`FROM `+minimalBaseImage()))
5844736c
 	res = inspectFieldJSON(c, name, "Config.Labels")
 	if res != expected {
 		c.Fatalf("Labels %s, expected %s", res, expected)
 	}
 
28a9a7de
 	// Command line option labels with env var
 	name = "scratchz"
 	expected = `{"bar":"$PATH"}`
50c4475d
 	buildImageSuccessfully(c, name, cli.WithFlags("--label", "bar=$PATH"),
 		build.WithDockerfile(`FROM `+minimalBaseImage()))
28a9a7de
 	res = inspectFieldJSON(c, name, "Config.Labels")
5844736c
 	if res != expected {
 		c.Fatalf("Labels %s, expected %s", res, expected)
 	}
 }
d96e36cb
 
 // Test case for #22855
 func (s *DockerSuite) TestBuildDeleteCommittedFile(c *check.C) {
 	name := "test-delete-committed-file"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
d96e36cb
 		RUN echo test > file
 		RUN test -e file
 		RUN rm file
c778f4b9
 		RUN sh -c "! test -e file"`))
d96e36cb
 }
8913dace
 
 // #20083
 func (s *DockerSuite) TestBuildDockerignoreComment(c *check.C) {
d75aaa2c
 	// TODO Windows: Figure out why this test is flakey on TP5. If you add
 	// something like RUN sleep 5, or even RUN ls /tmp after the ADD line,
 	// it is more reliable, but that's not a good fix.
 	testRequires(c, DaemonIsLinux)
 
8913dace
 	name := "testbuilddockerignorecleanpaths"
 	dockerfile := `
         FROM busybox
         ADD . /tmp/
         RUN sh -c "(ls -la /tmp/#1)"
         RUN sh -c "(! ls -la /tmp/#2)"
         RUN sh -c "(! ls /tmp/foo) && (! ls /tmp/foo2) && (ls /tmp/dir1/foo)"`
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", dockerfile),
 		build.WithFile("foo", "foo"),
 		build.WithFile("foo2", "foo2"),
 		build.WithFile("dir1/foo", "foo in dir1"),
 		build.WithFile("#1", "# file 1"),
 		build.WithFile("#2", "# file 2"),
 		build.WithFile(".dockerignore", `# Visual C++ cache files
8913dace
 # because we have git ;-)
 # The above comment is from #20083
 foo
 #dir1/foo
 foo2
 # The following is considered as comment as # is at the beginning
 #1
 # The following is not considered as comment as # is not at the beginning
   #2
c778f4b9
 `)))
8913dace
 }
678c80f9
 
 // Test case for #23221
 func (s *DockerSuite) TestBuildWithUTF8BOM(c *check.C) {
 	name := "test-with-utf8-bom"
 	dockerfile := []byte(`FROM busybox`)
 	bomDockerfile := append([]byte{0xEF, 0xBB, 0xBF}, dockerfile...)
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", string(bomDockerfile)),
c778f4b9
 	))
678c80f9
 }
ea86320f
 
 // Test case for UTF-8 BOM in .dockerignore, related to #23221
 func (s *DockerSuite) TestBuildWithUTF8BOMDockerignore(c *check.C) {
 	name := "test-with-utf8-bom-dockerignore"
 	dockerfile := `
         FROM busybox
 		ADD . /tmp/
 		RUN ls -la /tmp
 		RUN sh -c "! ls /tmp/Dockerfile"
 		RUN ls /tmp/.dockerignore`
 	dockerignore := []byte("./Dockerfile\n")
 	bomDockerignore := append([]byte{0xEF, 0xBB, 0xBF}, dockerignore...)
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", dockerfile),
 		build.WithFile(".dockerignore", string(bomDockerignore)),
c778f4b9
 	))
ea86320f
 }
b18ae8c9
 
 // #22489 Shell test to confirm config gets updated correctly
 func (s *DockerSuite) TestBuildShellUpdatesConfig(c *check.C) {
 	name := "testbuildshellupdatesconfig"
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
c778f4b9
         SHELL ["foo", "-bar"]`))
b18ae8c9
 	expected := `["foo","-bar","#(nop) ","SHELL [foo -bar]"]`
 	res := inspectFieldJSON(c, name, "ContainerConfig.Cmd")
 	if res != expected {
 		c.Fatalf("%s, expected %s", res, expected)
 	}
 	res = inspectFieldJSON(c, name, "ContainerConfig.Shell")
 	if res != `["foo","-bar"]` {
 		c.Fatalf(`%s, expected ["foo","-bar"]`, res)
 	}
 }
 
 // #22489 Changing the shell multiple times and CMD after.
 func (s *DockerSuite) TestBuildShellMultiple(c *check.C) {
 	name := "testbuildshellmultiple"
 
50c4475d
 	result := buildImage(name, build.WithDockerfile(`FROM busybox
b18ae8c9
 		RUN echo defaultshell
 		SHELL ["echo"]
 		RUN echoshell
 		SHELL ["ls"]
 		RUN -l
c778f4b9
 		CMD -l`))
 	result.Assert(c, icmd.Success)
b18ae8c9
 
 	// Must contain 'defaultshell' twice
c778f4b9
 	if len(strings.Split(result.Combined(), "defaultshell")) != 3 {
 		c.Fatalf("defaultshell should have appeared twice in %s", result.Combined())
b18ae8c9
 	}
 
 	// Must contain 'echoshell' twice
c778f4b9
 	if len(strings.Split(result.Combined(), "echoshell")) != 3 {
 		c.Fatalf("echoshell should have appeared twice in %s", result.Combined())
b18ae8c9
 	}
 
 	// Must contain "total " (part of ls -l)
c778f4b9
 	if !strings.Contains(result.Combined(), "total ") {
 		c.Fatalf("%s should have contained 'total '", result.Combined())
b18ae8c9
 	}
 
 	// A container started from the image uses the shell-form CMD.
 	// Last shell is ls. CMD is -l. So should contain 'total '.
 	outrun, _ := dockerCmd(c, "run", "--rm", name)
 	if !strings.Contains(outrun, "total ") {
 		c.Fatalf("Expected started container to run ls -l. %s", outrun)
 	}
 }
 
 // #22489. Changed SHELL with ENTRYPOINT
 func (s *DockerSuite) TestBuildShellEntrypoint(c *check.C) {
 	name := "testbuildshellentrypoint"
 
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
b18ae8c9
 		SHELL ["ls"]
c778f4b9
 		ENTRYPOINT -l`))
b18ae8c9
 	// A container started from the image uses the shell-form ENTRYPOINT.
 	// Shell is ls. ENTRYPOINT is -l. So should contain 'total '.
 	outrun, _ := dockerCmd(c, "run", "--rm", name)
 	if !strings.Contains(outrun, "total ") {
 		c.Fatalf("Expected started container to run ls -l. %s", outrun)
 	}
 }
 
 // #22489 Shell test to confirm shell is inherited in a subsequent build
 func (s *DockerSuite) TestBuildShellInherited(c *check.C) {
 	name1 := "testbuildshellinherited1"
50c4475d
 	buildImageSuccessfully(c, name1, build.WithDockerfile(`FROM busybox
c778f4b9
         SHELL ["ls"]`))
b18ae8c9
 	name2 := "testbuildshellinherited2"
50c4475d
 	buildImage(name2, build.WithDockerfile(`FROM `+name1+`
c778f4b9
         RUN -l`)).Assert(c, icmd.Expected{
 		// ls -l has "total " followed by some number in it, ls without -l does not.
 		Out: "total ",
 	})
b18ae8c9
 }
 
 // #22489 Shell test to confirm non-JSON doesn't work
 func (s *DockerSuite) TestBuildShellNotJSON(c *check.C) {
 	name := "testbuildshellnotjson"
 
50c4475d
 	buildImage(name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
b18ae8c9
         sHeLl exec -form`, // Casing explicit to ensure error is upper-cased.
c778f4b9
 	)).Assert(c, icmd.Expected{
 		ExitCode: 1,
 		Err:      "SHELL requires the arguments to be in JSON form",
 	})
b18ae8c9
 }
 
 // #22489 Windows shell test to confirm native is powershell if executing a PS command
 // This would error if the default shell were still cmd.
 func (s *DockerSuite) TestBuildShellWindowsPowershell(c *check.C) {
 	testRequires(c, DaemonIsWindows)
 	name := "testbuildshellpowershell"
50c4475d
 	buildImage(name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
b18ae8c9
         SHELL ["powershell", "-command"]
c778f4b9
 		RUN Write-Host John`)).Assert(c, icmd.Expected{
 		Out: "\nJohn\n",
 	})
b18ae8c9
 }
d05d0211
 
91278184
 // Verify that escape is being correctly applied to words when escape directive is not \.
 // Tests WORKDIR, ADD
 func (s *DockerSuite) TestBuildEscapeNotBackslashWordTest(c *check.C) {
 	testRequires(c, DaemonIsWindows)
 	name := "testbuildescapenotbackslashwordtesta"
50c4475d
 	buildImage(name, build.WithDockerfile(`# escape= `+"`"+`
91278184
 		FROM `+minimalBaseImage()+`
         WORKDIR c:\windows
c778f4b9
 		RUN dir /w`)).Assert(c, icmd.Expected{
 		Out: "[System32]",
 	})
91278184
 
 	name = "testbuildescapenotbackslashwordtestb"
50c4475d
 	buildImage(name, build.WithDockerfile(`# escape= `+"`"+`
91278184
 		FROM `+minimalBaseImage()+`
 		SHELL ["powershell.exe"]
         WORKDIR c:\foo
 		ADD Dockerfile c:\foo\
c778f4b9
 		RUN dir Dockerfile`)).Assert(c, icmd.Expected{
 		Out: "-a----",
 	})
91278184
 }
 
d05d0211
 // #22868. Make sure shell-form CMD is marked as escaped in the config of the image
 func (s *DockerSuite) TestBuildCmdShellArgsEscaped(c *check.C) {
 	testRequires(c, DaemonIsWindows)
 	name := "testbuildcmdshellescaped"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`
d05d0211
   FROM `+minimalBaseImage()+`
2dba96ca
   CMD "ipconfig"
c778f4b9
   `))
d05d0211
 	res := inspectFieldJSON(c, name, "Config.ArgsEscaped")
 	if res != "true" {
 		c.Fatalf("CMD did not update Config.ArgsEscaped on image: %v", res)
 	}
 	dockerCmd(c, "run", "--name", "inspectme", name)
 	dockerCmd(c, "wait", "inspectme")
 	res = inspectFieldJSON(c, name, "Config.Cmd")
 
2dba96ca
 	if res != `["cmd","/S","/C","\"ipconfig\""]` {
d05d0211
 		c.Fatalf("CMD was not escaped Config.Cmd: got %v", res)
 	}
 }
35418c14
 
 // Test case for #24912.
 func (s *DockerSuite) TestBuildStepsWithProgress(c *check.C) {
 	name := "testbuildstepswithprogress"
 	totalRun := 5
50c4475d
 	result := buildImage(name, build.WithDockerfile("FROM busybox\n"+strings.Repeat("RUN echo foo\n", totalRun)))
c778f4b9
 	result.Assert(c, icmd.Success)
 	c.Assert(result.Combined(), checker.Contains, fmt.Sprintf("Step 1/%d : FROM busybox", 1+totalRun))
35418c14
 	for i := 2; i <= 1+totalRun; i++ {
c778f4b9
 		c.Assert(result.Combined(), checker.Contains, fmt.Sprintf("Step %d/%d : RUN echo foo", i, 1+totalRun))
35418c14
 	}
 }
c8dc2b15
 
 func (s *DockerSuite) TestBuildWithFailure(c *check.C) {
 	name := "testbuildwithfailure"
 
 	// First test case can only detect `nobody` in runtime so all steps will show up
c778f4b9
 	dockerfile := "FROM busybox\nRUN nobody"
50c4475d
 	result := buildImage(name, build.WithDockerfile(dockerfile))
c778f4b9
 	c.Assert(result.Error, checker.NotNil)
 	c.Assert(result.Stdout(), checker.Contains, "Step 1/2 : FROM busybox")
 	c.Assert(result.Stdout(), checker.Contains, "Step 2/2 : RUN nobody")
c8dc2b15
 
 	// Second test case `FFOM` should have been detected before build runs so no steps
c778f4b9
 	dockerfile = "FFOM nobody\nRUN nobody"
50c4475d
 	result = buildImage(name, build.WithDockerfile(dockerfile))
c778f4b9
 	c.Assert(result.Error, checker.NotNil)
 	c.Assert(result.Stdout(), checker.Not(checker.Contains), "Step 1/2 : FROM busybox")
 	c.Assert(result.Stdout(), checker.Not(checker.Contains), "Step 2/2 : RUN nobody")
c8dc2b15
 }
4b8e680b
 
1cf4b2b8
 func (s *DockerSuite) TestBuildCacheFromEqualDiffIDsLength(c *check.C) {
 	dockerfile := `
 		FROM busybox
 		RUN echo "test"
 		ENTRYPOINT ["sh"]`
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(dockerfile),
 		fakecontext.WithFiles(map[string]string{
 			"Dockerfile": dockerfile,
 		}))
1cf4b2b8
 	defer ctx.Close()
 
56fb4653
 	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
1cf4b2b8
 	id1 := getIDByName(c, "build1")
 
 	// rebuild with cache-from
56fb4653
 	result := cli.BuildCmd(c, "build2", cli.WithFlags("--cache-from=build1"), build.WithExternalBuildContext(ctx))
1cf4b2b8
 	id2 := getIDByName(c, "build2")
 	c.Assert(id1, checker.Equals, id2)
 	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 2)
 }
 
4b8e680b
 func (s *DockerSuite) TestBuildCacheFrom(c *check.C) {
 	testRequires(c, DaemonIsLinux) // All tests that do save are skipped in windows
 	dockerfile := `
 		FROM busybox
 		ENV FOO=bar
 		ADD baz /
 		RUN touch bax`
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(dockerfile),
 		fakecontext.WithFiles(map[string]string{
 			"Dockerfile": dockerfile,
 			"baz":        "baz",
 		}))
4b8e680b
 	defer ctx.Close()
 
56fb4653
 	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
c10f6ef4
 	id1 := getIDByName(c, "build1")
4b8e680b
 
 	// rebuild with cache-from
56fb4653
 	result := cli.BuildCmd(c, "build2", cli.WithFlags("--cache-from=build1"), build.WithExternalBuildContext(ctx))
c10f6ef4
 	id2 := getIDByName(c, "build2")
4b8e680b
 	c.Assert(id1, checker.Equals, id2)
c10f6ef4
 	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 3)
56fb4653
 	cli.DockerCmd(c, "rmi", "build2")
4b8e680b
 
 	// no cache match with unknown source
56fb4653
 	result = cli.BuildCmd(c, "build2", cli.WithFlags("--cache-from=nosuchtag"), build.WithExternalBuildContext(ctx))
c10f6ef4
 	id2 = getIDByName(c, "build2")
4b8e680b
 	c.Assert(id1, checker.Not(checker.Equals), id2)
c10f6ef4
 	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 0)
56fb4653
 	cli.DockerCmd(c, "rmi", "build2")
4b8e680b
 
 	// clear parent images
 	tempDir, err := ioutil.TempDir("", "test-build-cache-from-")
 	if err != nil {
 		c.Fatalf("failed to create temporary directory: %s", tempDir)
 	}
 	defer os.RemoveAll(tempDir)
 	tempFile := filepath.Join(tempDir, "img.tar")
56fb4653
 	cli.DockerCmd(c, "save", "-o", tempFile, "build1")
 	cli.DockerCmd(c, "rmi", "build1")
 	cli.DockerCmd(c, "load", "-i", tempFile)
 	parentID := cli.DockerCmd(c, "inspect", "-f", "{{.Parent}}", "build1").Combined()
4b8e680b
 	c.Assert(strings.TrimSpace(parentID), checker.Equals, "")
 
 	// cache still applies without parents
56fb4653
 	result = cli.BuildCmd(c, "build2", cli.WithFlags("--cache-from=build1"), build.WithExternalBuildContext(ctx))
c10f6ef4
 	id2 = getIDByName(c, "build2")
4b8e680b
 	c.Assert(id1, checker.Equals, id2)
c10f6ef4
 	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 3)
56fb4653
 	history1 := cli.DockerCmd(c, "history", "-q", "build2").Combined()
4b8e680b
 
 	// Retry, no new intermediate images
56fb4653
 	result = cli.BuildCmd(c, "build3", cli.WithFlags("--cache-from=build1"), build.WithExternalBuildContext(ctx))
c10f6ef4
 	id3 := getIDByName(c, "build3")
4b8e680b
 	c.Assert(id1, checker.Equals, id3)
c10f6ef4
 	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 3)
56fb4653
 	history2 := cli.DockerCmd(c, "history", "-q", "build3").Combined()
4b8e680b
 
 	c.Assert(history1, checker.Equals, history2)
56fb4653
 	cli.DockerCmd(c, "rmi", "build2")
 	cli.DockerCmd(c, "rmi", "build3")
 	cli.DockerCmd(c, "rmi", "build1")
 	cli.DockerCmd(c, "load", "-i", tempFile)
4b8e680b
 
 	// Modify file, everything up to last command and layers are reused
 	dockerfile = `
 		FROM busybox
 		ENV FOO=bar
 		ADD baz /
 		RUN touch newfile`
 	err = ioutil.WriteFile(filepath.Join(ctx.Dir, "Dockerfile"), []byte(dockerfile), 0644)
 	c.Assert(err, checker.IsNil)
 
56fb4653
 	result = cli.BuildCmd(c, "build2", cli.WithFlags("--cache-from=build1"), build.WithExternalBuildContext(ctx))
c10f6ef4
 	id2 = getIDByName(c, "build2")
4b8e680b
 	c.Assert(id1, checker.Not(checker.Equals), id2)
c10f6ef4
 	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 2)
4b8e680b
 
56fb4653
 	layers1Str := cli.DockerCmd(c, "inspect", "-f", "{{json .RootFS.Layers}}", "build1").Combined()
 	layers2Str := cli.DockerCmd(c, "inspect", "-f", "{{json .RootFS.Layers}}", "build2").Combined()
4b8e680b
 
 	var layers1 []string
 	var layers2 []string
 	c.Assert(json.Unmarshal([]byte(layers1Str), &layers1), checker.IsNil)
 	c.Assert(json.Unmarshal([]byte(layers2Str), &layers2), checker.IsNil)
 
 	c.Assert(len(layers1), checker.Equals, len(layers2))
 	for i := 0; i < len(layers1)-1; i++ {
 		c.Assert(layers1[i], checker.Equals, layers2[i])
 	}
 	c.Assert(layers1[len(layers1)-1], checker.Not(checker.Equals), layers2[len(layers1)-1])
 }
e3b48fca
 
e90b7c06
 func (s *DockerSuite) TestBuildMultiStageCache(c *check.C) {
acad5992
 	testRequires(c, DaemonIsLinux) // All tests that do save are skipped in windows
 	dockerfile := `
 		FROM busybox
 		ADD baz /
 		FROM busybox
     ADD baz /`
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(dockerfile),
 		fakecontext.WithFiles(map[string]string{
 			"Dockerfile": dockerfile,
 			"baz":        "baz",
 		}))
acad5992
 	defer ctx.Close()
 
56fb4653
 	result := cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
acad5992
 	// second part of dockerfile was a repeat of first so should be cached
 	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 1)
 
56fb4653
 	result = cli.BuildCmd(c, "build2", cli.WithFlags("--cache-from=build1"), build.WithExternalBuildContext(ctx))
acad5992
 	// now both parts of dockerfile should be cached
 	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 2)
 }
 
e3b48fca
 func (s *DockerSuite) TestBuildNetNone(c *check.C) {
 	testRequires(c, DaemonIsLinux)
 	name := "testbuildnetnone"
50c4475d
 	buildImage(name, cli.WithFlags("--network=none"), build.WithDockerfile(`
e3b48fca
   FROM busybox
   RUN ping -c 1 8.8.8.8
c778f4b9
   `)).Assert(c, icmd.Expected{
 		ExitCode: 1,
 		Out:      "unreachable",
 	})
e3b48fca
 }
 
 func (s *DockerSuite) TestBuildNetContainer(c *check.C) {
 	testRequires(c, DaemonIsLinux)
 
 	id, _ := dockerCmd(c, "run", "--hostname", "foobar", "-d", "busybox", "nc", "-ll", "-p", "1234", "-e", "hostname")
 
 	name := "testbuildnetcontainer"
50c4475d
 	buildImageSuccessfully(c, name, cli.WithFlags("--network=container:"+strings.TrimSpace(id)),
 		build.WithDockerfile(`
e3b48fca
   FROM busybox
   RUN nc localhost 1234 > /otherhost
c778f4b9
   `))
e3b48fca
 
 	host, _ := dockerCmd(c, "run", "testbuildnetcontainer", "cat", "/otherhost")
 	c.Assert(strings.TrimSpace(host), check.Equals, "foobar")
 }
3e1b539e
 
7a962e45
 func (s *DockerSuite) TestBuildWithExtraHost(c *check.C) {
 	testRequires(c, DaemonIsLinux)
 
 	name := "testbuildwithextrahost"
 	buildImageSuccessfully(c, name,
50c4475d
 		cli.WithFlags(
7a962e45
 			"--add-host", "foo:127.0.0.1",
 			"--add-host", "bar:127.0.0.1",
 		),
50c4475d
 		build.WithDockerfile(`
7a962e45
   FROM busybox
   RUN ping -c 1 foo
   RUN ping -c 1 bar
   `))
 }
 
 func (s *DockerSuite) TestBuildWithExtraHostInvalidFormat(c *check.C) {
 	testRequires(c, DaemonIsLinux)
 	dockerfile := `
 		FROM busybox
 		RUN ping -c 1 foo`
 
 	testCases := []struct {
 		testName   string
 		dockerfile string
 		buildFlag  string
 	}{
 		{"extra_host_missing_ip", dockerfile, "--add-host=foo"},
39bcaee4
 		{"extra_host_missing_ip_with_delimiter", dockerfile, "--add-host=foo:"},
7a962e45
 		{"extra_host_missing_hostname", dockerfile, "--add-host=:127.0.0.1"},
 		{"extra_host_invalid_ipv4", dockerfile, "--add-host=foo:101.10.2"},
 		{"extra_host_invalid_ipv6", dockerfile, "--add-host=foo:2001::1::3F"},
 	}
 
 	for _, tc := range testCases {
50c4475d
 		result := buildImage(tc.testName, cli.WithFlags(tc.buildFlag), build.WithDockerfile(tc.dockerfile))
7a962e45
 		result.Assert(c, icmd.Expected{
 			ExitCode: 125,
 		})
 	}
 
 }
 
362369b4
 func (s *DockerSuite) TestBuildSquashParent(c *check.C) {
 	testRequires(c, ExperimentalDaemon)
 	dockerFile := `
 		FROM busybox
 		RUN echo hello > /hello
 		RUN echo world >> /hello
 		RUN echo hello > /remove_me
 		ENV HELLO world
 		RUN rm /remove_me
 		`
 	// build and get the ID that we can use later for history comparison
c778f4b9
 	name := "test"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(dockerFile))
c10f6ef4
 	origID := getIDByName(c, name)
362369b4
 
 	// build with squash
50c4475d
 	buildImageSuccessfully(c, name, cli.WithFlags("--squash"), build.WithDockerfile(dockerFile))
c10f6ef4
 	id := getIDByName(c, name)
362369b4
 
 	out, _ := dockerCmd(c, "run", "--rm", id, "/bin/sh", "-c", "cat /hello")
 	c.Assert(strings.TrimSpace(out), checker.Equals, "hello\nworld")
 
 	dockerCmd(c, "run", "--rm", id, "/bin/sh", "-c", "[ ! -f /remove_me ]")
 	dockerCmd(c, "run", "--rm", id, "/bin/sh", "-c", `[ "$(echo $HELLO)" == "world" ]`)
 
 	// make sure the ID produced is the ID of the tag we specified
ecbb0e62
 	inspectID := inspectImage(c, "test", ".ID")
362369b4
 	c.Assert(inspectID, checker.Equals, id)
 
 	origHistory, _ := dockerCmd(c, "history", origID)
 	testHistory, _ := dockerCmd(c, "history", "test")
 
 	splitOrigHistory := strings.Split(strings.TrimSpace(origHistory), "\n")
 	splitTestHistory := strings.Split(strings.TrimSpace(testHistory), "\n")
 	c.Assert(len(splitTestHistory), checker.Equals, len(splitOrigHistory)+1)
 
ecbb0e62
 	out = inspectImage(c, id, "len .RootFS.Layers")
1ecd8ed5
 	c.Assert(strings.TrimSpace(out), checker.Equals, "2")
362369b4
 }
eaf0b570
 
 func (s *DockerSuite) TestBuildContChar(c *check.C) {
 	name := "testbuildcontchar"
 
50c4475d
 	buildImage(name, build.WithDockerfile(`FROM busybox\`)).Assert(c, icmd.Expected{
c778f4b9
 		Out: "Step 1/1 : FROM busybox",
 	})
eaf0b570
 
50c4475d
 	result := buildImage(name, build.WithDockerfile(`FROM busybox
c778f4b9
 		 RUN echo hi \`))
 	result.Assert(c, icmd.Success)
 	c.Assert(result.Combined(), checker.Contains, "Step 1/2 : FROM busybox")
 	c.Assert(result.Combined(), checker.Contains, "Step 2/2 : RUN echo hi\n")
eaf0b570
 
50c4475d
 	result = buildImage(name, build.WithDockerfile(`FROM busybox
c778f4b9
 		 RUN echo hi \\`))
 	result.Assert(c, icmd.Success)
 	c.Assert(result.Combined(), checker.Contains, "Step 1/2 : FROM busybox")
 	c.Assert(result.Combined(), checker.Contains, "Step 2/2 : RUN echo hi \\\n")
eaf0b570
 
50c4475d
 	result = buildImage(name, build.WithDockerfile(`FROM busybox
c778f4b9
 		 RUN echo hi \\\`))
 	result.Assert(c, icmd.Success)
 	c.Assert(result.Combined(), checker.Contains, "Step 1/2 : FROM busybox")
 	c.Assert(result.Combined(), checker.Contains, "Step 2/2 : RUN echo hi \\\\\n")
eaf0b570
 }
64b43ed5
 
e90b7c06
 func (s *DockerSuite) TestBuildMultiStageCopyFromSyntax(c *check.C) {
f95f5828
 	dockerfile := `
87512bbc
 		FROM busybox AS first
f95f5828
 		COPY foo bar
51360965
 
f95f5828
 		FROM busybox
51360965
 		%s
 		COPY baz baz
 		RUN echo mno > baz/cc
 
f95f5828
 		FROM busybox
51360965
 		COPY bar /
 		COPY --from=1 baz sub/
 		COPY --from=0 bar baz
 		COPY --from=first bar bay`
87512bbc
 
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(fmt.Sprintf(dockerfile, "")),
 		fakecontext.WithFiles(map[string]string{
 			"foo":    "abc",
 			"bar":    "def",
 			"baz/aa": "ghi",
 			"baz/bb": "jkl",
 		}))
f95f5828
 	defer ctx.Close()
 
56fb4653
 	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
f95f5828
 
51360965
 	cli.DockerCmd(c, "run", "build1", "cat", "bar").Assert(c, icmd.Expected{Out: "def"})
 	cli.DockerCmd(c, "run", "build1", "cat", "sub/aa").Assert(c, icmd.Expected{Out: "ghi"})
 	cli.DockerCmd(c, "run", "build1", "cat", "sub/cc").Assert(c, icmd.Expected{Out: "mno"})
 	cli.DockerCmd(c, "run", "build1", "cat", "baz").Assert(c, icmd.Expected{Out: "abc"})
 	cli.DockerCmd(c, "run", "build1", "cat", "bay").Assert(c, icmd.Expected{Out: "abc"})
f95f5828
 
56fb4653
 	result := cli.BuildCmd(c, "build2", build.WithExternalBuildContext(ctx))
f95f5828
 
 	// all commands should be cached
 	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 7)
51360965
 	c.Assert(getIDByName(c, "build1"), checker.Equals, getIDByName(c, "build2"))
f95f5828
 
 	err := ioutil.WriteFile(filepath.Join(ctx.Dir, "Dockerfile"), []byte(fmt.Sprintf(dockerfile, "COPY baz/aa foo")), 0644)
 	c.Assert(err, checker.IsNil)
 
 	// changing file in parent block should not affect last block
56fb4653
 	result = cli.BuildCmd(c, "build3", build.WithExternalBuildContext(ctx))
f95f5828
 	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 5)
 
 	err = ioutil.WriteFile(filepath.Join(ctx.Dir, "foo"), []byte("pqr"), 0644)
 	c.Assert(err, checker.IsNil)
 
 	// changing file in parent block should affect both first and last block
56fb4653
 	result = cli.BuildCmd(c, "build4", build.WithExternalBuildContext(ctx))
f95f5828
 	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 5)
 
51360965
 	cli.DockerCmd(c, "run", "build4", "cat", "bay").Assert(c, icmd.Expected{Out: "pqr"})
 	cli.DockerCmd(c, "run", "build4", "cat", "baz").Assert(c, icmd.Expected{Out: "pqr"})
f95f5828
 }
 
e90b7c06
 func (s *DockerSuite) TestBuildMultiStageCopyFromErrors(c *check.C) {
56fb4653
 	testCases := []struct {
 		dockerfile    string
 		expectedError string
 	}{
 		{
 			dockerfile: `
f95f5828
 		FROM busybox
56fb4653
 		COPY --from=foo foo bar`,
 			expectedError: "invalid from flag value foo",
 		},
 		{
 			dockerfile: `
f95f5828
 		FROM busybox
56fb4653
 		COPY --from=0 foo bar`,
ab3a037a
 			expectedError: "invalid from flag value 0: refers to current build stage",
56fb4653
 		},
 		{
 			dockerfile: `
87512bbc
 		FROM busybox AS foo
56fb4653
 		COPY --from=bar foo bar`,
 			expectedError: "invalid from flag value bar",
 		},
 		{
 			dockerfile: `
87512bbc
 		FROM busybox AS 1
56fb4653
 		COPY --from=1 foo bar`,
 			expectedError: "invalid name for build stage",
 		},
 	}
87512bbc
 
56fb4653
 	for _, tc := range testCases {
 		ctx := fakecontext.New(c, "",
 			fakecontext.WithDockerfile(tc.dockerfile),
 			fakecontext.WithFiles(map[string]string{
 				"foo": "abc",
 			}))
87512bbc
 
56fb4653
 		cli.Docker(cli.Build("build1"), build.WithExternalBuildContext(ctx)).Assert(c, icmd.Expected{
 			ExitCode: 1,
 			Err:      tc.expectedError,
 		})
 
 		ctx.Close()
 	}
f95f5828
 }
 
e90b7c06
 func (s *DockerSuite) TestBuildMultiStageMultipleBuilds(c *check.C) {
f95f5828
 	dockerfile := `
 		FROM busybox
 		COPY foo bar`
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(dockerfile),
 		fakecontext.WithFiles(map[string]string{
 			"foo": "abc",
 		}))
f95f5828
 	defer ctx.Close()
 
56fb4653
 	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
f95f5828
 
 	dockerfile = `
87512bbc
 		FROM build1:latest AS foo
f95f5828
     FROM busybox
87512bbc
 		COPY --from=foo bar /
f95f5828
 		COPY foo /`
56fb4653
 	ctx = fakecontext.New(c, "",
 		fakecontext.WithDockerfile(dockerfile),
 		fakecontext.WithFiles(map[string]string{
 			"foo": "def",
 		}))
f95f5828
 	defer ctx.Close()
 
56fb4653
 	cli.BuildCmd(c, "build2", build.WithExternalBuildContext(ctx))
f95f5828
 
56fb4653
 	out := cli.DockerCmd(c, "run", "build2", "cat", "bar").Combined()
f95f5828
 	c.Assert(strings.TrimSpace(out), check.Equals, "abc")
56fb4653
 	out = cli.DockerCmd(c, "run", "build2", "cat", "foo").Combined()
f95f5828
 	c.Assert(strings.TrimSpace(out), check.Equals, "def")
 }
 
e90b7c06
 func (s *DockerSuite) TestBuildMultiStageImplicitFrom(c *check.C) {
73b4b8ed
 	dockerfile := `
 		FROM busybox
 		COPY --from=busybox /etc/passwd /mypasswd
 		RUN cmp /etc/passwd /mypasswd`
 
 	if DaemonIsWindows() {
 		dockerfile = `
 			FROM busybox
 			COPY --from=busybox License.txt foo`
 	}
 
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(dockerfile),
 	)
73b4b8ed
 	defer ctx.Close()
 
56fb4653
 	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
73b4b8ed
 
 	if DaemonIsWindows() {
56fb4653
 		out := cli.DockerCmd(c, "run", "build1", "cat", "License.txt").Combined()
73b4b8ed
 		c.Assert(len(out), checker.GreaterThan, 10)
56fb4653
 		out2 := cli.DockerCmd(c, "run", "build1", "cat", "foo").Combined()
73b4b8ed
 		c.Assert(out, check.Equals, out2)
 	}
 }
 
e90b7c06
 func (s *DockerRegistrySuite) TestBuildMultiStageImplicitPull(c *check.C) {
672ea30a
 	repoName := fmt.Sprintf("%v/dockercli/testf", privateRegistryURL)
 
 	dockerfile := `
 		FROM busybox
 		COPY foo bar`
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(dockerfile),
 		fakecontext.WithFiles(map[string]string{
 			"foo": "abc",
 		}))
672ea30a
 	defer ctx.Close()
 
56fb4653
 	cli.BuildCmd(c, repoName, build.WithExternalBuildContext(ctx))
672ea30a
 
56fb4653
 	cli.DockerCmd(c, "push", repoName)
 	cli.DockerCmd(c, "rmi", repoName)
672ea30a
 
 	dockerfile = `
 		FROM busybox
 		COPY --from=%s bar baz`
 
56fb4653
 	ctx = fakecontext.New(c, "", fakecontext.WithDockerfile(fmt.Sprintf(dockerfile, repoName)))
672ea30a
 	defer ctx.Close()
 
56fb4653
 	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
672ea30a
 
56fb4653
 	cli.Docker(cli.Args("run", "build1", "cat", "baz")).Assert(c, icmd.Expected{Out: "abc"})
672ea30a
 }
 
e90b7c06
 func (s *DockerSuite) TestBuildMultiStageNameVariants(c *check.C) {
672ea30a
 	dockerfile := `
 		FROM busybox as foo
 		COPY foo /
 		FROM foo as foo1
 		RUN echo 1 >> foo
 		FROM foo as foO2
 		RUN echo 2 >> foo
 		FROM foo
 		COPY --from=foo1 foo f1
 		COPY --from=FOo2 foo f2
e90b7c06
 		` // foo2 case also tests that names are case insensitive
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(dockerfile),
 		fakecontext.WithFiles(map[string]string{
 			"foo": "bar",
 		}))
672ea30a
 	defer ctx.Close()
 
56fb4653
 	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
 	cli.Docker(cli.Args("run", "build1", "cat", "foo")).Assert(c, icmd.Expected{Out: "bar"})
 	cli.Docker(cli.Args("run", "build1", "cat", "f1")).Assert(c, icmd.Expected{Out: "bar1"})
 	cli.Docker(cli.Args("run", "build1", "cat", "f2")).Assert(c, icmd.Expected{Out: "bar2"})
672ea30a
 }
 
e90b7c06
 func (s *DockerTrustSuite) TestBuildMultiStageTrusted(c *check.C) {
79ccb347
 	img1 := s.setupTrustedImage(c, "trusted-build1")
 	img2 := s.setupTrustedImage(c, "trusted-build2")
 	dockerFile := fmt.Sprintf(`
 	FROM %s AS build-base
 	RUN echo ok > /foo
 	FROM %s
 	COPY --from=build-base foo bar`, img1, img2)
 
 	name := "testcopyfromtrustedbuild"
 
 	r := buildImage(name, trustedBuild, build.WithDockerfile(dockerFile))
 	r.Assert(c, icmd.Expected{
 		Out: fmt.Sprintf("FROM %s@sha", img1[:len(img1)-7]),
 	})
 	r.Assert(c, icmd.Expected{
 		Out: fmt.Sprintf("FROM %s@sha", img2[:len(img2)-7]),
 	})
 
 	dockerCmdWithResult("run", name, "cat", "bar").Assert(c, icmd.Expected{Out: "ok"})
 }
 
e90b7c06
 func (s *DockerSuite) TestBuildMultiStageMultipleBuildsWindows(c *check.C) {
b0e75888
 	testRequires(c, DaemonIsWindows)
 	dockerfile := `
dfedc9ef
 		FROM ` + testEnv.PlatformDefaults.BaseImage + `
b0e75888
 		COPY foo c:\\bar`
56fb4653
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(dockerfile),
 		fakecontext.WithFiles(map[string]string{
 			"foo": "abc",
 		}))
b0e75888
 	defer ctx.Close()
 
56fb4653
 	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
b0e75888
 
 	dockerfile = `
 		FROM build1:latest
dfedc9ef
     	FROM ` + testEnv.PlatformDefaults.BaseImage + `
b0e75888
 		COPY --from=0 c:\\bar /
 		COPY foo /`
56fb4653
 	ctx = fakecontext.New(c, "",
 		fakecontext.WithDockerfile(dockerfile),
 		fakecontext.WithFiles(map[string]string{
 			"foo": "def",
 		}))
b0e75888
 	defer ctx.Close()
 
56fb4653
 	cli.BuildCmd(c, "build2", build.WithExternalBuildContext(ctx))
b0e75888
 
56fb4653
 	out := cli.DockerCmd(c, "run", "build2", "cmd.exe", "/s", "/c", "type", "c:\\bar").Combined()
b0e75888
 	c.Assert(strings.TrimSpace(out), check.Equals, "abc")
56fb4653
 	out = cli.DockerCmd(c, "run", "build2", "cmd.exe", "/s", "/c", "type", "c:\\foo").Combined()
b0e75888
 	c.Assert(strings.TrimSpace(out), check.Equals, "def")
 }
 
 func (s *DockerSuite) TestBuildCopyFromForbidWindowsSystemPaths(c *check.C) {
 	testRequires(c, DaemonIsWindows)
 	dockerfile := `
dfedc9ef
 		FROM ` + testEnv.PlatformDefaults.BaseImage + `
 		FROM ` + testEnv.PlatformDefaults.BaseImage + `
b0e75888
 		COPY --from=0 %s c:\\oscopy
 		`
 	exp := icmd.Expected{
 		ExitCode: 1,
 		Err:      "copy from c:\\ or c:\\windows is not allowed on windows",
 	}
 	buildImage("testforbidsystempaths1", build.WithDockerfile(fmt.Sprintf(dockerfile, "c:\\\\"))).Assert(c, exp)
 	buildImage("testforbidsystempaths2", build.WithDockerfile(fmt.Sprintf(dockerfile, "C:\\\\"))).Assert(c, exp)
 	buildImage("testforbidsystempaths3", build.WithDockerfile(fmt.Sprintf(dockerfile, "c:\\\\windows"))).Assert(c, exp)
 	buildImage("testforbidsystempaths4", build.WithDockerfile(fmt.Sprintf(dockerfile, "c:\\\\wInDows"))).Assert(c, exp)
 }
 
 func (s *DockerSuite) TestBuildCopyFromForbidWindowsRelativePaths(c *check.C) {
 	testRequires(c, DaemonIsWindows)
 	dockerfile := `
dfedc9ef
 		FROM ` + testEnv.PlatformDefaults.BaseImage + `
 		FROM ` + testEnv.PlatformDefaults.BaseImage + `
b0e75888
 		COPY --from=0 %s c:\\oscopy
 		`
 	exp := icmd.Expected{
 		ExitCode: 1,
 		Err:      "copy from c:\\ or c:\\windows is not allowed on windows",
 	}
 	buildImage("testforbidsystempaths1", build.WithDockerfile(fmt.Sprintf(dockerfile, "c:"))).Assert(c, exp)
 	buildImage("testforbidsystempaths2", build.WithDockerfile(fmt.Sprintf(dockerfile, "."))).Assert(c, exp)
 	buildImage("testforbidsystempaths3", build.WithDockerfile(fmt.Sprintf(dockerfile, "..\\\\"))).Assert(c, exp)
 	buildImage("testforbidsystempaths4", build.WithDockerfile(fmt.Sprintf(dockerfile, ".\\\\windows"))).Assert(c, exp)
 	buildImage("testforbidsystempaths5", build.WithDockerfile(fmt.Sprintf(dockerfile, "\\\\windows"))).Assert(c, exp)
 }
 
 func (s *DockerSuite) TestBuildCopyFromWindowsIsCaseInsensitive(c *check.C) {
 	testRequires(c, DaemonIsWindows)
 	dockerfile := `
dfedc9ef
 		FROM ` + testEnv.PlatformDefaults.BaseImage + `
c7fad9b7
 		COPY foo /
dfedc9ef
 		FROM ` + testEnv.PlatformDefaults.BaseImage + `
b0e75888
 		COPY --from=0 c:\\fOo c:\\copied
 		RUN type c:\\copied
 		`
56fb4653
 	cli.Docker(cli.Build("copyfrom-windows-insensitive"), build.WithBuildContext(c,
 		build.WithFile("Dockerfile", dockerfile),
 		build.WithFile("foo", "hello world"),
 	)).Assert(c, icmd.Expected{
b0e75888
 		ExitCode: 0,
 		Out:      "hello world",
56fb4653
 	})
b0e75888
 }
 
b1922185
 // #33176
e90b7c06
 func (s *DockerSuite) TestBuildMulitStageResetScratch(c *check.C) {
b1922185
 	testRequires(c, DaemonIsLinux)
 
 	dockerfile := `
 		FROM busybox
 		WORKDIR /foo/bar
 		FROM scratch
 		ENV FOO=bar
 		`
 	ctx := fakecontext.New(c, "",
 		fakecontext.WithDockerfile(dockerfile),
 	)
 	defer ctx.Close()
 
 	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
 
 	res := cli.InspectCmd(c, "build1", cli.Format(".Config.WorkingDir")).Combined()
 	c.Assert(strings.TrimSpace(res), checker.Equals, "")
 }
 
33e07f41
 func (s *DockerSuite) TestBuildIntermediateTarget(c *check.C) {
 	dockerfile := `
 		FROM busybox AS build-env
 		CMD ["/dev"]
 		FROM busybox
 		CMD ["/dist"]
 		`
56fb4653
 	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile))
33e07f41
 	defer ctx.Close()
 
56fb4653
 	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx),
33e07f41
 		cli.WithFlags("--target", "build-env"))
 
56fb4653
 	//res := inspectFieldJSON(c, "build1", "Config.Cmd")
 	res := cli.InspectCmd(c, "build1", cli.Format("json .Config.Cmd")).Combined()
 	c.Assert(strings.TrimSpace(res), checker.Equals, `["/dev"]`)
33e07f41
 
56fb4653
 	result := cli.Docker(cli.Build("build1"), build.WithExternalBuildContext(ctx),
33e07f41
 		cli.WithFlags("--target", "nosuchtarget"))
 	result.Assert(c, icmd.Expected{
 		ExitCode: 1,
 		Err:      "failed to reach build target",
 	})
 }
 
64b43ed5
 // TestBuildOpaqueDirectory tests that a build succeeds which
 // creates opaque directories.
 // See https://github.com/docker/docker/issues/25244
 func (s *DockerSuite) TestBuildOpaqueDirectory(c *check.C) {
 	testRequires(c, DaemonIsLinux)
 	dockerFile := `
 		FROM busybox
 		RUN mkdir /dir1 && touch /dir1/f1
 		RUN rm -rf /dir1 && mkdir /dir1 && touch /dir1/f2
 		RUN touch /dir1/f3
 		RUN [ -f /dir1/f2 ]
 		`
 	// Test that build succeeds, last command fails if opaque directory
 	// was not handled correctly
50c4475d
 	buildImageSuccessfully(c, "testopaquedirectory", build.WithDockerfile(dockerFile))
64b43ed5
 }
a3c4ab9b
 
 // Windows test for USER in dockerfile
 func (s *DockerSuite) TestBuildWindowsUser(c *check.C) {
 	testRequires(c, DaemonIsWindows)
 	name := "testbuildwindowsuser"
dfedc9ef
 	buildImage(name, build.WithDockerfile(`FROM `+testEnv.PlatformDefaults.BaseImage+`
a3c4ab9b
 		RUN net user user /add
 		USER user
 		RUN set username
c778f4b9
 		`)).Assert(c, icmd.Expected{
 		Out: "USERNAME=user",
 	})
a3c4ab9b
 }
286ab6d6
 
 // Verifies if COPY file . when WORKDIR is set to a non-existing directory,
 // the directory is created and the file is copied into the directory,
 // as opposed to the file being copied as a file with the name of the
 // directory. Fix for 27545 (found on Windows, but regression good for Linux too).
 // Note 27545 was reverted in 28505, but a new fix was added subsequently in 28514.
 func (s *DockerSuite) TestBuildCopyFileDotWithWorkdir(c *check.C) {
 	name := "testbuildcopyfiledotwithworkdir"
56fb4653
 	buildImageSuccessfully(c, name, build.WithBuildContext(c,
 		build.WithFile("Dockerfile", `FROM busybox
c778f4b9
 WORKDIR /foo
 COPY file .
 RUN ["cat", "/foo/file"]
 `),
56fb4653
 		build.WithFile("file", "content"),
c778f4b9
 	))
286ab6d6
 }
49f392ff
 
 // Case-insensitive environment variables on Windows
 func (s *DockerSuite) TestBuildWindowsEnvCaseInsensitive(c *check.C) {
 	testRequires(c, DaemonIsWindows)
 	name := "testbuildwindowsenvcaseinsensitive"
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(`
dfedc9ef
 		FROM `+testEnv.PlatformDefaults.BaseImage+`
c778f4b9
 		ENV FOO=bar foo=baz
   `))
49f392ff
 	res := inspectFieldJSON(c, name, "Config.Env")
c778f4b9
 	if res != `["foo=baz"]` { // Should not have FOO=bar in it - takes the last one processed. And only one entry as deduped.
49f392ff
 		c.Fatalf("Case insensitive environment variables on Windows failed. Got %s", res)
 	}
 }
08360238
 
 // Test case for 29667
 func (s *DockerSuite) TestBuildWorkdirImageCmd(c *check.C) {
 	image := "testworkdirimagecmd"
50c4475d
 	buildImageSuccessfully(c, image, build.WithDockerfile(`
08360238
 FROM busybox
 WORKDIR /foo/bar
c778f4b9
 `))
 	out, _ := dockerCmd(c, "inspect", "--format", "{{ json .Config.Cmd }}", image)
528a5fd2
 
 	// The Windows busybox image has a blank `cmd`
 	lookingFor := `["sh"]`
18a771a7
 	if testEnv.OSType == "windows" {
528a5fd2
 		lookingFor = "null"
 	}
 	c.Assert(strings.TrimSpace(out), checker.Equals, lookingFor)
08360238
 
 	image = "testworkdirlabelimagecmd"
50c4475d
 	buildImageSuccessfully(c, image, build.WithDockerfile(`
08360238
 FROM busybox
 WORKDIR /foo/bar
 LABEL a=b
c778f4b9
 `))
08360238
 
 	out, _ = dockerCmd(c, "inspect", "--format", "{{ json .Config.Cmd }}", image)
528a5fd2
 	c.Assert(strings.TrimSpace(out), checker.Equals, lookingFor)
08360238
 }
 
bc19388f
 // Test case for 28902/28909
08360238
 func (s *DockerSuite) TestBuildWorkdirCmd(c *check.C) {
 	testRequires(c, DaemonIsLinux)
c778f4b9
 	name := "testbuildworkdircmd"
08360238
 	dockerFile := `
bc19388f
                 FROM busybox
08360238
                 WORKDIR /
                 `
50c4475d
 	buildImageSuccessfully(c, name, build.WithDockerfile(dockerFile))
 	result := buildImage(name, build.WithDockerfile(dockerFile))
c778f4b9
 	result.Assert(c, icmd.Success)
 	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 1)
08360238
 }
8f282cde
 
c778f4b9
 // FIXME(vdemeester) should be a unit test
8f282cde
 func (s *DockerSuite) TestBuildLineErrorOnBuild(c *check.C) {
 	name := "test_build_line_error_onbuild"
50c4475d
 	buildImage(name, build.WithDockerfile(`FROM busybox
8f282cde
   ONBUILD
c778f4b9
   `)).Assert(c, icmd.Expected{
 		ExitCode: 1,
 		Err:      "Dockerfile parse error line 2: ONBUILD requires at least one argument",
 	})
8f282cde
 }
 
c778f4b9
 // FIXME(vdemeester) should be a unit test
c7fad9b7
 func (s *DockerSuite) TestBuildLineErrorUnknownInstruction(c *check.C) {
8f282cde
 	name := "test_build_line_error_unknown_instruction"
c7fad9b7
 	cli.Docker(cli.Build(name), build.WithDockerfile(`FROM busybox
8f282cde
   RUN echo hello world
   NOINSTRUCTION echo ba
   RUN echo hello
   ERROR
c778f4b9
   `)).Assert(c, icmd.Expected{
 		ExitCode: 1,
c7fad9b7
 		Err:      "Dockerfile parse error line 3: unknown instruction: NOINSTRUCTION",
c778f4b9
 	})
8f282cde
 }
 
c778f4b9
 // FIXME(vdemeester) should be a unit test
8f282cde
 func (s *DockerSuite) TestBuildLineErrorWithEmptyLines(c *check.C) {
 	name := "test_build_line_error_with_empty_lines"
c7fad9b7
 	cli.Docker(cli.Build(name), build.WithDockerfile(`
8f282cde
   FROM busybox
 
   RUN echo hello world
 
   NOINSTRUCTION echo ba
 
   CMD ["/bin/init"]
c778f4b9
   `)).Assert(c, icmd.Expected{
 		ExitCode: 1,
c7fad9b7
 		Err:      "Dockerfile parse error line 6: unknown instruction: NOINSTRUCTION",
c778f4b9
 	})
8f282cde
 }
 
c778f4b9
 // FIXME(vdemeester) should be a unit test
8f282cde
 func (s *DockerSuite) TestBuildLineErrorWithComments(c *check.C) {
 	name := "test_build_line_error_with_comments"
c7fad9b7
 	cli.Docker(cli.Build(name), build.WithDockerfile(`FROM busybox
8f282cde
   # This will print hello world
   # and then ba
   RUN echo hello world
c778f4b9
   NOINSTRUCTION echo ba
   `)).Assert(c, icmd.Expected{
 		ExitCode: 1,
c7fad9b7
 		Err:      "Dockerfile parse error line 5: unknown instruction: NOINSTRUCTION",
c778f4b9
 	})
8f282cde
 }
a1fa59ea
 
 // #31957
 func (s *DockerSuite) TestBuildSetCommandWithDefinedShell(c *check.C) {
 	buildImageSuccessfully(c, "build1", build.WithDockerfile(`
 FROM busybox
 SHELL ["/bin/sh", "-c"]
 `))
 	buildImageSuccessfully(c, "build2", build.WithDockerfile(`
 FROM build1
 CMD echo foo
 `))
 
 	out, _ := dockerCmd(c, "inspect", "--format", "{{ json .Config.Cmd }}", "build2")
 	c.Assert(strings.TrimSpace(out), checker.Equals, `["/bin/sh","-c","echo foo"]`)
 }
5894bc1a
 
 func (s *DockerSuite) TestBuildIidFile(c *check.C) {
 	tmpDir, err := ioutil.TempDir("", "TestBuildIidFile")
 	if err != nil {
 		c.Fatal(err)
 	}
 	defer os.RemoveAll(tmpDir)
 	tmpIidFile := filepath.Join(tmpDir, "iid")
 
 	name := "testbuildiidfile"
 	// Use a Dockerfile with multiple stages to ensure we get the last one
 	cli.BuildCmd(c, name,
 		build.WithDockerfile(`FROM `+minimalBaseImage()+` AS stage1
 ENV FOO FOO
 FROM `+minimalBaseImage()+`
 ENV BAR BAZ`),
 		cli.WithFlags("--iidfile", tmpIidFile))
 
 	id, err := ioutil.ReadFile(tmpIidFile)
 	c.Assert(err, check.IsNil)
 	d, err := digest.Parse(string(id))
 	c.Assert(err, check.IsNil)
 	c.Assert(d.String(), checker.Equals, getIDByName(c, name))
 }
 
 func (s *DockerSuite) TestBuildIidFileCleanupOnFail(c *check.C) {
 	tmpDir, err := ioutil.TempDir("", "TestBuildIidFileCleanupOnFail")
 	if err != nil {
 		c.Fatal(err)
 	}
 	defer os.RemoveAll(tmpDir)
 	tmpIidFile := filepath.Join(tmpDir, "iid")
 
 	err = ioutil.WriteFile(tmpIidFile, []byte("Dummy"), 0666)
 	c.Assert(err, check.IsNil)
 
 	cli.Docker(cli.Build("testbuildiidfilecleanuponfail"),
 		build.WithDockerfile(`FROM `+minimalBaseImage()+`
 	RUN /non/existing/command`),
 		cli.WithFlags("--iidfile", tmpIidFile)).Assert(c, icmd.Expected{
 		ExitCode: 1,
 	})
 	_, err = os.Stat(tmpIidFile)
 	c.Assert(err, check.NotNil)
 	c.Assert(os.IsNotExist(err), check.Equals, true)
 }
9777ec3b
 
 func (s *DockerSuite) TestBuildIidFileSquash(c *check.C) {
 	testRequires(c, ExperimentalDaemon)
 	tmpDir, err := ioutil.TempDir("", "TestBuildIidFileSquash")
 	if err != nil {
 		c.Fatal(err)
 	}
 	defer os.RemoveAll(tmpDir)
 	tmpIidFile := filepath.Join(tmpDir, "iidsquash")
 
 	name := "testbuildiidfilesquash"
 	// Use a Dockerfile with multiple stages to ensure we get the last one
 	cli.BuildCmd(c, name,
 		// This could be minimalBaseImage except
 		// https://github.com/moby/moby/issues/33823 requires
 		// `touch` to workaround.
 		build.WithDockerfile(`FROM busybox
 ENV FOO FOO
 ENV BAR BAR
 RUN touch /foop
 `),
 		cli.WithFlags("--iidfile", tmpIidFile, "--squash"))
 
 	id, err := ioutil.ReadFile(tmpIidFile)
 	c.Assert(err, check.IsNil)
 	d, err := digest.Parse(string(id))
 	c.Assert(err, check.IsNil)
 	c.Assert(d.String(), checker.Equals, getIDByName(c, name))
 }