Repository: digitalocean/doctl
Pull request #1257 (2022-09-28 21:52:02)

appdev: correct source_dir and dockerfile_path interaction
dockerfile_path in the app spec is relative to the workspace root and so it can be outside of source_dir.
However the docker tooling expects it to be present in the build context that is uploaded to the docker engine and therefore relative to source_dir.

This fixes the interaction between the two options and adds support for building with dockerfiles that are outside of source_dir.

Most of the logic is copied from the `docker` cli: https://github.com/docker/cli/blob/9400e3dbe8ebd0bede3ab7023f744a8d7f4397d2/cli/command/image/build.go#L180

Test are WIP but putting up a PR to unblock reviews.

andrewsomething: @kamaln7  Can you include that link in a code comment? It will be extremely helpful for any future debugging. 

Patch:
diff --git a/commands/apps_charm.go b/commands/apps_charm.go
index 190f5f4d..d4679722 100644
--- a/commands/apps_charm.go
+++ b/commands/apps_charm.go
@@ -5,6 +5,7 @@ import (
 
 	"github.com/digitalocean/doctl/commands/charm"
 	"github.com/digitalocean/doctl/commands/charm/template"
+	"github.com/digitalocean/doctl/internal/apps/builder"
 	"github.com/digitalocean/godo"
 )
 
@@ -22,6 +23,12 @@ func (i componentListItem) Description() string {
 	}
 
 	if buildable, ok := i.spec.(godo.AppBuildableComponentSpec); ok {
+		if builder.IsDockerBuild(buildable) {
+			desc[0] += " [dockerfile]"
+		} else if builder.IsCNBBuild(buildable) {
+			desc[0] += " [buildpacks]"
+		}
+
 		if sourceDir := buildable.GetSourceDir(); sourceDir != "" {
 			desc = append(desc, template.String(`located in ./{{highlight .}}`, sourceDir))
 		}
diff --git a/go.mod b/go.mod
index 6779c045..408e7391 100644
--- a/go.mod
+++ b/go.mod
@@ -23,7 +23,7 @@ require (
 	github.com/mattn/go-isatty v0.0.14
 	github.com/mitchellh/copystructure v1.0.0
 	github.com/natefinch/pie v0.0.0-20170715172608-9a0d72014007
-	github.com/opencontainers/image-spec v1.0.2
+	github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799
 	github.com/opencontainers/runc v1.1.3 // indirect
 	github.com/pkg/errors v0.9.1
 	github.com/sclevine/spec v1.3.0
@@ -47,7 +47,6 @@ require (
 require (
 	github.com/MakeNowJust/heredoc v1.0.0
 	github.com/apache/openwhisk-client-go v0.0.0-20211007130743-38709899040b
-	github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
 	github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2
 	github.com/charmbracelet/bubbles v0.13.1-0.20220731172002-8f6516082803
 	github.com/charmbracelet/bubbletea v0.22.0
@@ -57,17 +56,18 @@ require (
 	github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
 	github.com/muesli/reflow v0.3.0
 	github.com/muesli/termenv v0.12.0
+	github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
 	gopkg.in/yaml.v3 v3.0.1
 )
 
 require (
-	github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
+	github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
 	github.com/Microsoft/go-winio v0.5.2 // indirect
 	github.com/atotto/clipboard v0.1.4 // indirect
 	github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 // indirect
 	github.com/containerd/cgroups v1.0.3 // indirect
 	github.com/containerd/console v1.0.3 // indirect
-	github.com/containerd/containerd v1.5.13 // indirect
+	github.com/containerd/containerd v1.6.3-0.20220401172941-5ff8fce1fcc6 // indirect
 	github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 	github.com/docker/distribution v2.8.1+incompatible // indirect
@@ -91,9 +91,11 @@ require (
 	github.com/mattn/go-runewidth v0.0.14 // indirect
 	github.com/mitchellh/mapstructure v1.4.3 // indirect
 	github.com/mitchellh/reflectwalk v1.0.0 // indirect
+	github.com/moby/buildkit v0.10.4 // indirect
 	github.com/moby/sys/mount v0.3.3 // indirect
 	github.com/moby/sys/mountinfo v0.6.2 // indirect
-	github.com/moby/term v0.0.0-20200312100748-672ec06f55cd // indirect
+	github.com/moby/sys/symlink v0.2.0 // indirect
+	github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/morikuni/aec v1.0.0 // indirect
diff --git a/go.sum b/go.sum
index c86db254..ae433585 100644
--- a/go.sum
+++ b/go.sum
@@ -38,8 +38,9 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
 cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
+github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
+github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
 github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
 github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
 github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
@@ -186,8 +187,8 @@ github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09Zvgq
 github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
 github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
 github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
-github.com/containerd/containerd v1.5.13 h1:XqvKw9i4P7/mFrC3TSM7yV5cwFZ9avXe6M3YANKnzEE=
-github.com/containerd/containerd v1.5.13/go.mod h1:3AlCrzKROjIuP3JALsY14n8YtntaUDBu7vek+rPN5Vc=
+github.com/containerd/containerd v1.6.3-0.20220401172941-5ff8fce1fcc6 h1:nig7zto6cp3Wt1lPMK8EmyP6f/ZNmn/tL6ASQ7stews=
+github.com/containerd/containerd v1.6.3-0.20220401172941-5ff8fce1fcc6/go.mod h1:WSt2SnDLAGWlu+Vl+EWay37seZLKqgRt6XLjIMy8SYM=
 github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
 github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
 github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@@ -590,6 +591,8 @@ github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
 github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
 github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
 github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/moby/buildkit v0.10.4 h1:FvC+buO8isGpUFZ1abdSLdGHZVqg9sqI4BbFL8tlzP4=
+github.com/moby/buildkit v0.10.4/go.mod h1:Yajz9vt1Zw5q9Pp4pdb3TCSUXJBIroIQGQ3TTs/sLug=
 github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
 github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
 github.com/moby/sys/mount v0.3.3 h1:fX1SVkXFJ47XWDoeFW4Sq7PdQJnV2QIDZAqjNqgEjUs=
@@ -600,8 +603,11 @@ github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdx
 github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
 github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
 github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ=
-github.com/moby/term v0.0.0-20200312100748-672ec06f55cd h1:aY7OQNf2XqY/JQ6qREWamhI/81os/agb2BAGpcx5yWI=
+github.com/moby/sys/symlink v0.2.0 h1:tk1rOM+Ljp0nFmfOIBtlV3rTDlWOwFRhjEeAhZB0nZc=
+github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs=
 github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
+github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc=
+github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -671,8 +677,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
 github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
 github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
-github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec=
+github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
 github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
 github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
 github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
diff --git a/internal/apps/builder/builder.go b/internal/apps/builder/builder.go
index d1f90230..d14b0f8d 100644
--- a/internal/apps/builder/builder.go
+++ b/internal/apps/builder/builder.go
@@ -322,3 +322,13 @@ func IsCNBBuild(spec godo.AppBuildableComponentSpec) bool {
 
 	return true
 }
+
+// IsDockerBuild indicates whether the component will be built using the Docker builder.
+func IsDockerBuild(spec godo.AppBuildableComponentSpec) bool {
+	dockerBuildable, ok := spec.(godo.AppDockerBuildableComponentSpec)
+	if !ok {
+		return false
+	}
+
+	return dockerBuildable.GetDockerfilePath() != ""
+}
diff --git a/internal/apps/builder/docker.go b/internal/apps/builder/docker.go
index 92922832..b9edc112 100644
--- a/internal/apps/builder/docker.go
+++ b/internal/apps/builder/docker.go
@@ -16,8 +16,10 @@ import (
 
 	"github.com/digitalocean/doctl/commands/charm/template"
 	"github.com/digitalocean/godo"
+	"github.com/docker/cli/cli/command/image/build"
 	dockertypes "github.com/docker/docker/api/types"
 	"github.com/docker/docker/pkg/archive"
+	"github.com/docker/docker/pkg/idtools"
 )
 
 // DockerComponentBuilder builds components using a Dockerfile.
@@ -58,23 +60,20 @@ func (b *DockerComponentBuilder) Build(ctx context.Context) (ComponentBuilderRes
 		return ComponentBuilderResult{}, fmt.Errorf("configuring environment variables: %w", err)
 	}
 
-	buildContext := b.contextDir
-	if sd := filepath.Clean(b.component.GetSourceDir()); sd != "." && sd != "/" {
-		buildContext = filepath.Join(buildContext, sd)
-	}
-	// TODO Dockerfile must be relative to the source dir.
-	// Make it relative and if it's outside the source dir add it to the archive.
-	// ref: https://github.com/docker/cli/blob/9400e3dbe8ebd0bede3ab7023f744a8d7f4397d2/cli/command/image/build.go#L280-L286
-	template.Render(lw, `{{success checkmark}} building image using dockerfile {{highlight .}}{{nl 2}}`, b.dockerComponent.GetDockerfilePath())
+	template.Render(lw,
+		`{{success checkmark}} building image using dockerfile {{highlight .}}{{nl 2}}`,
+		b.dockerComponent.GetDockerfilePath(),
+	)
 	start := time.Now()
-	tar, err := archive.TarWithOptions(buildContext, &archive.TarOptions{})
+
+	imageBuildContext, imageBuildDockerfile, err := b.getImageBuildContext(ctx)
 	if err != nil {
 		return ComponentBuilderResult{}, fmt.Errorf("preparing build context: %w", err)
 	}
 
 	res := ComponentBuilderResult{}
-	dockerRes, err := b.cli.ImageBuild(ctx, tar, dockertypes.ImageBuildOptions{
-		Dockerfile: b.dockerComponent.GetDockerfilePath(),
+	dockerRes, err := b.cli.ImageBuild(ctx, imageBuildContext, dockertypes.ImageBuildOptions{
+		Dockerfile: imageBuildDockerfile,
 		Tags: []string{
 			b.AppImageOutputName(),
 		},
@@ -106,6 +105,65 @@ func (b *DockerComponentBuilder) Build(ctx context.Context) (ComponentBuilderRes
 	return res, nil
 }
 
+func (b *DockerComponentBuilder) getImageBuildContext(ctx context.Context) (io.Reader, string, error) {
+	// this assembles the build context in a way that fits cli.ImageBuild's expectations around
+	// dockerfiles and .dockerignore.
+	// much of this logic is copied from the `docker` cli implementation:
+	//   https://github.com/docker/cli/blob/9400e3dbe8ebd0bede3ab7023f744a8d7f4397d2/cli/command/image/build.go#L180
+	//   specifically the "build context is a local directory" flow.
+
+	absSourceDir, err := filepath.Abs(filepath.Join(b.contextDir, b.dockerComponent.GetSourceDir()))
+	if err != nil {
+		return nil, "", fmt.Errorf("parsing source_dir: %w", err)
+	}
+	absDockerfile, err := filepath.Abs(filepath.Join(b.contextDir, b.dockerComponent.GetDockerfilePath()))
+	if err != nil {
+		return nil, "", fmt.Errorf("parsing dockerfile_path: %w", err)
+	}
+	relDockerfile, err := filepath.Rel(absSourceDir, absDockerfile)
+	if err != nil {
+		return nil, "", err
+	}
+
+	excludes, err := build.ReadDockerignore(absSourceDir)
+	if err != nil {
+		return nil, "", fmt.Errorf("reading .dockerignore: %w", err)
+	}
+
+	if err := build.ValidateContextDirectory(absSourceDir, excludes); err != nil {
+		return nil, "", err
+	}
+
+	// canonicalize dockerfile name to a platform-independent one
+	relDockerfile = archive.CanonicalTarNameForPath(relDockerfile)
+	excludes = build.TrimBuildFilesFromExcludes(excludes, relDockerfile, false)
+	tar, err := archive.TarWithOptions(absSourceDir, &archive.TarOptions{
+		ExcludePatterns: excludes,
+		ChownOpts:       &idtools.Identity{UID: 0, GID: 0},
+	})
+	if err != nil {
+		return nil, "", fmt.Errorf("preparing build context: %w", err)
+	}
+
+	// NOTE: archive.CanonicalTarNameForPath normalizes path separators so the relative path will use /
+	// even on windows.
+	if strings.HasPrefix(relDockerfile, "../") {
+		dockerfileReader, err := os.Open(absDockerfile)
+		if err != nil {
+			return nil, "", fmt.Errorf("opening dockerfile: %w", err)
+		}
+		defer dockerfileReader.Close()
+		// dockerfile_path is outside of source_dir. we need to copy it inside the build context
+		// so that the docker engine can access it.
+		tar, relDockerfile, err = build.AddDockerfileToBuildContext(dockerfileReader, tar)
+		if err != nil {
+			return nil, "", fmt.Errorf("copying external dockerfile inside build context: %w", err)
+		}
+	}
+
+	return tar, relDockerfile, nil
+}
+
 // buildStaticSiteImage builds a container image that runs a webserver hosting the static site content
 func (b *DockerComponentBuilder) buildStaticSiteImage(ctx context.Context) error {
 	c, ok := b.component.(*godo.AppStaticSiteSpec)
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go
index a6732797..5599082a 100644
--- a/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go
@@ -10,6 +10,7 @@ import (
 	"syscall"
 
 	"github.com/Azure/go-ansiterm"
+	windows "golang.org/x/sys/windows"
 )
 
 // Windows keyboard constants
@@ -162,15 +163,28 @@ func ensureInRange(n int16, min int16, max int16) int16 {
 
 func GetStdFile(nFile int) (*os.File, uintptr) {
 	var file *os.File
-	switch nFile {
-	case syscall.STD_INPUT_HANDLE:
+
+	// syscall uses negative numbers
+	// windows package uses very big uint32
+	// Keep these switches split so we don't have to convert ints too much.
+	switch uint32(nFile) {
+	case windows.STD_INPUT_HANDLE:
 		file = os.Stdin
-	case syscall.STD_OUTPUT_HANDLE:
+	case windows.STD_OUTPUT_HANDLE:
 		file = os.Stdout
-	case syscall.STD_ERROR_HANDLE:
+	case windows.STD_ERROR_HANDLE:
 		file = os.Stderr
 	default:
-		panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile))
+		switch nFile {
+		case syscall.STD_INPUT_HANDLE:
+			file = os.Stdin
+		case syscall.STD_OUTPUT_HANDLE:
+			file = os.Stdout
+		case syscall.STD_ERROR_HANDLE:
+			file = os.Stderr
+		default:
+			panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile))
+		}
 	}
 
 	fd, err := syscall.GetStdHandle(nFile)
diff --git a/vendor/github.com/containerd/containerd/log/context.go b/vendor/github.com/containerd/containerd/log/context.go
deleted file mode 100644
index 37b6a7d1..00000000
--- a/vendor/github.com/containerd/containerd/log/context.go
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-   Copyright The containerd Authors.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package log
-
-import (
-	"context"
-
-	"github.com/sirupsen/logrus"
-)
-
-var (
-	// G is an alias for GetLogger.
-	//
-	// We may want to define this locally to a package to get package tagged log
-	// messages.
-	G = GetLogger
-
-	// L is an alias for the standard logger.
-	L = logrus.NewEntry(logrus.StandardLogger())
-)
-
-type (
-	loggerKey struct{}
-)
-
-const (
-	// RFC3339NanoFixed is time.RFC3339Nano with nanoseconds padded using zeros to
-	// ensure the formatted time is always the same number of characters.
-	RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
-
-	// TextFormat represents the text logging format
-	TextFormat = "text"
-
-	// JSONFormat represents the JSON logging format
-	JSONFormat = "json"
-)
-
-// WithLogger returns a new context with the provided logger. Use in
-// combination with logger.WithField(s) for great effect.
-func WithLogger(ctx context.Context, logger *logrus.Entry) context.Context {
-	return context.WithValue(ctx, loggerKey{}, logger)
-}
-
-// GetLogger retrieves the current logger from the context. If no logger is
-// available, the default logger is returned.
-func GetLogger(ctx context.Context) *logrus.Entry {
-	logger := ctx.Value(loggerKey{})
-
-	if logger == nil {
-		return L
-	}
-
-	return logger.(*logrus.Entry)
-}
diff --git a/vendor/github.com/containerd/containerd/sys/fds.go b/vendor/github.com/containerd/containerd/sys/fds.go
index 8b1ba8d7..a71a9cd7 100644
--- a/vendor/github.com/containerd/containerd/sys/fds.go
+++ b/vendor/github.com/containerd/containerd/sys/fds.go
@@ -20,14 +20,14 @@
 package sys
 
 import (
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"strconv"
 )
 
 // GetOpenFds returns the number of open fds for the process provided by pid
 func GetOpenFds(pid int) (int, error) {
-	dirs, err := ioutil.ReadDir(filepath.Join("/proc", strconv.Itoa(pid), "fd"))
+	dirs, err := os.ReadDir(filepath.Join("/proc", strconv.Itoa(pid), "fd"))
 	if err != nil {
 		return -1, err
 	}
diff --git a/vendor/github.com/containerd/containerd/sys/filesys_windows.go b/vendor/github.com/containerd/containerd/sys/filesys_windows.go
index a30baba5..87ebacc2 100644
--- a/vendor/github.com/containerd/containerd/sys/filesys_windows.go
+++ b/vendor/github.com/containerd/containerd/sys/filesys_windows.go
@@ -1,6 +1,3 @@
-//go:build windows
-// +build windows
-
 /*
    Copyright The containerd Authors.
 
@@ -20,6 +17,7 @@
 package sys
 
 import (
+	"fmt"
 	"os"
 	"path/filepath"
 	"regexp"
@@ -30,7 +28,6 @@ import (
 	"unsafe"
 
 	"github.com/Microsoft/hcsshim"
-	"github.com/pkg/errors"
 	"golang.org/x/sys/windows"
 )
 
@@ -271,7 +268,7 @@ func ForceRemoveAll(path string) error {
 	snapshotDir := filepath.Join(path, snapshotPlugin, "snapshots")
 	if stat, err := os.Stat(snapshotDir); err == nil && stat.IsDir() {
 		if err := cleanupWCOWLayers(snapshotDir); err != nil {
-			return errors.Wrapf(err, "failed to cleanup WCOW layers in %s", snapshotDir)
+			return fmt.Errorf("failed to cleanup WCOW layers in %s: %w", snapshotDir, err)
 		}
 	}
 
@@ -281,12 +278,22 @@ func ForceRemoveAll(path string) error {
 func cleanupWCOWLayers(root string) error {
 	// See snapshots/windows/windows.go getSnapshotDir()
 	var layerNums []int
+	var rmLayerNums []int
 	if err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
 		if path != root && info.IsDir() {
-			if layerNum, err := strconv.Atoi(filepath.Base(path)); err == nil {
-				layerNums = append(layerNums, layerNum)
+			name := filepath.Base(path)
+			if strings.HasPrefix(name, "rm-") {
+				layerNum, err := strconv.Atoi(strings.TrimPrefix(name, "rm-"))
+				if err != nil {
+					return err
+				}
+				rmLayerNums = append(rmLayerNums, layerNum)
 			} else {
-				return err
+				layerNum, err := strconv.Atoi(name)
+				if err != nil {
+					return err
+				}
+				layerNums = append(layerNums, layerNum)
 			}
 			return filepath.SkipDir
 		}
@@ -296,8 +303,14 @@ func cleanupWCOWLayers(root string) error {
 		return err
 	}
 
-	sort.Sort(sort.Reverse(sort.IntSlice(layerNums)))
+	sort.Sort(sort.Reverse(sort.IntSlice(rmLayerNums)))
+	for _, rmLayerNum := range rmLayerNums {
+		if err := cleanupWCOWLayer(filepath.Join(root, "rm-"+strconv.Itoa(rmLayerNum))); err != nil {
+			return err
+		}
+	}
 
+	sort.Sort(sort.Reverse(sort.IntSlice(layerNums)))
 	for _, layerNum := range layerNums {
 		if err := cleanupWCOWLayer(filepath.Join(root, strconv.Itoa(layerNum))); err != nil {
 			return err
@@ -312,19 +325,20 @@ func cleanupWCOWLayer(layerPath string) error {
 		HomeDir: filepath.Dir(layerPath),
 	}
 
-	// ERROR_DEV_NOT_EXIST is returned if the layer is not currently prepared.
+	// ERROR_DEV_NOT_EXIST is returned if the layer is not currently prepared or activated.
+	// ERROR_FLT_INSTANCE_NOT_FOUND is returned if the layer is currently activated but not prepared.
 	if err := hcsshim.UnprepareLayer(info, filepath.Base(layerPath)); err != nil {
-		if hcserror, ok := err.(*hcsshim.HcsError); !ok || hcserror.Err != windows.ERROR_DEV_NOT_EXIST {
-			return errors.Wrapf(err, "failed to unprepare %s", layerPath)
+		if hcserror, ok := err.(*hcsshim.HcsError); !ok || (hcserror.Err != windows.ERROR_DEV_NOT_EXIST && hcserror.Err != syscall.Errno(windows.ERROR_FLT_INSTANCE_NOT_FOUND)) {
+			return fmt.Errorf("failed to unprepare %s: %w", layerPath, err)
 		}
 	}
 
 	if err := hcsshim.DeactivateLayer(info, filepath.Base(layerPath)); err != nil {
-		return errors.Wrapf(err, "failed to deactivate %s", layerPath)
+		return fmt.Errorf("failed to deactivate %s: %w", layerPath, err)
 	}
 
 	if err := hcsshim.DestroyLayer(info, filepath.Base(layerPath)); err != nil {
-		return errors.Wrapf(err, "failed to destroy %s", layerPath)
+		return fmt.Errorf("failed to destroy %s: %w", layerPath, err)
 	}
 
 	return nil
diff --git a/vendor/github.com/containerd/containerd/sys/mount_linux.go b/vendor/github.com/containerd/containerd/sys/mount_linux.go
deleted file mode 100644
index a2104552..00000000
--- a/vendor/github.com/containerd/containerd/sys/mount_linux.go
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
-   Copyright The containerd Authors.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package sys
-
-import (
-	"runtime"
-	"syscall"
-	"unsafe"
-
-	"github.com/containerd/containerd/log"
-	"github.com/pkg/errors"
-	"golang.org/x/sys/unix"
-)
-
-// FMountat performs mount from the provided directory.
-func FMountat(dirfd uintptr, source, target, fstype string, flags uintptr, data string) error {
-	var (
-		sourceP, targetP, fstypeP, dataP *byte
-		pid                              uintptr
-		err                              error
-		errno, status                    syscall.Errno
-	)
-
-	sourceP, err = syscall.BytePtrFromString(source)
-	if err != nil {
-		return err
-	}
-
-	targetP, err = syscall.BytePtrFromString(target)
-	if err != nil {
-		return err
-	}
-
-	fstypeP, err = syscall.BytePtrFromString(fstype)
-	if err != nil {
-		return err
-	}
-
-	if data != "" {
-		dataP, err = syscall.BytePtrFromString(data)
-		if err != nil {
-			return err
-		}
-	}
-
-	runtime.LockOSThread()
-	defer runtime.UnlockOSThread()
-
-	var pipefds [2]int
-	if err := syscall.Pipe2(pipefds[:], syscall.O_CLOEXEC); err != nil {
-		return errors.Wrap(err, "failed to open pipe")
-	}
-
-	defer func() {
-		// close both ends of the pipe in a deferred function, since open file
-		// descriptor table is shared with child
-		syscall.Close(pipefds[0])
-		syscall.Close(pipefds[1])
-	}()
-
-	pid, errno = forkAndMountat(dirfd,
-		uintptr(unsafe.Pointer(sourceP)),
-		uintptr(unsafe.Pointer(targetP)),
-		uintptr(unsafe.Pointer(fstypeP)),
-		flags,
-		uintptr(unsafe.Pointer(dataP)),
-		pipefds[1],
-	)
-
-	if errno != 0 {
-		return errors.Wrap(errno, "failed to fork thread")
-	}
-
-	defer func() {
-		_, err := unix.Wait4(int(pid), nil, 0, nil)
-		for err == syscall.EINTR {
-			_, err = unix.Wait4(int(pid), nil, 0, nil)
-		}
-
-		if err != nil {
-			log.L.WithError(err).Debugf("failed to find pid=%d process", pid)
-		}
-	}()
-
-	_, _, errno = syscall.RawSyscall(syscall.SYS_READ,
-		uintptr(pipefds[0]),
-		uintptr(unsafe.Pointer(&status)),
-		unsafe.Sizeof(status))
-	if errno != 0 {
-		return errors.Wrap(errno, "failed to read pipe")
-	}
-
-	if status != 0 {
-		return errors.Wrap(status, "failed to mount")
-	}
-
-	return nil
-}
-
-// forkAndMountat will fork thread, change working dir and mount.
-//
-// precondition: the runtime OS thread must be locked.
-func forkAndMountat(dirfd uintptr, source, target, fstype, flags, data uintptr, pipefd int) (pid uintptr, errno syscall.Errno) {
-
-	// block signal during clone
-	beforeFork()
-
-	// the cloned thread shares the open file descriptor, but the thread
-	// never be reused by runtime.
-	pid, _, errno = syscall.RawSyscall6(syscall.SYS_CLONE, uintptr(syscall.SIGCHLD)|syscall.CLONE_FILES, 0, 0, 0, 0, 0)
-	if errno != 0 || pid != 0 {
-		// restore all signals
-		afterFork()
-		return
-	}
-
-	// restore all signals
-	afterForkInChild()
-
-	// change working dir
-	_, _, errno = syscall.RawSyscall(syscall.SYS_FCHDIR, dirfd, 0, 0)
-	if errno != 0 {
-		goto childerr
-	}
-	_, _, errno = syscall.RawSyscall6(syscall.SYS_MOUNT, source, target, fstype, flags, data, 0)
-
-childerr:
-	_, _, errno = syscall.RawSyscall(syscall.SYS_WRITE, uintptr(pipefd), uintptr(unsafe.Pointer(&errno)), unsafe.Sizeof(errno))
-	syscall.RawSyscall(syscall.SYS_EXIT, uintptr(errno), 0, 0)
-	panic("unreachable")
-}
diff --git a/vendor/github.com/containerd/containerd/sys/oom_linux.go b/vendor/github.com/containerd/containerd/sys/oom_linux.go
index 82a347c6..bb2a3eaf 100644
--- a/vendor/github.com/containerd/containerd/sys/oom_linux.go
+++ b/vendor/github.com/containerd/containerd/sys/oom_linux.go
@@ -18,7 +18,6 @@ package sys
 
 import (
 	"fmt"
-	"io/ioutil"
 	"os"
 	"strconv"
 	"strings"
@@ -69,7 +68,7 @@ func SetOOMScore(pid, score int) error {
 // no oom score is set, or a sore is set to 0.
 func GetOOMScoreAdj(pid int) (int, error) {
 	path := fmt.Sprintf("/proc/%d/oom_score_adj", pid)
-	data, err := ioutil.ReadFile(path)
+	data, err := os.ReadFile(path)
 	if err != nil {
 		return 0, err
 	}
diff --git a/vendor/github.com/containerd/containerd/sys/socket_unix.go b/vendor/github.com/containerd/containerd/sys/socket_unix.go
index eb803503..367e19ca 100644
--- a/vendor/github.com/containerd/containerd/sys/socket_unix.go
+++ b/vendor/github.com/containerd/containerd/sys/socket_unix.go
@@ -20,11 +20,11 @@
 package sys
 
 import (
+	"fmt"
 	"net"
 	"os"
 	"path/filepath"
 
-	"github.com/pkg/errors"
 	"golang.org/x/sys/unix"
 )
 
@@ -32,7 +32,7 @@ import (
 func CreateUnixSocket(path string) (net.Listener, error) {
 	// BSDs have a 104 limit
 	if len(path) > 104 {
-		return nil, errors.Errorf("%q: unix socket path too long (> 104)", path)
+		return nil, fmt.Errorf("%q: unix socket path too long (> 104)", path)
 	}
 	if err := os.MkdirAll(filepath.Dir(path), 0660); err != nil {
 		return nil, err
diff --git a/vendor/github.com/containerd/containerd/sys/socket_windows.go b/vendor/github.com/containerd/containerd/sys/socket_windows.go
index 7c7694fd..1ae12bc5 100644
--- a/vendor/github.com/containerd/containerd/sys/socket_windows.go
+++ b/vendor/github.com/containerd/containerd/sys/socket_windows.go
@@ -1,6 +1,3 @@
-//go:build windows
-// +build windows
-
 /*
    Copyright The containerd Authors.
 
diff --git a/vendor/github.com/containerd/containerd/sys/stat_bsd.go b/vendor/github.com/containerd/containerd/sys/stat_bsd.go
deleted file mode 100644
index 3f6ba640..00000000
--- a/vendor/github.com/containerd/containerd/sys/stat_bsd.go
+++ /dev/null
@@ -1,45 +0,0 @@
-//go:build darwin || freebsd || netbsd
-// +build darwin freebsd netbsd
-
-/*
-   Copyright The containerd Authors.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package sys
-
-import (
-	"syscall"
-	"time"
-)
-
-// StatAtime returns the access time from a stat struct
-func StatAtime(st *syscall.Stat_t) syscall.Timespec {
-	return st.Atimespec
-}
-
-// StatCtime returns the created time from a stat struct
-func StatCtime(st *syscall.Stat_t) syscall.Timespec {
-	return st.Ctimespec
-}
-
-// StatMtime returns the modified time from a stat struct
-func StatMtime(st *syscall.Stat_t) syscall.Timespec {
-	return st.Mtimespec
-}
-
-// StatATimeAsTime returns the access time as a time.Time
-func StatATimeAsTime(st *syscall.Stat_t) time.Time {
-	return time.Unix(int64(st.Atimespec.Sec), int64(st.Atimespec.Nsec)) // nolint: unconvert
-}
diff --git a/vendor/github.com/containerd/containerd/sys/stat_openbsd.go b/vendor/github.com/containerd/containerd/sys/stat_openbsd.go
deleted file mode 100644
index e4093f9b..00000000
--- a/vendor/github.com/containerd/containerd/sys/stat_openbsd.go
+++ /dev/null
@@ -1,46 +0,0 @@
-//go:build openbsd
-// +build openbsd
-
-/*
-   Copyright The containerd Authors.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package sys
-
-import (
-	"syscall"
-	"time"
-)
-
-// StatAtime returns the Atim
-func StatAtime(st *syscall.Stat_t) syscall.Timespec {
-	return st.Atim
-}
-
-// StatCtime returns the Ctim
-func StatCtime(st *syscall.Stat_t) syscall.Timespec {
-	return st.Ctim
-}
-
-// StatMtime returns the Mtim
-func StatMtime(st *syscall.Stat_t) syscall.Timespec {
-	return st.Mtim
-}
-
-// StatATimeAsTime returns st.Atim as a time.Time
-func StatATimeAsTime(st *syscall.Stat_t) time.Time {
-	// The int64 conversions ensure the line compiles for 32-bit systems as well.
-	return time.Unix(int64(st.Atim.Sec), int64(st.Atim.Nsec)) // nolint: unconvert
-}
diff --git a/vendor/github.com/containerd/containerd/sys/stat_unix.go b/vendor/github.com/containerd/containerd/sys/stat_unix.go
deleted file mode 100644
index 9bb63b36..00000000
--- a/vendor/github.com/containerd/containerd/sys/stat_unix.go
+++ /dev/null
@@ -1,45 +0,0 @@
-//go:build linux || solaris
-// +build linux solaris
-
-/*
-   Copyright The containerd Authors.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package sys
-
-import (
-	"syscall"
-	"time"
-)
-
-// StatAtime returns the Atim
-func StatAtime(st *syscall.Stat_t) syscall.Timespec {
-	return st.Atim
-}
-
-// StatCtime returns the Ctim
-func StatCtime(st *syscall.Stat_t) syscall.Timespec {
-	return st.Ctim
-}
-
-// StatMtime returns the Mtim
-func StatMtime(st *syscall.Stat_t) syscall.Timespec {
-	return st.Mtim
-}
-
-// StatATimeAsTime returns st.Atim as a time.Time
-func StatATimeAsTime(st *syscall.Stat_t) time.Time {
-	return time.Unix(int64(st.Atim.Sec), int64(st.Atim.Nsec)) // nolint: unconvert
-}
diff --git a/vendor/github.com/containerd/containerd/sys/subprocess_unsafe_linux.go b/vendor/github.com/containerd/containerd/sys/subprocess_unsafe_linux.go
deleted file mode 100644
index 6e40a9c7..00000000
--- a/vendor/github.com/containerd/containerd/sys/subprocess_unsafe_linux.go
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-   Copyright The containerd Authors.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package sys
-
-import (
-	_ "unsafe" // required for go:linkname.
-)
-
-//go:linkname beforeFork syscall.runtime_BeforeFork
-func beforeFork()
-
-//go:linkname afterFork syscall.runtime_AfterFork
-func afterFork()
-
-//go:linkname afterForkInChild syscall.runtime_AfterForkInChild
-func afterForkInChild()
diff --git a/vendor/github.com/containerd/containerd/sys/subprocess_unsafe_linux.s b/vendor/github.com/containerd/containerd/sys/subprocess_unsafe_linux.s
deleted file mode 100644
index c073fa4a..00000000
--- a/vendor/github.com/containerd/containerd/sys/subprocess_unsafe_linux.s
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
-   Copyright The containerd Authors.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
diff --git a/vendor/github.com/docker/cli/cli/command/image/build/context.go b/vendor/github.com/docker/cli/cli/command/image/build/context.go
new file mode 100644
index 00000000..2509f66d
--- /dev/null
+++ b/vendor/github.com/docker/cli/cli/command/image/build/context.go
@@ -0,0 +1,440 @@
+package build
+
+import (
+	"archive/tar"
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"time"
+
+	"github.com/docker/docker/builder/remotecontext/git"
+	"github.com/docker/docker/pkg/archive"
+	"github.com/docker/docker/pkg/fileutils"
+	"github.com/docker/docker/pkg/ioutils"
+	"github.com/docker/docker/pkg/pools"
+	"github.com/docker/docker/pkg/progress"
+	"github.com/docker/docker/pkg/streamformatter"
+	"github.com/docker/docker/pkg/stringid"
+	"github.com/pkg/errors"
+	exec "golang.org/x/sys/execabs"
+)
+
+const (
+	// DefaultDockerfileName is the Default filename with Docker commands, read by docker build
+	DefaultDockerfileName string = "Dockerfile"
+	// archiveHeaderSize is the number of bytes in an archive header
+	archiveHeaderSize = 512
+)
+
+// ValidateContextDirectory checks if all the contents of the directory
+// can be read and returns an error if some files can't be read
+// symlinks which point to non-existing files don't trigger an error
+func ValidateContextDirectory(srcPath string, excludes []string) error {
+	contextRoot, err := getContextRoot(srcPath)
+	if err != nil {
+		return err
+	}
+
+	pm, err := fileutils.NewPatternMatcher(excludes)
+	if err != nil {
+		return err
+	}
+
+	return filepath.Walk(contextRoot, func(filePath string, f os.FileInfo, err error) error {
+		if err != nil {
+			if os.IsPermission(err) {
+				return errors.Errorf("can't stat '%s'", filePath)
+			}
+			if os.IsNotExist(err) {
+				return errors.Errorf("file ('%s') not found or excluded by .dockerignore", filePath)
+			}
+			return err
+		}
+
+		// skip this directory/file if it's not in the path, it won't get added to the context
+		if relFilePath, err := filepath.Rel(contextRoot, filePath); err != nil {
+			return err
+		} else if skip, err := filepathMatches(pm, relFilePath); err != nil {
+			return err
+		} else if skip {
+			if f.IsDir() {
+				return filepath.SkipDir
+			}
+			return nil
+		}
+
+		// skip checking if symlinks point to non-existing files, such symlinks can be useful
+		// also skip named pipes, because they hanging on open
+		if f.Mode()&(os.ModeSymlink|os.ModeNamedPipe) != 0 {
+			return nil
+		}
+
+		if !f.IsDir() {
+			currentFile, err := os.Open(filePath)
+			if err != nil && os.IsPermission(err) {
+				return errors.Errorf("no permission to read from '%s'", filePath)
+			}
+			currentFile.Close()
+		}
+		return nil
+	})
+}
+
+func filepathMatches(matcher *fileutils.PatternMatcher, file string) (bool, error) {
+	file = filepath.Clean(file)
+	if file == "." {
+		// Don't let them exclude everything, kind of silly.
+		return false, nil
+	}
+	return matcher.Matches(file)
+}
+
+// DetectArchiveReader detects whether the input stream is an archive or a
+// Dockerfile and returns a buffered version of input, safe to consume in lieu
+// of input. If an archive is detected, isArchive is set to true, and to false
+// otherwise, in which case it is safe to assume input represents the contents
+// of a Dockerfile.
+func DetectArchiveReader(input io.ReadCloser) (rc io.ReadCloser, isArchive bool, err error) {
+	buf := bufio.NewReader(input)
+
+	magic, err := buf.Peek(archiveHeaderSize * 2)
+	if err != nil && err != io.EOF {
+		return nil, false, errors.Errorf("failed to peek context header from STDIN: %v", err)
+	}
+
+	return ioutils.NewReadCloserWrapper(buf, func() error { return input.Close() }), IsArchive(magic), nil
+}
+
+// WriteTempDockerfile writes a Dockerfile stream to a temporary file with a
+// name specified by DefaultDockerfileName and returns the path to the
+// temporary directory containing the Dockerfile.
+func WriteTempDockerfile(rc io.ReadCloser) (dockerfileDir string, err error) {
+	// err is a named return value, due to the defer call below.
+	dockerfileDir, err = ioutil.TempDir("", "docker-build-tempdockerfile-")
+	if err != nil {
+		return "", errors.Errorf("unable to create temporary context directory: %v", err)
+	}
+	defer func() {
+		if err != nil {
+			os.RemoveAll(dockerfileDir)
+		}
+	}()
+
+	f, err := os.Create(filepath.Join(dockerfileDir, DefaultDockerfileName))
+	if err != nil {
+		return "", err
+	}
+	defer f.Close()
+	if _, err := io.Copy(f, rc); err != nil {
+		return "", err
+	}
+	return dockerfileDir, rc.Close()
+}
+
+// GetContextFromReader will read the contents of the given reader as either a
+// Dockerfile or tar archive. Returns a tar archive used as a context and a
+// path to the Dockerfile inside the tar.
+func GetContextFromReader(rc io.ReadCloser, dockerfileName string) (out io.ReadCloser, relDockerfile string, err error) {
+	rc, isArchive, err := DetectArchiveReader(rc)
+	if err != nil {
+		return nil, "", err
+	}
+
+	if isArchive {
+		return rc, dockerfileName, nil
+	}
+
+	// Input should be read as a Dockerfile.
+
+	if dockerfileName == "-" {
+		return nil, "", errors.New("build context is not an archive")
+	}
+
+	dockerfileDir, err := WriteTempDockerfile(rc)
+	if err != nil {
+		return nil, "", err
+	}
+
+	tar, err := archive.Tar(dockerfileDir, archive.Uncompressed)
+	if err != nil {
+		return nil, "", err
+	}
+
+	return ioutils.NewReadCloserWrapper(tar, func() error {
+		err := tar.Close()
+		os.RemoveAll(dockerfileDir)
+		return err
+	}), DefaultDockerfileName, nil
+}
+
+// IsArchive checks for the magic bytes of a tar or any supported compression
+// algorithm.
+func IsArchive(header []byte) bool {
+	compression := archive.DetectCompression(header)
+	if compression != archive.Uncompressed {
+		return true
+	}
+	r := tar.NewReader(bytes.NewBuffer(header))
+	_, err := r.Next()
+	return err == nil
+}
+
+// GetContextFromGitURL uses a Git URL as context for a `docker build`. The
+// git repo is cloned into a temporary directory used as the context directory.
+// Returns the absolute path to the temporary context directory, the relative
+// path of the dockerfile in that context directory, and a non-nil error on
+// success.
+func GetContextFromGitURL(gitURL, dockerfileName string) (string, string, error) {
+	if _, err := exec.LookPath("git"); err != nil {
+		return "", "", errors.Wrapf(err, "unable to find 'git'")
+	}
+	absContextDir, err := git.Clone(gitURL)
+	if err != nil {
+		return "", "", errors.Wrapf(err, "unable to 'git clone' to temporary context directory")
+	}
+
+	absContextDir, err = ResolveAndValidateContextPath(absContextDir)
+	if err != nil {
+		return "", "", err
+	}
+	relDockerfile, err := getDockerfileRelPath(absContextDir, dockerfileName)
+	if err == nil && strings.HasPrefix(relDockerfile, ".."+string(filepath.Separator)) {
+		return "", "", errors.Errorf("the Dockerfile (%s) must be within the build context", dockerfileName)
+	}
+
+	return absContextDir, relDockerfile, err
+}
+
+// GetContextFromURL uses a remote URL as context for a `docker build`. The
+// remote resource is downloaded as either a Dockerfile or a tar archive.
+// Returns the tar archive used for the context and a path of the
+// dockerfile inside the tar.
+func GetContextFromURL(out io.Writer, remoteURL, dockerfileName string) (io.ReadCloser, string, error) {
+	response, err := getWithStatusError(remoteURL)
+	if err != nil {
+		return nil, "", errors.Errorf("unable to download remote context %s: %v", remoteURL, err)
+	}
+	progressOutput := streamformatter.NewProgressOutput(out)
+
+	// Pass the response body through a progress reader.
+	progReader := progress.NewProgressReader(response.Body, progressOutput, response.ContentLength, "", fmt.Sprintf("Downloading build context from remote url: %s", remoteURL))
+
+	return GetContextFromReader(ioutils.NewReadCloserWrapper(progReader, func() error { return response.Body.Close() }), dockerfileName)
+}
+
+// getWithStatusError does an http.Get() and returns an error if the
+// status code is 4xx or 5xx.
+func getWithStatusError(url string) (resp *http.Response, err error) {
+	// #nosec G107
+	if resp, err = http.Get(url); err != nil {
+		return nil, err
+	}
+	if resp.StatusCode < 400 {
+		return resp, nil
+	}
+	msg := fmt.Sprintf("failed to GET %s with status %s", url, resp.Status)
+	body, err := ioutil.ReadAll(resp.Body)
+	resp.Body.Close()
+	if err != nil {
+		return nil, errors.Wrapf(err, "%s: error reading body", msg)
+	}
+	return nil, errors.Errorf("%s: %s", msg, bytes.TrimSpace(body))
+}
+
+// GetContextFromLocalDir uses the given local directory as context for a
+// `docker build`. Returns the absolute path to the local context directory,
+// the relative path of the dockerfile in that context directory, and a non-nil
+// error on success.
+func GetContextFromLocalDir(localDir, dockerfileName string) (string, string, error) {
+	localDir, err := ResolveAndValidateContextPath(localDir)
+	if err != nil {
+		return "", "", err
+	}
+
+	// When using a local context directory, and the Dockerfile is specified
+	// with the `-f/--file` option then it is considered relative to the
+	// current directory and not the context directory.
+	if dockerfileName != "" && dockerfileName != "-" {
+		if dockerfileName, err = filepath.Abs(dockerfileName); err != nil {
+			return "", "", errors.Errorf("unable to get absolute path to Dockerfile: %v", err)
+		}
+	}
+
+	relDockerfile, err := getDockerfileRelPath(localDir, dockerfileName)
+	return localDir, relDockerfile, err
+}
+
+// ResolveAndValidateContextPath uses the given context directory for a `docker build`
+// and returns the absolute path to the context directory.
+func ResolveAndValidateContextPath(givenContextDir string) (string, error) {
+	absContextDir, err := filepath.Abs(givenContextDir)
+	if err != nil {
+		return "", errors.Errorf("unable to get absolute context directory of given context directory %q: %v", givenContextDir, err)
+	}
+
+	// The context dir might be a symbolic link, so follow it to the actual
+	// target directory.
+	//
+	// FIXME. We use isUNC (always false on non-Windows platforms) to workaround
+	// an issue in golang. On Windows, EvalSymLinks does not work on UNC file
+	// paths (those starting with \\). This hack means that when using links
+	// on UNC paths, they will not be followed.
+	if !isUNC(absContextDir) {
+		absContextDir, err = filepath.EvalSymlinks(absContextDir)
+		if err != nil {
+			return "", errors.Errorf("unable to evaluate symlinks in context path: %v", err)
+		}
+	}
+
+	stat, err := os.Lstat(absContextDir)
+	if err != nil {
+		return "", errors.Errorf("unable to stat context directory %q: %v", absContextDir, err)
+	}
+
+	if !stat.IsDir() {
+		return "", errors.Errorf("context must be a directory: %s", absContextDir)
+	}
+	return absContextDir, err
+}
+
+// getDockerfileRelPath returns the dockerfile path relative to the context
+// directory
+func getDockerfileRelPath(absContextDir, givenDockerfile string) (string, error) {
+	var err error
+
+	if givenDockerfile == "-" {
+		return givenDockerfile, nil
+	}
+
+	absDockerfile := givenDockerfile
+	if absDockerfile == "" {
+		// No -f/--file was specified so use the default relative to the
+		// context directory.
+		absDockerfile = filepath.Join(absContextDir, DefaultDockerfileName)
+
+		// Just to be nice ;-) look for 'dockerfile' too but only
+		// use it if we found it, otherwise ignore this check
+		if _, err = os.Lstat(absDockerfile); os.IsNotExist(err) {
+			altPath := filepath.Join(absContextDir, strings.ToLower(DefaultDockerfileName))
+			if _, err = os.Lstat(altPath); err == nil {
+				absDockerfile = altPath
+			}
+		}
+	}
+
+	// If not already an absolute path, the Dockerfile path should be joined to
+	// the base directory.
+	if !filepath.IsAbs(absDockerfile) {
+		absDockerfile = filepath.Join(absContextDir, absDockerfile)
+	}
+
+	// Evaluate symlinks in the path to the Dockerfile too.
+	//
+	// FIXME. We use isUNC (always false on non-Windows platforms) to workaround
+	// an issue in golang. On Windows, EvalSymLinks does not work on UNC file
+	// paths (those starting with \\). This hack means that when using links
+	// on UNC paths, they will not be followed.
+	if !isUNC(absDockerfile) {
+		absDockerfile, err = filepath.EvalSymlinks(absDockerfile)
+		if err != nil {
+			return "", errors.Errorf("unable to evaluate symlinks in Dockerfile path: %v", err)
+		}
+	}
+
+	if _, err := os.Lstat(absDockerfile); err != nil {
+		if os.IsNotExist(err) {
+			return "", errors.Errorf("Cannot locate Dockerfile: %q", absDockerfile)
+		}
+		return "", errors.Errorf("unable to stat Dockerfile: %v", err)
+	}
+
+	relDockerfile, err := filepath.Rel(absContextDir, absDockerfile)
+	if err != nil {
+		return "", errors.Errorf("unable to get relative Dockerfile path: %v", err)
+	}
+
+	return relDockerfile, nil
+}
+
+// isUNC returns true if the path is UNC (one starting \\). It always returns
+// false on Linux.
+func isUNC(path string) bool {
+	return runtime.GOOS == "windows" && strings.HasPrefix(path, `\\`)
+}
+
+// AddDockerfileToBuildContext from a ReadCloser, returns a new archive and
+// the relative path to the dockerfile in the context.
+func AddDockerfileToBuildContext(dockerfileCtx io.ReadCloser, buildCtx io.ReadCloser) (io.ReadCloser, string, error) {
+	file, err := ioutil.ReadAll(dockerfileCtx)
+	dockerfileCtx.Close()
+	if err != nil {
+		return nil, "", err
+	}
+	now := time.Now()
+	hdrTmpl := &tar.Header{
+		Mode:       0600,
+		Uid:        0,
+		Gid:        0,
+		ModTime:    now,
+		Typeflag:   tar.TypeReg,
+		AccessTime: now,
+		ChangeTime: now,
+	}
+	randomName := ".dockerfile." + stringid.GenerateRandomID()[:20]
+
+	buildCtx = archive.ReplaceFileTarWrapper(buildCtx, map[string]archive.TarModifierFunc{
+		// Add the dockerfile with a random filename
+		randomName: func(_ string, h *tar.Header, content io.Reader) (*tar.Header, []byte, error) {
+			return hdrTmpl, file, nil
+		},
+		// Update .dockerignore to include the random filename
+		".dockerignore": func(_ string, h *tar.Header, content io.Reader) (*tar.Header, []byte, error) {
+			if h == nil {
+				h = hdrTmpl
+			}
+
+			b := &bytes.Buffer{}
+			if content != nil {
+				if _, err := b.ReadFrom(content); err != nil {
+					return nil, nil, err
+				}
+			} else {
+				b.WriteString(".dockerignore")
+			}
+			b.WriteString("\n" + randomName + "\n")
+			return h, b.Bytes(), nil
+		},
+	})
+	return buildCtx, randomName, nil
+}
+
+// Compress the build context for sending to the API
+func Compress(buildCtx io.ReadCloser) (io.ReadCloser, error) {
+	pipeReader, pipeWriter := io.Pipe()
+
+	go func() {
+		compressWriter, err := archive.CompressStream(pipeWriter, archive.Gzip)
+		if err != nil {
+			pipeWriter.CloseWithError(err)
+		}
+		defer buildCtx.Close()
+
+		if _, err := pools.Copy(compressWriter, buildCtx); err != nil {
+			pipeWriter.CloseWithError(
+				errors.Wrap(err, "failed to compress context"))
+			compressWriter.Close()
+			return
+		}
+		compressWriter.Close()
+		pipeWriter.Close()
+	}()
+
+	return pipeReader, nil
+}
diff --git a/vendor/github.com/docker/cli/cli/command/image/build/context_unix.go b/vendor/github.com/docker/cli/cli/command/image/build/context_unix.go
new file mode 100644
index 00000000..5bf97c09
--- /dev/null
+++ b/vendor/github.com/docker/cli/cli/command/image/build/context_unix.go
@@ -0,0 +1,12 @@
+//go:build !windows
+// +build !windows
+
+package build
+
+import (
+	"path/filepath"
+)
+
+func getContextRoot(srcPath string) (string, error) {
+	return filepath.Join(srcPath, "."), nil
+}
diff --git a/vendor/github.com/docker/cli/cli/command/image/build/context_windows.go b/vendor/github.com/docker/cli/cli/command/image/build/context_windows.go
new file mode 100644
index 00000000..f127e5a1
--- /dev/null
+++ b/vendor/github.com/docker/cli/cli/command/image/build/context_windows.go
@@ -0,0 +1,15 @@
+package build
+
+import (
+	"path/filepath"
+
+	"github.com/docker/docker/pkg/longpath"
+)
+
+func getContextRoot(srcPath string) (string, error) {
+	cr, err := filepath.Abs(srcPath)
+	if err != nil {
+		return "", err
+	}
+	return longpath.AddPrefix(cr), nil
+}
diff --git a/vendor/github.com/docker/cli/cli/command/image/build/dockerignore.go b/vendor/github.com/docker/cli/cli/command/image/build/dockerignore.go
new file mode 100644
index 00000000..38cde094
--- /dev/null
+++ b/vendor/github.com/docker/cli/cli/command/image/build/dockerignore.go
@@ -0,0 +1,39 @@
+package build
+
+import (
+	"os"
+	"path/filepath"
+
+	"github.com/docker/docker/pkg/fileutils"
+	"github.com/moby/buildkit/frontend/dockerfile/dockerignore"
+)
+
+// ReadDockerignore reads the .dockerignore file in the context directory and
+// returns the list of paths to exclude
+func ReadDockerignore(contextDir string) ([]string, error) {
+	var excludes []string
+
+	f, err := os.Open(filepath.Join(contextDir, ".dockerignore"))
+	switch {
+	case os.IsNotExist(err):
+		return excludes, nil
+	case err != nil:
+		return nil, err
+	}
+	defer f.Close()
+
+	return dockerignore.ReadAll(f)
+}
+
+// TrimBuildFilesFromExcludes removes the named Dockerfile and .dockerignore from
+// the list of excluded files. The daemon will remove them from the final context
+// but they must be in available in the context when passed to the API.
+func TrimBuildFilesFromExcludes(excludes []string, dockerfile string, dockerfileFromStdin bool) []string {
+	if keep, _ := fileutils.Matches(".dockerignore", excludes); keep {
+		excludes = append(excludes, "!.dockerignore")
+	}
+	if keep, _ := fileutils.Matches(dockerfile, excludes); keep && !dockerfileFromStdin {
+		excludes = append(excludes, "!"+dockerfile)
+	}
+	return excludes
+}
diff --git a/vendor/github.com/docker/docker/builder/remotecontext/git/gitutils.go b/vendor/github.com/docker/docker/builder/remotecontext/git/gitutils.go
new file mode 100644
index 00000000..c0f68f8f
--- /dev/null
+++ b/vendor/github.com/docker/docker/builder/remotecontext/git/gitutils.go
@@ -0,0 +1,227 @@
+package git // import "github.com/docker/docker/builder/remotecontext/git"
+
+import (
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/moby/sys/symlink"
+	"github.com/pkg/errors"
+	exec "golang.org/x/sys/execabs"
+)
+
+type gitRepo struct {
+	remote string
+	ref    string
+	subdir string
+}
+
+// Clone clones a repository into a newly created directory which
+// will be under "docker-build-git"
+func Clone(remoteURL string) (string, error) {
+	repo, err := parseRemoteURL(remoteURL)
+
+	if err != nil {
+		return "", err
+	}
+
+	return cloneGitRepo(repo)
+}
+
+func cloneGitRepo(repo gitRepo) (checkoutDir string, err error) {
+	fetch := fetchArgs(repo.remote, repo.ref)
+
+	root, err := ioutil.TempDir("", "docker-build-git")
+	if err != nil {
+		return "", err
+	}
+
+	defer func() {
+		if err != nil {
+			os.RemoveAll(root)
+		}
+	}()
+
+	if out, err := gitWithinDir(root, "init"); err != nil {
+		return "", errors.Wrapf(err, "failed to init repo at %s: %s", root, out)
+	}
+
+	// Add origin remote for compatibility with previous implementation that
+	// used "git clone" and also to make sure local refs are created for branches
+	if out, err := gitWithinDir(root, "remote", "add", "origin", repo.remote); err != nil {
+		return "", errors.Wrapf(err, "failed add origin repo at %s: %s", repo.remote, out)
+	}
+
+	if output, err := gitWithinDir(root, fetch...); err != nil {
+		return "", errors.Wrapf(err, "error fetching: %s", output)
+	}
+
+	checkoutDir, err = checkoutGit(root, repo.ref, repo.subdir)
+	if err != nil {
+		return "", err
+	}
+
+	cmd := exec.Command("git", "submodule", "update", "--init", "--recursive", "--depth=1")
+	cmd.Dir = root
+	output, err := cmd.CombinedOutput()
+	if err != nil {
+		return "", errors.Wrapf(err, "error initializing submodules: %s", output)
+	}
+
+	return checkoutDir, nil
+}
+
+func parseRemoteURL(remoteURL string) (gitRepo, error) {
+	repo := gitRepo{}
+
+	if !isGitTransport(remoteURL) {
+		remoteURL = "https://" + remoteURL
+	}
+
+	var fragment string
+	if strings.HasPrefix(remoteURL, "git@") {
+		// git@.. is not an URL, so cannot be parsed as URL
+		parts := strings.SplitN(remoteURL, "#", 2)
+
+		repo.remote = parts[0]
+		if len(parts) == 2 {
+			fragment = parts[1]
+		}
+		repo.ref, repo.subdir = getRefAndSubdir(fragment)
+	} else {
+		u, err := url.Parse(remoteURL)
+		if err != nil {
+			return repo, err
+		}
+
+		repo.ref, repo.subdir = getRefAndSubdir(u.Fragment)
+		u.Fragment = ""
+		repo.remote = u.String()
+	}
+
+	if strings.HasPrefix(repo.ref, "-") {
+		return gitRepo{}, errors.Errorf("invalid refspec: %s", repo.ref)
+	}
+
+	return repo, nil
+}
+
+func getRefAndSubdir(fragment string) (ref string, subdir string) {
+	refAndDir := strings.SplitN(fragment, ":", 2)
+	ref = "master"
+	if len(refAndDir[0]) != 0 {
+		ref = refAndDir[0]
+	}
+	if len(refAndDir) > 1 && len(refAndDir[1]) != 0 {
+		subdir = refAndDir[1]
+	}
+	return
+}
+
+func fetchArgs(remoteURL string, ref string) []string {
+	args := []string{"fetch"}
+
+	if supportsShallowClone(remoteURL) {
+		args = append(args, "--depth", "1")
+	}
+
+	return append(args, "origin", "--", ref)
+}
+
+// Check if a given git URL supports a shallow git clone,
+// i.e. it is a non-HTTP server or a smart HTTP server.
+func supportsShallowClone(remoteURL string) bool {
+	if scheme := getScheme(remoteURL); scheme == "http" || scheme == "https" {
+		// Check if the HTTP server is smart
+
+		// Smart servers must correctly respond to a query for the git-upload-pack service
+		serviceURL := remoteURL + "/info/refs?service=git-upload-pack"
+
+		// Try a HEAD request and fallback to a Get request on error
+		res, err := http.Head(serviceURL) // #nosec G107
+		if err != nil || res.StatusCode != http.StatusOK {
+			res, err = http.Get(serviceURL) // #nosec G107
+			if err == nil {
+				res.Body.Close()
+			}
+			if err != nil || res.StatusCode != http.StatusOK {
+				// request failed
+				return false
+			}
+		}
+
+		if res.Header.Get("Content-Type") != "application/x-git-upload-pack-advertisement" {
+			// Fallback, not a smart server
+			return false
+		}
+		return true
+	}
+	// Non-HTTP protocols always support shallow clones
+	return true
+}
+
+func checkoutGit(root, ref, subdir string) (string, error) {
+	// Try checking out by ref name first. This will work on branches and sets
+	// .git/HEAD to the current branch name
+	if output, err := gitWithinDir(root, "checkout", ref); err != nil {
+		// If checking out by branch name fails check out the last fetched ref
+		if _, err2 := gitWithinDir(root, "checkout", "FETCH_HEAD"); err2 != nil {
+			return "", errors.Wrapf(err, "error checking out %s: %s", ref, output)
+		}
+	}
+
+	if subdir != "" {
+		newCtx, err := symlink.FollowSymlinkInScope(filepath.Join(root, subdir), root)
+		if err != nil {
+			return "", errors.Wrapf(err, "error setting git context, %q not within git root", subdir)
+		}
+
+		fi, err := os.Stat(newCtx)
+		if err != nil {
+			return "", err
+		}
+		if !fi.IsDir() {
+			return "", errors.Errorf("error setting git context, not a directory: %s", newCtx)
+		}
+		root = newCtx
+	}
+
+	return root, nil
+}
+
+func gitWithinDir(dir string, args ...string) ([]byte, error) {
+	a := []string{"--work-tree", dir, "--git-dir", filepath.Join(dir, ".git")}
+	return git(append(a, args...)...)
+}
+
+func git(args ...string) ([]byte, error) {
+	return exec.Command("git", args...).CombinedOutput()
+}
+
+// isGitTransport returns true if the provided str is a git transport by inspecting
+// the prefix of the string for known protocols used in git.
+func isGitTransport(str string) bool {
+	if strings.HasPrefix(str, "git@") {
+		return true
+	}
+
+	switch getScheme(str) {
+	case "git", "http", "https", "ssh":
+		return true
+	}
+
+	return false
+}
+
+// getScheme returns addresses' scheme in lowercase, or an empty
+// string in case address is an invalid URL.
+func getScheme(address string) string {
+	u, err := url.Parse(address)
+	if err != nil {
+		return ""
+	}
+	return u.Scheme
+}
diff --git a/vendor/github.com/docker/docker/pkg/progress/progress.go b/vendor/github.com/docker/docker/pkg/progress/progress.go
new file mode 100644
index 00000000..32300914
--- /dev/null
+++ b/vendor/github.com/docker/docker/pkg/progress/progress.go
@@ -0,0 +1,93 @@
+package progress // import "github.com/docker/docker/pkg/progress"
+
+import (
+	"fmt"
+)
+
+// Progress represents the progress of a transfer.
+type Progress struct {
+	ID string
+
+	// Progress contains a Message or...
+	Message string
+
+	// ...progress of an action
+	Action  string
+	Current int64
+	Total   int64
+
+	// If true, don't show xB/yB
+	HideCounts bool
+	// If not empty, use units instead of bytes for counts
+	Units string
+
+	// Aux contains extra information not presented to the user, such as
+	// digests for push signing.
+	Aux interface{}
+
+	LastUpdate bool
+}
+
+// Output is an interface for writing progress information. It's
+// like a writer for progress, but we don't call it Writer because
+// that would be confusing next to ProgressReader (also, because it
+// doesn't implement the io.Writer interface).
+type Output interface {
+	WriteProgress(Progress) error
+}
+
+type chanOutput chan<- Progress
+
+func (out chanOutput) WriteProgress(p Progress) error {
+	// FIXME: workaround for panic in #37735
+	defer func() {
+		recover()
+	}()
+	out <- p
+	return nil
+}
+
+// ChanOutput returns an Output that writes progress updates to the
+// supplied channel.
+func ChanOutput(progressChan chan<- Progress) Output {
+	return chanOutput(progressChan)
+}
+
+type discardOutput struct{}
+
+func (discardOutput) WriteProgress(Progress) error {
+	return nil
+}
+
+// DiscardOutput returns an Output that discards progress
+func DiscardOutput() Output {
+	return discardOutput{}
+}
+
+// Update is a convenience function to write a progress update to the channel.
+func Update(out Output, id, action string) {
+	out.WriteProgress(Progress{ID: id, Action: action})
+}
+
+// Updatef is a convenience function to write a printf-formatted progress update
+// to the channel.
+func Updatef(out Output, id, format string, a ...interface{}) {
+	Update(out, id, fmt.Sprintf(format, a...))
+}
+
+// Message is a convenience function to write a progress message to the channel.
+func Message(out Output, id, message string) {
+	out.WriteProgress(Progress{ID: id, Message: message})
+}
+
+// Messagef is a convenience function to write a printf-formatted progress
+// message to the channel.
+func Messagef(out Output, id, format string, a ...interface{}) {
+	Message(out, id, fmt.Sprintf(format, a...))
+}
+
+// Aux sends auxiliary information over a progress interface, which will not be
+// formatted for the UI. This is used for things such as push signing.
+func Aux(out Output, a interface{}) {
+	out.WriteProgress(Progress{Aux: a})
+}
diff --git a/vendor/github.com/docker/docker/pkg/progress/progressreader.go b/vendor/github.com/docker/docker/pkg/progress/progressreader.go
new file mode 100644
index 00000000..07450a2d
--- /dev/null
+++ b/vendor/github.com/docker/docker/pkg/progress/progressreader.go
@@ -0,0 +1,66 @@
+package progress // import "github.com/docker/docker/pkg/progress"
+
+import (
+	"io"
+	"time"
+
+	"golang.org/x/time/rate"
+)
+
+// Reader is a Reader with progress bar.
+type Reader struct {
+	in          io.ReadCloser // Stream to read from
+	out         Output        // Where to send progress bar to
+	size        int64
+	current     int64
+	lastUpdate  int64
+	id          string
+	action      string
+	rateLimiter *rate.Limiter
+}
+
+// NewProgressReader creates a new ProgressReader.
+func NewProgressReader(in io.ReadCloser, out Output, size int64, id, action string) *Reader {
+	return &Reader{
+		in:          in,
+		out:         out,
+		size:        size,
+		id:          id,
+		action:      action,
+		rateLimiter: rate.NewLimiter(rate.Every(100*time.Millisecond), 1),
+	}
+}
+
+func (p *Reader) Read(buf []byte) (n int, err error) {
+	read, err := p.in.Read(buf)
+	p.current += int64(read)
+	updateEvery := int64(1024 * 512) // 512kB
+	if p.size > 0 {
+		// Update progress for every 1% read if 1% < 512kB
+		if increment := int64(0.01 * float64(p.size)); increment < updateEvery {
+			updateEvery = increment
+		}
+	}
+	if p.current-p.lastUpdate > updateEvery || err != nil {
+		p.updateProgress(err != nil && read == 0)
+		p.lastUpdate = p.current
+	}
+
+	return read, err
+}
+
+// Close closes the progress reader and its underlying reader.
+func (p *Reader) Close() error {
+	if p.current < p.size {
+		// print a full progress bar when closing prematurely
+		p.current = p.size
+		p.updateProgress(false)
+	}
+	return p.in.Close()
+}
+
+func (p *Reader) updateProgress(last bool) {
+	if last || p.current == p.size || p.rateLimiter.Allow() {
+		p.out.WriteProgress(Progress{ID: p.id, Action: p.action, Current: p.current, Total: p.size, LastUpdate: last})
+	}
+}
diff --git a/vendor/github.com/docker/docker/pkg/streamformatter/streamformatter.go b/vendor/github.com/docker/docker/pkg/streamformatter/streamformatter.go
new file mode 100644
index 00000000..b0456e58
--- /dev/null
+++ b/vendor/github.com/docker/docker/pkg/streamformatter/streamformatter.go
@@ -0,0 +1,159 @@
+// Package streamformatter provides helper functions to format a stream.
+package streamformatter // import "github.com/docker/docker/pkg/streamformatter"
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+
+	"github.com/docker/docker/pkg/jsonmessage"
+	"github.com/docker/docker/pkg/progress"
+)
+
+const streamNewline = "\r\n"
+
+type jsonProgressFormatter struct{}
+
+func appendNewline(source []byte) []byte {
+	return append(source, []byte(streamNewline)...)
+}
+
+// FormatStatus formats the specified objects according to the specified format (and id).
+func FormatStatus(id, format string, a ...interface{}) []byte {
+	str := fmt.Sprintf(format, a...)
+	b, err := json.Marshal(&jsonmessage.JSONMessage{ID: id, Status: str})
+	if err != nil {
+		return FormatError(err)
+	}
+	return appendNewline(b)
+}
+
+// FormatError formats the error as a JSON object
+func FormatError(err error) []byte {
+	jsonError, ok := err.(*jsonmessage.JSONError)
+	if !ok {
+		jsonError = &jsonmessage.JSONError{Message: err.Error()}
+	}
+	if b, err := json.Marshal(&jsonmessage.JSONMessage{Error: jsonError, ErrorMessage: err.Error()}); err == nil {
+		return appendNewline(b)
+	}
+	return []byte(`{"error":"format error"}` + streamNewline)
+}
+
+func (sf *jsonProgressFormatter) formatStatus(id, format string, a ...interface{}) []byte {
+	return FormatStatus(id, format, a...)
+}
+
+// formatProgress formats the progress information for a specified action.
+func (sf *jsonProgressFormatter) formatProgress(id, action string, progress *jsonmessage.JSONProgress, aux interface{}) []byte {
+	if progress == nil {
+		progress = &jsonmessage.JSONProgress{}
+	}
+	var auxJSON *json.RawMessage
+	if aux != nil {
+		auxJSONBytes, err := json.Marshal(aux)
+		if err != nil {
+			return nil
+		}
+		auxJSON = new(json.RawMessage)
+		*auxJSON = auxJSONBytes
+	}
+	b, err := json.Marshal(&jsonmessage.JSONMessage{
+		Status:          action,
+		ProgressMessage: progress.String(),
+		Progress:        progress,
+		ID:              id,
+		Aux:             auxJSON,
+	})
+	if err != nil {
+		return nil
+	}
+	return appendNewline(b)
+}
+
+type rawProgressFormatter struct{}
+
+func (sf *rawProgressFormatter) formatStatus(id, format string, a ...interface{}) []byte {
+	return []byte(fmt.Sprintf(format, a...) + streamNewline)
+}
+
+func (sf *rawProgressFormatter) formatProgress(id, action string, progress *jsonmessage.JSONProgress, aux interface{}) []byte {
+	if progress == nil {
+		progress = &jsonmessage.JSONProgress{}
+	}
+	endl := "\r"
+	if progress.String() == "" {
+		endl += "\n"
+	}
+	return []byte(action + " " + progress.String() + endl)
+}
+
+// NewProgressOutput returns a progress.Output object that can be passed to
+// progress.NewProgressReader.
+func NewProgressOutput(out io.Writer) progress.Output {
+	return &progressOutput{sf: &rawProgressFormatter{}, out: out, newLines: true}
+}
+
+// NewJSONProgressOutput returns a progress.Output that formats output
+// using JSON objects
+func NewJSONProgressOutput(out io.Writer, newLines bool) progress.Output {
+	return &progressOutput{sf: &jsonProgressFormatter{}, out: out, newLines: newLines}
+}
+
+type formatProgress interface {
+	formatStatus(id, format string, a ...interface{}) []byte
+	formatProgress(id, action string, progress *jsonmessage.JSONProgress, aux interface{}) []byte
+}
+
+type progressOutput struct {
+	sf       formatProgress
+	out      io.Writer
+	newLines bool
+}
+
+// WriteProgress formats progress information from a ProgressReader.
+func (out *progressOutput) WriteProgress(prog progress.Progress) error {
+	var formatted []byte
+	if prog.Message != "" {
+		formatted = out.sf.formatStatus(prog.ID, prog.Message)
+	} else {
+		jsonProgress := jsonmessage.JSONProgress{Current: prog.Current, Total: prog.Total, HideCounts: prog.HideCounts, Units: prog.Units}
+		formatted = out.sf.formatProgress(prog.ID, prog.Action, &jsonProgress, prog.Aux)
+	}
+	_, err := out.out.Write(formatted)
+	if err != nil {
+		return err
+	}
+
+	if out.newLines && prog.LastUpdate {
+		_, err = out.out.Write(out.sf.formatStatus("", ""))
+		return err
+	}
+
+	return nil
+}
+
+// AuxFormatter is a streamFormatter that writes aux progress messages
+type AuxFormatter struct {
+	io.Writer
+}
+
+// Emit emits the given interface as an aux progress message
+func (sf *AuxFormatter) Emit(id string, aux interface{}) error {
+	auxJSONBytes, err := json.Marshal(aux)
+	if err != nil {
+		return err
+	}
+	auxJSON := new(json.RawMessage)
+	*auxJSON = auxJSONBytes
+	msgJSON, err := json.Marshal(&jsonmessage.JSONMessage{ID: id, Aux: auxJSON})
+	if err != nil {
+		return err
+	}
+	msgJSON = appendNewline(msgJSON)
+	n, err := sf.Writer.Write(msgJSON)
+	if n != len(msgJSON) {
+		return io.ErrShortWrite
+	}
+	return err
+}
diff --git a/vendor/github.com/docker/docker/pkg/streamformatter/streamwriter.go b/vendor/github.com/docker/docker/pkg/streamformatter/streamwriter.go
new file mode 100644
index 00000000..1473ed97
--- /dev/null
+++ b/vendor/github.com/docker/docker/pkg/streamformatter/streamwriter.go
@@ -0,0 +1,47 @@
+package streamformatter // import "github.com/docker/docker/pkg/streamformatter"
+
+import (
+	"encoding/json"
+	"io"
+
+	"github.com/docker/docker/pkg/jsonmessage"
+)
+
+type streamWriter struct {
+	io.Writer
+	lineFormat func([]byte) string
+}
+
+func (sw *streamWriter) Write(buf []byte) (int, error) {
+	formattedBuf := sw.format(buf)
+	n, err := sw.Writer.Write(formattedBuf)
+	if n != len(formattedBuf) {
+		return n, io.ErrShortWrite
+	}
+	return len(buf), err
+}
+
+func (sw *streamWriter) format(buf []byte) []byte {
+	msg := &jsonmessage.JSONMessage{Stream: sw.lineFormat(buf)}
+	b, err := json.Marshal(msg)
+	if err != nil {
+		return FormatError(err)
+	}
+	return appendNewline(b)
+}
+
+// NewStdoutWriter returns a writer which formats the output as json message
+// representing stdout lines
+func NewStdoutWriter(out io.Writer) io.Writer {
+	return &streamWriter{Writer: out, lineFormat: func(buf []byte) string {
+		return string(buf)
+	}}
+}
+
+// NewStderrWriter returns a writer which formats the output as json message
+// representing stderr lines
+func NewStderrWriter(out io.Writer) io.Writer {
+	return &streamWriter{Writer: out, lineFormat: func(buf []byte) string {
+		return "\033[91m" + string(buf) + "\033[0m"
+	}}
+}
diff --git a/vendor/github.com/docker/docker/pkg/stringid/README.md b/vendor/github.com/docker/docker/pkg/stringid/README.md
new file mode 100644
index 00000000..37a5098f
--- /dev/null
+++ b/vendor/github.com/docker/docker/pkg/stringid/README.md
@@ -0,0 +1,1 @@
+This package provides helper functions for dealing with string identifiers
diff --git a/vendor/github.com/docker/docker/pkg/stringid/stringid.go b/vendor/github.com/docker/docker/pkg/stringid/stringid.go
new file mode 100644
index 00000000..5fe071d6
--- /dev/null
+++ b/vendor/github.com/docker/docker/pkg/stringid/stringid.go
@@ -0,0 +1,63 @@
+// Package stringid provides helper functions for dealing with string identifiers
+package stringid // import "github.com/docker/docker/pkg/stringid"
+
+import (
+	"crypto/rand"
+	"encoding/hex"
+	"fmt"
+	"regexp"
+	"strconv"
+	"strings"
+)
+
+const shortLen = 12
+
+var (
+	validShortID = regexp.MustCompile("^[a-f0-9]{12}$")
+	validHex     = regexp.MustCompile(`^[a-f0-9]{64}$`)
+)
+
+// IsShortID determines if an arbitrary string *looks like* a short ID.
+func IsShortID(id string) bool {
+	return validShortID.MatchString(id)
+}
+
+// TruncateID returns a shorthand version of a string identifier for convenience.
+// A collision with other shorthands is very unlikely, but possible.
+// In case of a collision a lookup with TruncIndex.Get() will fail, and the caller
+// will need to use a longer prefix, or the full-length Id.
+func TruncateID(id string) string {
+	if i := strings.IndexRune(id, ':'); i >= 0 {
+		id = id[i+1:]
+	}
+	if len(id) > shortLen {
+		id = id[:shortLen]
+	}
+	return id
+}
+
+// GenerateRandomID returns a unique id.
+func GenerateRandomID() string {
+	b := make([]byte, 32)
+	for {
+		if _, err := rand.Read(b); err != nil {
+			panic(err) // This shouldn't happen
+		}
+		id := hex.EncodeToString(b)
+		// if we try to parse the truncated for as an int and we don't have
+		// an error then the value is all numeric and causes issues when
+		// used as a hostname. ref #3869
+		if _, err := strconv.ParseInt(TruncateID(id), 10, 64); err == nil {
+			continue
+		}
+		return id
+	}
+}
+
+// ValidateID checks whether an ID string is a valid image ID.
+func ValidateID(id string) error {
+	if ok := validHex.MatchString(id); !ok {
+		return fmt.Errorf("image ID %q is invalid", id)
+	}
+	return nil
+}
diff --git a/vendor/github.com/moby/buildkit/AUTHORS b/vendor/github.com/moby/buildkit/AUTHORS
new file mode 100644
index 00000000..c1dce655
--- /dev/null
+++ b/vendor/github.com/moby/buildkit/AUTHORS
@@ -0,0 +1,66 @@
+# This file lists all individuals having contributed content to the repository.
+# For how it is generated, see `scripts/generate-authors.sh`.
+
+Aaron L. Xu <likexu@harmonycloud.cn>
+Aaron Lehmann <aaron.lehmann@docker.com>
+Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
+Alexander Morozov <lk4d4@docker.com>
+Alice Frosi <afrosi@de.ibm.com>
+Allen Sun <allen.sun@daocloud.io>
+Anda Xu <anda.xu@docker.com>
+Anthony Sottile <asottile@umich.edu>
+Arnaud Bailly <arnaud.oqube@gmail.com>
+Bin Liu <liubin0329@gmail.com>
+Brian Goff <cpuguy83@gmail.com>
+Daniel Nephin <dnephin@gmail.com>
+Dave Chen <dave.chen@arm.com>
+David Calavera <david.calavera@gmail.com>
+Dennis Chen <dennis.chen@arm.com>
+Derek McGowan <derek@mcgstyle.net>
+Doug Davis <dug@us.ibm.com>
+Edgar Lee <edgarl@netflix.com>
+Eli Uriegas <eli.uriegas@docker.com>
+f0 <f0@users.noreply.github.com>
+Fernando Miguel <github@FernandoMiguel.net>
+Hao Hu <hao.hu.fr@gmail.com>
+Helen Xie <chenjg@harmonycloud.cn>
+Himanshu Pandey <hpandey@pivotal.io>
+Hiromu Nakamura <abctail30@gmail.com>
+Ian Campbell <ijc@docker.com>
+Iskander (Alex) Sharipov <quasilyte@gmail.com>
+Jean-Pierre Huynh <jean-pierre.huynh@ounet.fr>
+Jessica Frazelle <acidburn@microsoft.com>
+John Howard <jhoward@microsoft.com>
+Jonathan Stoppani <jonathan.stoppani@divio.com>
+Justas Brazauskas <brazauskasjustas@gmail.com>
+Justin Cormack <justin.cormack@docker.com>
+Kunal Kushwaha <kushwaha_kunal_v7@lab.ntt.co.jp>
+Lajos Papp <lalyos@yahoo.com>
+Matt Rickard <mrick@google.com>
+Michael Crosby <crosbymichael@gmail.com>
+Miyachi Katsuya <miyachi_katsuya@r.recruit.co.jp>
+Nao YONASHIRO <yonashiro@r.recruit.co.jp>
+Natasha Jarus <linuxmercedes@gmail.com>
+Noel Georgi <18496730+frezbo@users.noreply.github.com>
+Ondrej Fabry <ofabry@cisco.com>
+Patrick Van Stee <patrick@vanstee.me>
+Ri Xu <xuri.me@gmail.com>
+Sebastiaan van Stijn <github@gone.nl>
+Shev Yan <yandong_8212@163.com>
+Simon Ferquel <simon.ferquel@docker.com>
+Stefan Weil <sw@weilnetz.de>
+Thomas Leonard <thomas.leonard@docker.com>
+Thomas Shaw <tomwillfixit@users.noreply.github.com>
+Tibor Vass <tibor@docker.com>
+Tiffany Jernigan <tiffany.f.j@gmail.com>
+Tino Rusch <tino.rusch@gmail.com>
+Tobias Klauser <tklauser@distanz.ch>
+Tomas Tomecek <ttomecek@redhat.com>
+Tomohiro Kusumoto <zabio1192@gmail.com>
+Tõnis Tiigi <tonistiigi@gmail.com>
+Vincent Demeester <vincent.demeester@docker.com>
+Wei Fu <fuweid89@gmail.com>
+Yong Tang <yong.tang.github@outlook.com>
+Yuichiro Kaneko <spiketeika@gmail.com>
+Ziv Tsarfati <digger18@gmail.com>
+郑泽宇 <perhapszzy@sina.com>
diff --git a/vendor/github.com/moby/buildkit/LICENSE b/vendor/github.com/moby/buildkit/LICENSE
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/vendor/github.com/moby/buildkit/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerignore/dockerignore.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerignore/dockerignore.go
new file mode 100644
index 00000000..cc223813
--- /dev/null
+++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerignore/dockerignore.go
@@ -0,0 +1,64 @@
+package dockerignore
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+	"path/filepath"
+	"strings"
+)
+
+// ReadAll reads a .dockerignore file and returns the list of file patterns
+// to ignore. Note this will trim whitespace from each line as well
+// as use GO's "clean" func to get the shortest/cleanest path for each.
+func ReadAll(reader io.Reader) ([]string, error) {
+	if reader == nil {
+		return nil, nil
+	}
+
+	scanner := bufio.NewScanner(reader)
+	var excludes []string
+	currentLine := 0
+
+	utf8bom := []byte{0xEF, 0xBB, 0xBF}
+	for scanner.Scan() {
+		scannedBytes := scanner.Bytes()
+		// We trim UTF8 BOM
+		if currentLine == 0 {
+			scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom)
+		}
+		pattern := string(scannedBytes)
+		currentLine++
+		// Lines starting with # (comments) are ignored before processing
+		if strings.HasPrefix(pattern, "#") {
+			continue
+		}
+		pattern = strings.TrimSpace(pattern)
+		if pattern == "" {
+			continue
+		}
+		// normalize absolute paths to paths relative to the context
+		// (taking care of '!' prefix)
+		invert := pattern[0] == '!'
+		if invert {
+			pattern = strings.TrimSpace(pattern[1:])
+		}
+		if len(pattern) > 0 {
+			pattern = filepath.Clean(pattern)
+			pattern = filepath.ToSlash(pattern)
+			if len(pattern) > 1 && pattern[0] == '/' {
+				pattern = pattern[1:]
+			}
+		}
+		if invert {
+			pattern = "!" + pattern
+		}
+
+		excludes = append(excludes, pattern)
+	}
+	if err := scanner.Err(); err != nil {
+		return nil, fmt.Errorf("Error reading .dockerignore: %v", err)
+	}
+	return excludes, nil
+}
diff --git a/vendor/github.com/moby/sys/symlink/LICENSE b/vendor/github.com/moby/sys/symlink/LICENSE
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/vendor/github.com/moby/sys/symlink/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/vendor/github.com/moby/sys/symlink/LICENSE.APACHE b/vendor/github.com/moby/sys/symlink/LICENSE.APACHE
new file mode 100644
index 00000000..5d80670b
--- /dev/null
+++ b/vendor/github.com/moby/sys/symlink/LICENSE.APACHE
@@ -0,0 +1,191 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   Copyright 2014-2018 Docker, Inc.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/vendor/github.com/moby/sys/symlink/LICENSE.BSD b/vendor/github.com/moby/sys/symlink/LICENSE.BSD
new file mode 100644
index 00000000..2ee8768d
--- /dev/null
+++ b/vendor/github.com/moby/sys/symlink/LICENSE.BSD
@@ -0,0 +1,27 @@
+Copyright (c) 2014-2018 The Docker & Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/moby/sys/symlink/README.md b/vendor/github.com/moby/sys/symlink/README.md
new file mode 100644
index 00000000..8dba54fd
--- /dev/null
+++ b/vendor/github.com/moby/sys/symlink/README.md
@@ -0,0 +1,6 @@
+Package symlink implements EvalSymlinksInScope which is an extension of filepath.EvalSymlinks,
+as well as a Windows long-path aware version of filepath.EvalSymlinks
+from the [Go standard library](https://golang.org/pkg/path/filepath).
+
+The code from filepath.EvalSymlinks has been adapted in fs.go.
+Please read the LICENSE.BSD file that governs fs.go and LICENSE.APACHE for fs_test.go.
diff --git a/vendor/github.com/moby/sys/symlink/doc.go b/vendor/github.com/moby/sys/symlink/doc.go
new file mode 100644
index 00000000..d2de7ecd
--- /dev/null
+++ b/vendor/github.com/moby/sys/symlink/doc.go
@@ -0,0 +1,4 @@
+// Package symlink implements EvalSymlinksInScope which is an extension of
+// filepath.EvalSymlinks, as well as a Windows long-path aware version of
+// filepath.EvalSymlinks from the Go standard library (https://golang.org/pkg/path/filepath).
+package symlink
diff --git a/vendor/github.com/moby/sys/symlink/fs.go b/vendor/github.com/moby/sys/symlink/fs.go
new file mode 100644
index 00000000..244b0096
--- /dev/null
+++ b/vendor/github.com/moby/sys/symlink/fs.go
@@ -0,0 +1,142 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE.BSD file.
+
+// This code is a modified version of path/filepath/symlink.go from the Go standard library.
+
+package symlink
+
+import (
+	"bytes"
+	"errors"
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+// FollowSymlinkInScope is a wrapper around evalSymlinksInScope that returns an
+// absolute path. This function handles paths in a platform-agnostic manner.
+func FollowSymlinkInScope(path, root string) (string, error) {
+	path, err := filepath.Abs(filepath.FromSlash(path))
+	if err != nil {
+		return "", err
+	}
+	root, err = filepath.Abs(filepath.FromSlash(root))
+	if err != nil {
+		return "", err
+	}
+	return evalSymlinksInScope(path, root)
+}
+
+// evalSymlinksInScope will evaluate symlinks in `path` within a scope `root` and return
+// a result guaranteed to be contained within the scope `root`, at the time of the call.
+// Symlinks in `root` are not evaluated and left as-is.
+// Errors encountered while attempting to evaluate symlinks in path will be returned.
+// Non-existing paths are valid and do not constitute an error.
+// `path` has to contain `root` as a prefix, or else an error will be returned.
+// Trying to break out from `root` does not constitute an error.
+//
+// Example:
+//   If /foo/bar -> /outside,
+//   FollowSymlinkInScope("/foo/bar", "/foo") == "/foo/outside" instead of "/outside"
+//
+// IMPORTANT: it is the caller's responsibility to call evalSymlinksInScope *after* relevant symlinks
+// are created and not to create subsequently, additional symlinks that could potentially make a
+// previously-safe path, unsafe. Example: if /foo/bar does not exist, evalSymlinksInScope("/foo/bar", "/foo")
+// would return "/foo/bar". If one makes /foo/bar a symlink to /baz subsequently, then "/foo/bar" should
+// no longer be considered safely contained in "/foo".
+func evalSymlinksInScope(path, root string) (string, error) {
+	root = filepath.Clean(root)
+	if path == root {
+		return path, nil
+	}
+	if !strings.HasPrefix(path, root) {
+		return "", errors.New("evalSymlinksInScope: " + path + " is not in " + root)
+	}
+	const maxIter = 255
+	originalPath := path
+	// given root of "/a" and path of "/a/b/../../c" we want path to be "/b/../../c"
+	path = path[len(root):]
+	if root == string(filepath.Separator) {
+		path = string(filepath.Separator) + path
+	}
+	if !strings.HasPrefix(path, string(filepath.Separator)) {
+		return "", errors.New("evalSymlinksInScope: " + path + " is not in " + root)
+	}
+	path = filepath.Clean(path)
+	// consume path by taking each frontmost path element,
+	// expanding it if it's a symlink, and appending it to b
+	var b bytes.Buffer
+	// b here will always be considered to be the "current absolute path inside
+	// root" when we append paths to it, we also append a slash and use
+	// filepath.Clean after the loop to trim the trailing slash
+	for n := 0; path != ""; n++ {
+		if n > maxIter {
+			return "", errors.New("evalSymlinksInScope: too many links in " + originalPath)
+		}
+
+		// find next path component, p
+		i := strings.IndexRune(path, filepath.Separator)
+		var p string
+		if i == -1 {
+			p, path = path, ""
+		} else {
+			p, path = path[:i], path[i+1:]
+		}
+
+		if p == "" {
+			continue
+		}
+
+		// this takes a b.String() like "b/../" and a p like "c" and turns it
+		// into "/b/../c" which then gets filepath.Cleaned into "/c" and then
+		// root gets prepended and we Clean again (to remove any trailing slash
+		// if the first Clean gave us just "/")
+		cleanP := filepath.Clean(string(filepath.Separator) + b.String() + p)
+		if isDriveOrRoot(cleanP) {
+			// never Lstat "/" itself, or drive letters on Windows
+			b.Reset()
+			continue
+		}
+		fullP := filepath.Clean(root + cleanP)
+
+		fi, err := os.Lstat(fullP)
+		if os.IsNotExist(err) {
+			// if p does not exist, accept it
+			b.WriteString(p)
+			b.WriteRune(filepath.Separator)
+			continue
+		}
+		if err != nil {
+			return "", err
+		}
+		if fi.Mode()&os.ModeSymlink == 0 {
+			b.WriteString(p)
+			b.WriteRune(filepath.Separator)
+			continue
+		}
+
+		// it's a symlink, put it at the front of path
+		dest, err := os.Readlink(fullP)
+		if err != nil {
+			return "", err
+		}
+		if isAbs(dest) {
+			b.Reset()
+		}
+		path = dest + string(filepath.Separator) + path
+	}
+
+	// see note above on "fullP := ..." for why this is double-cleaned and
+	// what's happening here
+	return filepath.Clean(root + filepath.Clean(string(filepath.Separator)+b.String())), nil
+}
+
+// EvalSymlinks returns the path name after the evaluation of any symbolic
+// links.
+// If path is relative the result will be relative to the current directory,
+// unless one of the components is an absolute symbolic link.
+// This version has been updated to support long paths prepended with `\\?\`.
+func EvalSymlinks(path string) (string, error) {
+	return evalSymlinks(path)
+}
diff --git a/vendor/github.com/moby/sys/symlink/fs_unix.go b/vendor/github.com/moby/sys/symlink/fs_unix.go
new file mode 100644
index 00000000..13ce8251
--- /dev/null
+++ b/vendor/github.com/moby/sys/symlink/fs_unix.go
@@ -0,0 +1,18 @@
+//go:build !windows
+// +build !windows
+
+package symlink
+
+import (
+	"path/filepath"
+)
+
+func evalSymlinks(path string) (string, error) {
+	return filepath.EvalSymlinks(path)
+}
+
+func isDriveOrRoot(p string) bool {
+	return p == string(filepath.Separator)
+}
+
+var isAbs = filepath.IsAbs
diff --git a/vendor/github.com/moby/sys/symlink/fs_windows.go b/vendor/github.com/moby/sys/symlink/fs_windows.go
new file mode 100644
index 00000000..87fd1b88
--- /dev/null
+++ b/vendor/github.com/moby/sys/symlink/fs_windows.go
@@ -0,0 +1,185 @@
+package symlink
+
+import (
+	"bytes"
+	"errors"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"golang.org/x/sys/windows"
+)
+
+func toShort(path string) (string, error) {
+	p, err := windows.UTF16FromString(path)
+	if err != nil {
+		return "", err
+	}
+	b := p // GetShortPathName says we can reuse buffer
+	n, err := windows.GetShortPathName(&p[0], &b[0], uint32(len(b)))
+	if err != nil {
+		return "", err
+	}
+	if n > uint32(len(b)) {
+		b = make([]uint16, n)
+		if _, err = windows.GetShortPathName(&p[0], &b[0], uint32(len(b))); err != nil {
+			return "", err
+		}
+	}
+	return windows.UTF16ToString(b), nil
+}
+
+func toLong(path string) (string, error) {
+	p, err := windows.UTF16FromString(path)
+	if err != nil {
+		return "", err
+	}
+	b := p // GetLongPathName says we can reuse buffer
+	n, err := windows.GetLongPathName(&p[0], &b[0], uint32(len(b)))
+	if err != nil {
+		return "", err
+	}
+	if n > uint32(len(b)) {
+		b = make([]uint16, n)
+		n, err = windows.GetLongPathName(&p[0], &b[0], uint32(len(b)))
+		if err != nil {
+			return "", err
+		}
+	}
+	b = b[:n]
+	return windows.UTF16ToString(b), nil
+}
+
+func evalSymlinks(path string) (string, error) {
+	path, err := walkSymlinks(path)
+	if err != nil {
+		return "", err
+	}
+
+	p, err := toShort(path)
+	if err != nil {
+		return "", err
+	}
+	p, err = toLong(p)
+	if err != nil {
+		return "", err
+	}
+	// windows.GetLongPathName does not change the case of the drive letter,
+	// but the result of EvalSymlinks must be unique, so we have
+	// EvalSymlinks(`c:\a`) == EvalSymlinks(`C:\a`).
+	// Make drive letter upper case.
+	if len(p) >= 2 && p[1] == ':' && 'a' <= p[0] && p[0] <= 'z' {
+		p = string(p[0]+'A'-'a') + p[1:]
+	} else if len(p) >= 6 && p[5] == ':' && 'a' <= p[4] && p[4] <= 'z' {
+		p = p[:3] + string(p[4]+'A'-'a') + p[5:]
+	}
+	return filepath.Clean(p), nil
+}
+
+const (
+	utf8RuneSelf   = 0x80
+	longPathPrefix = `\\?\`
+)
+
+func walkSymlinks(path string) (string, error) {
+	const maxIter = 255
+	originalPath := path
+	// consume path by taking each frontmost path element,
+	// expanding it if it's a symlink, and appending it to b
+	var b bytes.Buffer
+	for n := 0; path != ""; n++ {
+		if n > maxIter {
+			return "", errors.New("too many links in " + originalPath)
+		}
+
+		// A path beginning with `\\?\` represents the root, so automatically
+		// skip that part and begin processing the next segment.
+		if strings.HasPrefix(path, longPathPrefix) {
+			b.WriteString(longPathPrefix)
+			path = path[4:]
+			continue
+		}
+
+		// find next path component, p
+		i := -1
+		for j, c := range path {
+			if c < utf8RuneSelf && os.IsPathSeparator(uint8(c)) {
+				i = j
+				break
+			}
+		}
+		var p string
+		if i == -1 {
+			p, path = path, ""
+		} else {
+			p, path = path[:i], path[i+1:]
+		}
+
+		if p == "" {
+			if b.Len() == 0 {
+				// must be absolute path
+				b.WriteRune(filepath.Separator)
+			}
+			continue
+		}
+
+		// If this is the first segment after the long path prefix, accept the
+		// current segment as a volume root or UNC share and move on to the next.
+		if b.String() == longPathPrefix {
+			b.WriteString(p)
+			b.WriteRune(filepath.Separator)
+			continue
+		}
+
+		fi, err := os.Lstat(b.String() + p)
+		if err != nil {
+			return "", err
+		}
+		if fi.Mode()&os.ModeSymlink == 0 {
+			b.WriteString(p)
+			if path != "" || (b.Len() == 2 && len(p) == 2 && p[1] == ':') {
+				b.WriteRune(filepath.Separator)
+			}
+			continue
+		}
+
+		// it's a symlink, put it at the front of path
+		dest, err := os.Readlink(b.String() + p)
+		if err != nil {
+			return "", err
+		}
+		if isAbs(dest) {
+			b.Reset()
+		}
+		path = dest + string(filepath.Separator) + path
+	}
+	return filepath.Clean(b.String()), nil
+}
+
+func isDriveOrRoot(p string) bool {
+	if p == string(filepath.Separator) {
+		return true
+	}
+
+	length := len(p)
+	if length >= 2 {
+		if p[length-1] == ':' && (('a' <= p[length-2] && p[length-2] <= 'z') || ('A' <= p[length-2] && p[length-2] <= 'Z')) {
+			return true
+		}
+	}
+	return false
+}
+
+// isAbs is a platform-specific wrapper for filepath.IsAbs. On Windows,
+// golang filepath.IsAbs does not consider a path \windows\system32 as absolute
+// as it doesn't start with a drive-letter/colon combination. However, in
+// docker we need to verify things such as WORKDIR /windows/system32 in
+// a Dockerfile (which gets translated to \windows\system32 when being processed
+// by the daemon. This SHOULD be treated as absolute from a docker processing
+// perspective.
+func isAbs(path string) bool {
+	if filepath.IsAbs(path) || strings.HasPrefix(path, string(os.PathSeparator)) {
+		return true
+	}
+	return false
+}
diff --git a/vendor/github.com/moby/term/.gitignore b/vendor/github.com/moby/term/.gitignore
index df63b129..b0747ff0 100644
--- a/vendor/github.com/moby/term/.gitignore
+++ b/vendor/github.com/moby/term/.gitignore
@@ -1,24 +1,8 @@
-# Docker project generated files to ignore
-#  if you want to ignore files created by your editor/tools,
-#  please consider a global .gitignore https://help.github.com/articles/ignoring-files
-*.exe
-*.exe~
-*.gz
-*.orig
-test.main
-.*.swp
-.DS_Store
-# a .bashrc may be added to customize the build environment
-.bashrc
-.editorconfig
-.gopath/
-.go-pkg-cache/
-.idea/
-autogen/
-bundles/
-cmd/dockerd/dockerd
-contrib/builder/rpm/*/changelog
-vendor/pkg/
-go-test-report.json
+# if you want to ignore files created by your editor/tools, consider using a
+# global .gitignore or .git/info/exclude see https://help.github.com/articles/ignoring-files
+.*
+!.github
+!.gitignore
 profile.out
-junit-report.xml
+# support running go modules in vendor mode for local development
+vendor/
diff --git a/vendor/github.com/moby/term/README.md b/vendor/github.com/moby/term/README.md
new file mode 100644
index 00000000..0ce92cc3
--- /dev/null
+++ b/vendor/github.com/moby/term/README.md
@@ -0,0 +1,36 @@
+# term - utilities for dealing with terminals
+
+![Test](https://github.com/moby/term/workflows/Test/badge.svg) [![GoDoc](https://godoc.org/github.com/moby/term?status.svg)](https://godoc.org/github.com/moby/term) [![Go Report Card](https://goreportcard.com/badge/github.com/moby/term)](https://goreportcard.com/report/github.com/moby/term)
+
+term provides structures and helper functions to work with terminal (state, sizes).
+
+#### Using term
+
+```go
+package main
+
+import (
+	"log"
+	"os"
+
+	"github.com/moby/term"
+)
+
+func main() {
+	fd := os.Stdin.Fd()
+	if term.IsTerminal(fd) {
+		ws, err := term.GetWinsize(fd)
+		if err != nil {
+			log.Fatalf("term.GetWinsize: %s", err)
+		}
+		log.Printf("%d:%d\n", ws.Height, ws.Width)
+	}
+}
+```
+
+## Contributing
+
+Want to hack on term? [Docker's contributions guidelines](https://github.com/docker/docker/blob/master/CONTRIBUTING.md) apply.
+
+## Copyright and license
+Code and documentation copyright 2015 Docker, inc. Code released under the Apache 2.0 license. Docs released under Creative commons.
diff --git a/vendor/github.com/moby/term/ascii.go b/vendor/github.com/moby/term/ascii.go
index 7c445686..55873c05 100644
--- a/vendor/github.com/moby/term/ascii.go
+++ b/vendor/github.com/moby/term/ascii.go
@@ -1,4 +1,4 @@
-package term // import "github.com/moby/term"
+package term
 
 import (
 	"fmt"
diff --git a/vendor/github.com/moby/term/proxy.go b/vendor/github.com/moby/term/proxy.go
index 9573222f..c47756b8 100644
--- a/vendor/github.com/moby/term/proxy.go
+++ b/vendor/github.com/moby/term/proxy.go
@@ -1,4 +1,4 @@
-package term // import "github.com/moby/term"
+package term
 
 import (
 	"io"
@@ -19,6 +19,7 @@ type escapeProxy struct {
 	escapeKeys   []byte
 	escapeKeyPos int
 	r            io.Reader
+	buf          []byte
 }
 
 // NewEscapeProxy returns a new TTY proxy reader which wraps the given reader
@@ -31,48 +32,57 @@ func NewEscapeProxy(r io.Reader, escapeKeys []byte) io.Reader {
 	}
 }
 
-func (r *escapeProxy) Read(buf []byte) (int, error) {
-	nr, err := r.r.Read(buf)
+func (r *escapeProxy) Read(buf []byte) (n int, err error) {
+	if len(r.escapeKeys) > 0 && r.escapeKeyPos == len(r.escapeKeys) {
+		return 0, EscapeError{}
+	}
 
-	if len(r.escapeKeys) == 0 {
-		return nr, err
+	if len(r.buf) > 0 {
+		n = copy(buf, r.buf)
+		r.buf = r.buf[n:]
 	}
 
-	preserve := func() {
-		// this preserves the original key presses in the passed in buffer
-		nr += r.escapeKeyPos
-		preserve := make([]byte, 0, r.escapeKeyPos+len(buf))
-		preserve = append(preserve, r.escapeKeys[:r.escapeKeyPos]...)
-		preserve = append(preserve, buf...)
-		r.escapeKeyPos = 0
-		copy(buf[0:nr], preserve)
+	nr, err := r.r.Read(buf[n:])
+	n += nr
+	if len(r.escapeKeys) == 0 {
+		return n, err
 	}
 
-	if nr != 1 || err != nil {
-		if r.escapeKeyPos > 0 {
-			preserve()
+	for i := 0; i < n; i++ {
+		if buf[i] == r.escapeKeys[r.escapeKeyPos] {
+			r.escapeKeyPos++
+
+			// Check if the full escape sequence is matched.
+			if r.escapeKeyPos == len(r.escapeKeys) {
+				n = i + 1 - r.escapeKeyPos
+				if n < 0 {
+					n = 0
+				}
+				return n, EscapeError{}
+			}
+			continue
 		}
-		return nr, err
-	}
 
-	if buf[0] != r.escapeKeys[r.escapeKeyPos] {
-		if r.escapeKeyPos > 0 {
-			preserve()
+		// If we need to prepend a partial escape sequence from the previous
+		// read, make sure the new buffer size doesn't exceed len(buf).
+		// Otherwise, preserve any extra data in a buffer for the next read.
+		if i < r.escapeKeyPos {
+			preserve := make([]byte, 0, r.escapeKeyPos+n)
+			preserve = append(preserve, r.escapeKeys[:r.escapeKeyPos]...)
+			preserve = append(preserve, buf[:n]...)
+			n = copy(buf, preserve)
+			i += r.escapeKeyPos
+			r.buf = append(r.buf, preserve[n:]...)
 		}
-		return nr, nil
+		r.escapeKeyPos = 0
 	}
 
-	if r.escapeKeyPos == len(r.escapeKeys)-1 {
-		return 0, EscapeError{}
+	// If we're in the middle of reading an escape sequence, make sure we don't
+	// let the caller read it. If later on we find that this is not the escape
+	// sequence, we'll prepend it back to buf.
+	n -= r.escapeKeyPos
+	if n < 0 {
+		n = 0
 	}
-
-	// Looks like we've got an escape key, but we need to match again on the next
-	// read.
-	// Store the current escape key we found so we can look for the next one on
-	// the next read.
-	// Since this is an escape key, make sure we don't let the caller read it
-	// If later on we find that this is not the escape sequence, we'll add the
-	// keys back
-	r.escapeKeyPos++
-	return nr - r.escapeKeyPos, nil
+	return n, err
 }
diff --git a/vendor/github.com/moby/term/tc.go b/vendor/github.com/moby/term/tc.go
index 162dfb2b..65556027 100644
--- a/vendor/github.com/moby/term/tc.go
+++ b/vendor/github.com/moby/term/tc.go
@@ -1,20 +1,19 @@
 // +build !windows
 
-package term // import "github.com/moby/term"
+package term
 
 import (
-	"syscall"
-	"unsafe"
-
 	"golang.org/x/sys/unix"
 )
 
-func tcget(fd uintptr, p *Termios) syscall.Errno {
-	_, _, err := unix.Syscall(unix.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(p)))
-	return err
+func tcget(fd uintptr) (*Termios, error) {
+	p, err := unix.IoctlGetTermios(int(fd), getTermios)
+	if err != nil {
+		return nil, err
+	}
+	return p, nil
 }
 
-func tcset(fd uintptr, p *Termios) syscall.Errno {
-	_, _, err := unix.Syscall(unix.SYS_IOCTL, fd, setTermios, uintptr(unsafe.Pointer(p)))
-	return err
+func tcset(fd uintptr, p *Termios) error {
+	return unix.IoctlSetTermios(int(fd), setTermios, p)
 }
diff --git a/vendor/github.com/moby/term/term.go b/vendor/github.com/moby/term/term.go
index 6d643516..29c6acf1 100644
--- a/vendor/github.com/moby/term/term.go
+++ b/vendor/github.com/moby/term/term.go
@@ -2,7 +2,7 @@
 
 // Package term provides structures and helper functions to work with
 // terminal (state, sizes).
-package term // import "github.com/moby/term"
+package term
 
 import (
 	"errors"
@@ -50,8 +50,8 @@ func GetFdInfo(in interface{}) (uintptr, bool) {
 
 // IsTerminal returns true if the given file descriptor is a terminal.
 func IsTerminal(fd uintptr) bool {
-	var termios Termios
-	return tcget(fd, &termios) == 0
+	_, err := tcget(fd)
+	return err == nil
 }
 
 // RestoreTerminal restores the terminal connected to the given file descriptor
@@ -60,20 +60,16 @@ func RestoreTerminal(fd uintptr, state *State) error {
 	if state == nil {
 		return ErrInvalidState
 	}
-	if err := tcset(fd, &state.termios); err != 0 {
-		return err
-	}
-	return nil
+	return tcset(fd, &state.termios)
 }
 
 // SaveState saves the state of the terminal connected to the given file descriptor.
 func SaveState(fd uintptr) (*State, error) {
-	var oldState State
-	if err := tcget(fd, &oldState.termios); err != 0 {
+	termios, err := tcget(fd)
+	if err != nil {
 		return nil, err
 	}
-
-	return &oldState, nil
+	return &State{termios: *termios}, nil
 }
 
 // DisableEcho applies the specified state to the terminal connected to the file
@@ -82,7 +78,7 @@ func DisableEcho(fd uintptr, state *State) error {
 	newState := state.termios
 	newState.Lflag &^= unix.ECHO
 
-	if err := tcset(fd, &newState); err != 0 {
+	if err := tcset(fd, &newState); err != nil {
 		return err
 	}
 	handleInterrupt(fd, state)
diff --git a/vendor/github.com/moby/term/term_windows.go b/vendor/github.com/moby/term/term_windows.go
index 1649c230..ba82960d 100644
--- a/vendor/github.com/moby/term/term_windows.go
+++ b/vendor/github.com/moby/term/term_windows.go
@@ -1,13 +1,12 @@
-package term // import "github.com/moby/term"
+package term
 
 import (
 	"io"
 	"os"
 	"os/signal"
-	"syscall" // used for STD_INPUT_HANDLE, STD_OUTPUT_HANDLE and STD_ERROR_HANDLE
 
-	"github.com/Azure/go-ansiterm/winterm"
 	windowsconsole "github.com/moby/term/windows"
+	"golang.org/x/sys/windows"
 )
 
 // State holds the console mode for the terminal.
@@ -28,37 +27,42 @@ var vtInputSupported bool
 func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
 	// Turn on VT handling on all std handles, if possible. This might
 	// fail, in which case we will fall back to terminal emulation.
-	var emulateStdin, emulateStdout, emulateStderr bool
-	fd := os.Stdin.Fd()
-	if mode, err := winterm.GetConsoleMode(fd); err == nil {
+	var (
+		emulateStdin, emulateStdout, emulateStderr bool
+
+		mode uint32
+	)
+
+	fd := windows.Handle(os.Stdin.Fd())
+	if err := windows.GetConsoleMode(fd, &mode); err == nil {
 		// Validate that winterm.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it.
-		if err = winterm.SetConsoleMode(fd, mode|winterm.ENABLE_VIRTUAL_TERMINAL_INPUT); err != nil {
+		if err = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err != nil {
 			emulateStdin = true
 		} else {
 			vtInputSupported = true
 		}
 		// Unconditionally set the console mode back even on failure because SetConsoleMode
 		// remembers invalid bits on input handles.
-		winterm.SetConsoleMode(fd, mode)
+		_ = windows.SetConsoleMode(fd, mode)
 	}
 
-	fd = os.Stdout.Fd()
-	if mode, err := winterm.GetConsoleMode(fd); err == nil {
+	fd = windows.Handle(os.Stdout.Fd())
+	if err := windows.GetConsoleMode(fd, &mode); err == nil {
 		// Validate winterm.DISABLE_NEWLINE_AUTO_RETURN is supported, but do not set it.
-		if err = winterm.SetConsoleMode(fd, mode|winterm.ENABLE_VIRTUAL_TERMINAL_PROCESSING|winterm.DISABLE_NEWLINE_AUTO_RETURN); err != nil {
+		if err = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING|windows.DISABLE_NEWLINE_AUTO_RETURN); err != nil {
 			emulateStdout = true
 		} else {
-			winterm.SetConsoleMode(fd, mode|winterm.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+			_ = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
 		}
 	}
 
-	fd = os.Stderr.Fd()
-	if mode, err := winterm.GetConsoleMode(fd); err == nil {
+	fd = windows.Handle(os.Stderr.Fd())
+	if err := windows.GetConsoleMode(fd, &mode); err == nil {
 		// Validate winterm.DISABLE_NEWLINE_AUTO_RETURN is supported, but do not set it.
-		if err = winterm.SetConsoleMode(fd, mode|winterm.ENABLE_VIRTUAL_TERMINAL_PROCESSING|winterm.DISABLE_NEWLINE_AUTO_RETURN); err != nil {
+		if err = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING|windows.DISABLE_NEWLINE_AUTO_RETURN); err != nil {
 			emulateStderr = true
 		} else {
-			winterm.SetConsoleMode(fd, mode|winterm.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+			_ = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
 		}
 	}
 
@@ -67,19 +71,22 @@ func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
 	// go-ansiterm hasn't switch to x/sys/windows.
 	// TODO: switch back to x/sys/windows once go-ansiterm has switched
 	if emulateStdin {
-		stdIn = windowsconsole.NewAnsiReader(syscall.STD_INPUT_HANDLE)
+		h := uint32(windows.STD_INPUT_HANDLE)
+		stdIn = windowsconsole.NewAnsiReader(int(h))
 	} else {
 		stdIn = os.Stdin
 	}
 
 	if emulateStdout {
-		stdOut = windowsconsole.NewAnsiWriter(syscall.STD_OUTPUT_HANDLE)
+		h := uint32(windows.STD_OUTPUT_HANDLE)
+		stdOut = windowsconsole.NewAnsiWriter(int(h))
 	} else {
 		stdOut = os.Stdout
 	}
 
 	if emulateStderr {
-		stdErr = windowsconsole.NewAnsiWriter(syscall.STD_ERROR_HANDLE)
+		h := uint32(windows.STD_ERROR_HANDLE)
+		stdErr = windowsconsole.NewAnsiWriter(int(h))
 	} else {
 		stdErr = os.Stderr
 	}
@@ -94,8 +101,8 @@ func GetFdInfo(in interface{}) (uintptr, bool) {
 
 // GetWinsize returns the window size based on the specified file descriptor.
 func GetWinsize(fd uintptr) (*Winsize, error) {
-	info, err := winterm.GetConsoleScreenBufferInfo(fd)
-	if err != nil {
+	var info windows.ConsoleScreenBufferInfo
+	if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil {
 		return nil, err
 	}
 
@@ -109,20 +116,23 @@ func GetWinsize(fd uintptr) (*Winsize, error) {
 
 // IsTerminal returns true if the given file descriptor is a terminal.
 func IsTerminal(fd uintptr) bool {
-	return windowsconsole.IsConsole(fd)
+	var mode uint32
+	err := windows.GetConsoleMode(windows.Handle(fd), &mode)
+	return err == nil
 }
 
 // RestoreTerminal restores the terminal connected to the given file descriptor
 // to a previous state.
 func RestoreTerminal(fd uintptr, state *State) error {
-	return winterm.SetConsoleMode(fd, state.mode)
+	return windows.SetConsoleMode(windows.Handle(fd), state.mode)
 }
 
 // SaveState saves the state of the terminal connected to the given file descriptor.
 func SaveState(fd uintptr) (*State, error) {
-	mode, e := winterm.GetConsoleMode(fd)
-	if e != nil {
-		return nil, e
+	var mode uint32
+
+	if err := windows.GetConsoleMode(windows.Handle(fd), &mode); err != nil {
+		return nil, err
 	}
 
 	return &State{mode: mode}, nil
@@ -132,9 +142,9 @@ func SaveState(fd uintptr) (*State, error) {
 // -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
 func DisableEcho(fd uintptr, state *State) error {
 	mode := state.mode
-	mode &^= winterm.ENABLE_ECHO_INPUT
-	mode |= winterm.ENABLE_PROCESSED_INPUT | winterm.ENABLE_LINE_INPUT
-	err := winterm.SetConsoleMode(fd, mode)
+	mode &^= windows.ENABLE_ECHO_INPUT
+	mode |= windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT
+	err := windows.SetConsoleMode(windows.Handle(fd), mode)
 	if err != nil {
 		return err
 	}
@@ -169,7 +179,7 @@ func SetRawTerminalOutput(fd uintptr) (*State, error) {
 
 	// Ignore failures, since winterm.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this
 	// version of Windows.
-	winterm.SetConsoleMode(fd, state.mode|winterm.DISABLE_NEWLINE_AUTO_RETURN)
+	_ = windows.SetConsoleMode(windows.Handle(fd), state.mode|windows.DISABLE_NEWLINE_AUTO_RETURN)
 	return state, err
 }
 
@@ -188,21 +198,21 @@ func MakeRaw(fd uintptr) (*State, error) {
 	// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
 
 	// Disable these modes
-	mode &^= winterm.ENABLE_ECHO_INPUT
-	mode &^= winterm.ENABLE_LINE_INPUT
-	mode &^= winterm.ENABLE_MOUSE_INPUT
-	mode &^= winterm.ENABLE_WINDOW_INPUT
-	mode &^= winterm.ENABLE_PROCESSED_INPUT
+	mode &^= windows.ENABLE_ECHO_INPUT
+	mode &^= windows.ENABLE_LINE_INPUT
+	mode &^= windows.ENABLE_MOUSE_INPUT
+	mode &^= windows.ENABLE_WINDOW_INPUT
+	mode &^= windows.ENABLE_PROCESSED_INPUT
 
 	// Enable these modes
-	mode |= winterm.ENABLE_EXTENDED_FLAGS
-	mode |= winterm.ENABLE_INSERT_MODE
-	mode |= winterm.ENABLE_QUICK_EDIT_MODE
+	mode |= windows.ENABLE_EXTENDED_FLAGS
+	mode |= windows.ENABLE_INSERT_MODE
+	mode |= windows.ENABLE_QUICK_EDIT_MODE
 	if vtInputSupported {
-		mode |= winterm.ENABLE_VIRTUAL_TERMINAL_INPUT
+		mode |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT
 	}
 
-	err = winterm.SetConsoleMode(fd, mode)
+	err = windows.SetConsoleMode(windows.Handle(fd), mode)
 	if err != nil {
 		return nil, err
 	}
@@ -215,7 +225,7 @@ func restoreAtInterrupt(fd uintptr, state *State) {
 
 	go func() {
 		_ = <-sigchan
-		RestoreTerminal(fd, state)
+		_ = RestoreTerminal(fd, state)
 		os.Exit(0)
 	}()
 }
diff --git a/vendor/github.com/moby/term/termios_linux.go b/vendor/github.com/moby/term/termios.go
similarity index 62%
rename from vendor/github.com/moby/term/termios_linux.go
rename to vendor/github.com/moby/term/termios.go
index be39ff56..0f028e22 100644
--- a/vendor/github.com/moby/term/termios_linux.go
+++ b/vendor/github.com/moby/term/termios.go
@@ -1,28 +1,24 @@
-package term // import "github.com/moby/term"
+// +build !windows
+
+package term
 
 import (
 	"golang.org/x/sys/unix"
 )
 
-const (
-	getTermios = unix.TCGETS
-	setTermios = unix.TCSETS
-)
-
 // Termios is the Unix API for terminal I/O.
-type Termios unix.Termios
+type Termios = unix.Termios
 
-// MakeRaw put the terminal connected to the given file descriptor into raw
+// MakeRaw puts the terminal connected to the given file descriptor into raw
 // mode and returns the previous state of the terminal so that it can be
 // restored.
 func MakeRaw(fd uintptr) (*State, error) {
-	termios, err := unix.IoctlGetTermios(int(fd), getTermios)
+	termios, err := tcget(fd)
 	if err != nil {
 		return nil, err
 	}
 
-	var oldState State
-	oldState.termios = Termios(*termios)
+	oldState := State{termios: *termios}
 
 	termios.Iflag &^= (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON)
 	termios.Oflag &^= unix.OPOST
@@ -32,7 +28,7 @@ func MakeRaw(fd uintptr) (*State, error) {
 	termios.Cc[unix.VMIN] = 1
 	termios.Cc[unix.VTIME] = 0
 
-	if err := unix.IoctlSetTermios(int(fd), setTermios, termios); err != nil {
+	if err := tcset(fd, termios); err != nil {
 		return nil, err
 	}
 	return &oldState, nil
diff --git a/vendor/github.com/moby/term/termios_bsd.go b/vendor/github.com/moby/term/termios_bsd.go
index da785106..922dd4ba 100644
--- a/vendor/github.com/moby/term/termios_bsd.go
+++ b/vendor/github.com/moby/term/termios_bsd.go
@@ -1,10 +1,8 @@
 // +build darwin freebsd openbsd netbsd
 
-package term // import "github.com/moby/term"
+package term
 
 import (
-	"unsafe"
-
 	"golang.org/x/sys/unix"
 )
 
@@ -12,31 +10,3 @@ const (
 	getTermios = unix.TIOCGETA
 	setTermios = unix.TIOCSETA
 )
-
-// Termios is the Unix API for terminal I/O.
-type Termios unix.Termios
-
-// MakeRaw put the terminal connected to the given file descriptor into raw
-// mode and returns the previous state of the terminal so that it can be
-// restored.
-func MakeRaw(fd uintptr) (*State, error) {
-	var oldState State
-	if _, _, err := unix.Syscall(unix.SYS_IOCTL, fd, getTermios, uintptr(unsafe.Pointer(&oldState.termios))); err != 0 {
-		return nil, err
-	}
-
-	newState := oldState.termios
-	newState.Iflag &^= (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON)
-	newState.Oflag &^= unix.OPOST
-	newState.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN)
-	newState.Cflag &^= (unix.CSIZE | unix.PARENB)
-	newState.Cflag |= unix.CS8
-	newState.Cc[unix.VMIN] = 1
-	newState.Cc[unix.VTIME] = 0
-
-	if _, _, err := unix.Syscall(unix.SYS_IOCTL, fd, setTermios, uintptr(unsafe.Pointer(&newState))); err != 0 {
-		return nil, err
-	}
-
-	return &oldState, nil
-}
diff --git a/vendor/github.com/moby/term/termios_nonbsd.go b/vendor/github.com/moby/term/termios_nonbsd.go
new file mode 100644
index 00000000..038fd61b
--- /dev/null
+++ b/vendor/github.com/moby/term/termios_nonbsd.go
@@ -0,0 +1,12 @@
+//+build !darwin,!freebsd,!netbsd,!openbsd,!windows
+
+package term
+
+import (
+	"golang.org/x/sys/unix"
+)
+
+const (
+	getTermios = unix.TCGETS
+	setTermios = unix.TCSETS
+)
diff --git a/vendor/github.com/moby/term/windows/ansi_reader.go b/vendor/github.com/moby/term/windows/ansi_reader.go
index 5114b63e..15525152 100644
--- a/vendor/github.com/moby/term/windows/ansi_reader.go
+++ b/vendor/github.com/moby/term/windows/ansi_reader.go
@@ -1,6 +1,6 @@
 // +build windows
 
-package windowsconsole // import "github.com/moby/term/windows"
+package windowsconsole
 
 import (
 	"bytes"
@@ -31,7 +31,6 @@ type ansiReader struct {
 // NewAnsiReader returns an io.ReadCloser that provides VT100 terminal emulation on top of a
 // Windows console input handle.
 func NewAnsiReader(nFile int) io.ReadCloser {
-	initLogger()
 	file, fd := winterm.GetStdFile(nFile)
 	return &ansiReader{
 		file:    file,
@@ -59,8 +58,6 @@ func (ar *ansiReader) Read(p []byte) (int, error) {
 
 	// Previously read bytes exist, read as much as we can and return
 	if len(ar.buffer) > 0 {
-		logger.Debugf("Reading previously cached bytes")
-
 		originalLength := len(ar.buffer)
 		copiedLength := copy(p, ar.buffer)
 
@@ -70,16 +67,14 @@ func (ar *ansiReader) Read(p []byte) (int, error) {
 			ar.buffer = ar.buffer[copiedLength:]
 		}
 
-		logger.Debugf("Read from cache p[%d]: % x", copiedLength, p)
 		return copiedLength, nil
 	}
 
 	// Read and translate key events
-	events, err := readInputEvents(ar.fd, len(p))
+	events, err := readInputEvents(ar, len(p))
 	if err != nil {
 		return 0, err
 	} else if len(events) == 0 {
-		logger.Debug("No input events detected")
 		return 0, nil
 	}
 
@@ -87,11 +82,9 @@ func (ar *ansiReader) Read(p []byte) (int, error) {
 
 	// Save excess bytes and right-size keyBytes
 	if len(keyBytes) > len(p) {
-		logger.Debugf("Received %d keyBytes, only room for %d bytes", len(keyBytes), len(p))
 		ar.buffer = keyBytes[len(p):]
 		keyBytes = keyBytes[:len(p)]
 	} else if len(keyBytes) == 0 {
-		logger.Debug("No key bytes returned from the translator")
 		return 0, nil
 	}
 
@@ -100,13 +93,11 @@ func (ar *ansiReader) Read(p []byte) (int, error) {
 		return 0, errors.New("unexpected copy length encountered")
 	}
 
-	logger.Debugf("Read        p[%d]: % x", copiedLength, p)
-	logger.Debugf("Read keyBytes[%d]: % x", copiedLength, keyBytes)
 	return copiedLength, nil
 }
 
 // readInputEvents polls until at least one event is available.
-func readInputEvents(fd uintptr, maxBytes int) ([]winterm.INPUT_RECORD, error) {
+func readInputEvents(ar *ansiReader, maxBytes int) ([]winterm.INPUT_RECORD, error) {
 	// Determine the maximum number of records to retrieve
 	// -- Cast around the type system to obtain the size of a single INPUT_RECORD.
 	//    unsafe.Sizeof requires an expression vs. a type-reference; the casting
@@ -118,25 +109,23 @@ func readInputEvents(fd uintptr, maxBytes int) ([]winterm.INPUT_RECORD, error) {
 	} else if countRecords == 0 {
 		countRecords = 1
 	}
-	logger.Debugf("[windows] readInputEvents: Reading %v records (buffer size %v, record size %v)", countRecords, maxBytes, recordSize)
 
 	// Wait for and read input events
 	events := make([]winterm.INPUT_RECORD, countRecords)
 	nEvents := uint32(0)
-	eventsExist, err := winterm.WaitForSingleObject(fd, winterm.WAIT_INFINITE)
+	eventsExist, err := winterm.WaitForSingleObject(ar.fd, winterm.WAIT_INFINITE)
 	if err != nil {
 		return nil, err
 	}
 
 	if eventsExist {
-		err = winterm.ReadConsoleInput(fd, events, &nEvents)
+		err = winterm.ReadConsoleInput(ar.fd, events, &nEvents)
 		if err != nil {
 			return nil, err
 		}
 	}
 
 	// Return a slice restricted to the number of returned records
-	logger.Debugf("[windows] readInputEvents: Read %v events", nEvents)
 	return events[:nEvents], nil
 }
 
diff --git a/vendor/github.com/moby/term/windows/ansi_writer.go b/vendor/github.com/moby/term/windows/ansi_writer.go
index 51bf9aa4..ccb5ef07 100644
--- a/vendor/github.com/moby/term/windows/ansi_writer.go
+++ b/vendor/github.com/moby/term/windows/ansi_writer.go
@@ -1,6 +1,6 @@
 // +build windows
 
-package windowsconsole // import "github.com/moby/term/windows"
+package windowsconsole
 
 import (
 	"io"
@@ -24,7 +24,6 @@ type ansiWriter struct {
 // NewAnsiWriter returns an io.Writer that provides VT100 terminal emulation on top of a
 // Windows console output handle.
 func NewAnsiWriter(nFile int) io.Writer {
-	initLogger()
 	file, fd := winterm.GetStdFile(nFile)
 	info, err := winterm.GetConsoleScreenBufferInfo(fd)
 	if err != nil {
@@ -32,9 +31,8 @@ func NewAnsiWriter(nFile int) io.Writer {
 	}
 
 	parser := ansiterm.CreateParser("Ground", winterm.CreateWinEventHandler(fd, file))
-	logger.Infof("newAnsiWriter: parser %p", parser)
 
-	aw := &ansiWriter{
+	return &ansiWriter{
 		file:           file,
 		fd:             fd,
 		infoReset:      info,
@@ -42,10 +40,6 @@ func NewAnsiWriter(nFile int) io.Writer {
 		escapeSequence: []byte(ansiterm.KEY_ESC_CSI),
 		parser:         parser,
 	}
-
-	logger.Infof("newAnsiWriter: aw.parser %p", aw.parser)
-	logger.Infof("newAnsiWriter: %v", aw)
-	return aw
 }
 
 func (aw *ansiWriter) Fd() uintptr {
@@ -58,7 +52,5 @@ func (aw *ansiWriter) Write(p []byte) (total int, err error) {
 		return 0, nil
 	}
 
-	logger.Infof("Write: % x", p)
-	logger.Infof("Write: %s", string(p))
 	return aw.parser.Parse(p)
 }
diff --git a/vendor/github.com/moby/term/windows/console.go b/vendor/github.com/moby/term/windows/console.go
index 54e0fe83..993694dd 100644
--- a/vendor/github.com/moby/term/windows/console.go
+++ b/vendor/github.com/moby/term/windows/console.go
@@ -1,11 +1,11 @@
 // +build windows
 
-package windowsconsole // import "github.com/moby/term/windows"
+package windowsconsole
 
 import (
 	"os"
 
-	"github.com/Azure/go-ansiterm/winterm"
+	"golang.org/x/sys/windows"
 )
 
 // GetHandleInfo returns file descriptor and bool indicating whether the file is a console.
@@ -22,14 +22,18 @@ func GetHandleInfo(in interface{}) (uintptr, bool) {
 
 	if file, ok := in.(*os.File); ok {
 		inFd = file.Fd()
-		isTerminal = IsConsole(inFd)
+		isTerminal = isConsole(inFd)
 	}
 	return inFd, isTerminal
 }
 
 // IsConsole returns true if the given file descriptor is a Windows Console.
 // The code assumes that GetConsoleMode will return an error for file descriptors that are not a console.
-func IsConsole(fd uintptr) bool {
-	_, e := winterm.GetConsoleMode(fd)
-	return e == nil
+// Deprecated: use golang.org/x/sys/windows.GetConsoleMode() or golang.org/x/term.IsTerminal()
+var IsConsole = isConsole
+
+func isConsole(fd uintptr) bool {
+	var mode uint32
+	err := windows.GetConsoleMode(windows.Handle(fd), &mode)
+	return err == nil
 }
diff --git a/vendor/github.com/moby/term/windows/doc.go b/vendor/github.com/moby/term/windows/doc.go
new file mode 100644
index 00000000..54265fff
--- /dev/null
+++ b/vendor/github.com/moby/term/windows/doc.go
@@ -0,0 +1,5 @@
+// These files implement ANSI-aware input and output streams for use by the Docker Windows client.
+// When asked for the set of standard streams (e.g., stdin, stdout, stderr), the code will create
+// and return pseudo-streams that convert ANSI sequences to / from Windows Console API calls.
+
+package windowsconsole
diff --git a/vendor/github.com/moby/term/windows/windows.go b/vendor/github.com/moby/term/windows/windows.go
deleted file mode 100644
index bb03e060..00000000
--- a/vendor/github.com/moby/term/windows/windows.go
+++ /dev/null
@@ -1,34 +0,0 @@
-// +build windows
-// These files implement ANSI-aware input and output streams for use by the Docker Windows client.
-// When asked for the set of standard streams (e.g., stdin, stdout, stderr), the code will create
-// and return pseudo-streams that convert ANSI sequences to / from Windows Console API calls.
-
-package windowsconsole // import "github.com/moby/term/windows"
-
-import (
-	"io/ioutil"
-	"os"
-	"sync"
-
-	ansiterm "github.com/Azure/go-ansiterm"
-	"github.com/sirupsen/logrus"
-)
-
-var logger *logrus.Logger
-var initOnce sync.Once
-
-func initLogger() {
-	initOnce.Do(func() {
-		logFile := ioutil.Discard
-
-		if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" {
-			logFile, _ = os.Create("ansiReaderWriter.log")
-		}
-
-		logger = &logrus.Logger{
-			Out:       logFile,
-			Formatter: new(logrus.TextFormatter),
-			Level:     logrus.DebugLevel,
-		}
-	})
-}
diff --git a/vendor/github.com/moby/term/winsize.go b/vendor/github.com/moby/term/winsize.go
index 29a0463d..1ef98d59 100644
--- a/vendor/github.com/moby/term/winsize.go
+++ b/vendor/github.com/moby/term/winsize.go
@@ -1,6 +1,6 @@
 // +build !windows
 
-package term // import "github.com/moby/term"
+package term
 
 import (
 	"golang.org/x/sys/unix"
diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go
index 35d81089..581cf7cd 100644
--- a/vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go
+++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go
@@ -53,4 +53,10 @@ const (
 
 	// AnnotationDescription is the annotation key for the human-readable description of the software packaged in the image.
 	AnnotationDescription = "org.opencontainers.image.description"
+
+	// AnnotationBaseImageDigest is the annotation key for the digest of the image's base image.
+	AnnotationBaseImageDigest = "org.opencontainers.image.base.digest"
+
+	// AnnotationBaseImageName is the annotation key for the image reference of the image's base image.
+	AnnotationBaseImageName = "org.opencontainers.image.base.name"
 )
diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go
index fe799bd6..ffff4b6d 100644
--- a/vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go
+++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go
@@ -89,9 +89,20 @@ type Image struct {
 	// Architecture is the CPU architecture which the binaries in this image are built to run on.
 	Architecture string `json:"architecture"`
 
+	// Variant is the variant of the specified CPU architecture which image binaries are intended to run on.
+	Variant string `json:"variant,omitempty"`
+
 	// OS is the name of the operating system which the image is built to run on.
 	OS string `json:"os"`
 
+	// OSVersion is an optional field specifying the operating system
+	// version, for example on Windows `10.0.14393.1066`.
+	OSVersion string `json:"os.version,omitempty"`
+
+	// OSFeatures is an optional field specifying an array of strings,
+	// each listing a required OS feature (for example on Windows `win32k`).
+	OSFeatures []string `json:"os.features,omitempty"`
+
 	// Config defines the execution parameters which should be used as a base when running a container using the image.
 	Config ImageConfig `json:"config,omitempty"`
 
diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go
index bad7bb97..4f35ac13 100644
--- a/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go
+++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go
@@ -34,6 +34,10 @@ const (
 	// referenced by the manifest.
 	MediaTypeImageLayerGzip = "application/vnd.oci.image.layer.v1.tar+gzip"
 
+	// MediaTypeImageLayerZstd is the media type used for zstd compressed
+	// layers referenced by the manifest.
+	MediaTypeImageLayerZstd = "application/vnd.oci.image.layer.v1.tar+zstd"
+
 	// MediaTypeImageLayerNonDistributable is the media type for layers referenced by
 	// the manifest but with distribution restrictions.
 	MediaTypeImageLayerNonDistributable = "application/vnd.oci.image.layer.nondistributable.v1.tar"
@@ -43,6 +47,11 @@ const (
 	// restrictions.
 	MediaTypeImageLayerNonDistributableGzip = "application/vnd.oci.image.layer.nondistributable.v1.tar+gzip"
 
+	// MediaTypeImageLayerNonDistributableZstd is the media type for zstd
+	// compressed layers referenced by the manifest but with distribution
+	// restrictions.
+	MediaTypeImageLayerNonDistributableZstd = "application/vnd.oci.image.layer.nondistributable.v1.tar+zstd"
+
 	// MediaTypeImageConfig specifies the media type for the image configuration.
 	MediaTypeImageConfig = "application/vnd.oci.image.config.v1+json"
 )
diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/version.go b/vendor/github.com/opencontainers/image-spec/specs-go/version.go
index 0d9543f1..31f99cf6 100644
--- a/vendor/github.com/opencontainers/image-spec/specs-go/version.go
+++ b/vendor/github.com/opencontainers/image-spec/specs-go/version.go
@@ -25,7 +25,7 @@ const (
 	VersionPatch = 2
 
 	// VersionDev indicates development branch. Releases will be empty string.
-	VersionDev = ""
+	VersionDev = "-dev"
 )
 
 // Version is the specification version that the package types support.
diff --git a/vendor/modules.txt b/vendor/modules.txt
index cdb6c89d..e36ce57d 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1,5 +1,5 @@
-# github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78
-## explicit
+# github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1
+## explicit; go 1.16
 github.com/Azure/go-ansiterm
 github.com/Azure/go-ansiterm/winterm
 # github.com/MakeNowJust/heredoc v1.0.0
@@ -70,9 +70,8 @@ github.com/containerd/cgroups/stats/v1
 # github.com/containerd/console v1.0.3
 ## explicit; go 1.13
 github.com/containerd/console
-# github.com/containerd/containerd v1.5.13
+# github.com/containerd/containerd v1.6.3-0.20220401172941-5ff8fce1fcc6
 ## explicit; go 1.17
-github.com/containerd/containerd/log
 github.com/containerd/containerd/pkg/userns
 github.com/containerd/containerd/sys
 # github.com/containerd/continuity v0.3.0
@@ -93,6 +92,7 @@ github.com/digitalocean/godo/metrics
 github.com/digitalocean/godo/util
 # github.com/docker/cli v20.10.17+incompatible
 ## explicit
+github.com/docker/cli/cli/command/image/build
 github.com/docker/cli/cli/config
 github.com/docker/cli/cli/config/configfile
 github.com/docker/cli/cli/config/credentials
@@ -119,6 +119,7 @@ github.com/docker/docker/api/types/swarm/runtime
 github.com/docker/docker/api/types/time
 github.com/docker/docker/api/types/versions
 github.com/docker/docker/api/types/volume
+github.com/docker/docker/builder/remotecontext/git
 github.com/docker/docker/client
 github.com/docker/docker/errdefs
 github.com/docker/docker/pkg/archive
@@ -129,7 +130,10 @@ github.com/docker/docker/pkg/ioutils
 github.com/docker/docker/pkg/jsonmessage
 github.com/docker/docker/pkg/longpath
 github.com/docker/docker/pkg/pools
+github.com/docker/docker/pkg/progress
 github.com/docker/docker/pkg/stdcopy
+github.com/docker/docker/pkg/streamformatter
+github.com/docker/docker/pkg/stringid
 github.com/docker/docker/pkg/system
 # github.com/docker/docker-credential-helpers v0.6.4
 ## explicit; go 1.13
@@ -268,13 +272,19 @@ github.com/mitchellh/mapstructure
 # github.com/mitchellh/reflectwalk v1.0.0
 ## explicit
 github.com/mitchellh/reflectwalk
+# github.com/moby/buildkit v0.10.4
+## explicit; go 1.17
+github.com/moby/buildkit/frontend/dockerfile/dockerignore
 # github.com/moby/sys/mount v0.3.3
 ## explicit; go 1.16
 github.com/moby/sys/mount
 # github.com/moby/sys/mountinfo v0.6.2
 ## explicit; go 1.16
 github.com/moby/sys/mountinfo
-# github.com/moby/term v0.0.0-20200312100748-672ec06f55cd
+# github.com/moby/sys/symlink v0.2.0
+## explicit; go 1.16
+github.com/moby/sys/symlink
+# github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6
 ## explicit; go 1.13
 github.com/moby/term
 github.com/moby/term/windows
@@ -316,7 +326,7 @@ github.com/nicksnyder/go-i18n/i18n/translation
 # github.com/opencontainers/go-digest v1.0.0
 ## explicit; go 1.13
 github.com/opencontainers/go-digest
-# github.com/opencontainers/image-spec v1.0.2
+# github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799
 ## explicit
 github.com/opencontainers/image-spec/specs-go
 github.com/opencontainers/image-spec/specs-go/v1


Test patch:
diff --git a/internal/apps/builder/docker_test.go b/internal/apps/builder/docker_test.go
index 75665821..ae44c664 100644
--- a/internal/apps/builder/docker_test.go
+++ b/internal/apps/builder/docker_test.go
@@ -7,6 +7,9 @@ import (
 	"fmt"
 	"io"
 	"io/ioutil"
+	"os"
+	"path/filepath"
+	"regexp"
 	"strings"
 	"sync"
 	"testing"
@@ -100,7 +103,6 @@ func TestDockerComponentBuild(t *testing.T) {
 	t.Run("happy path - service", func(t *testing.T) {
 		service := &godo.AppServiceSpec{
 			DockerfilePath: "./Dockerfile",
-			SourceDir:      "./subdir",
 			Name:           "web",
 			Envs: []*godo.AppVariableDefinition{
 				{
@@ -158,7 +160,7 @@ func TestDockerComponentBuild(t *testing.T) {
 		}
 
 		mockClient.EXPECT().ImageBuild(ctx, gomock.Any(), types.ImageBuildOptions{
-			Dockerfile: service.DockerfilePath,
+			Dockerfile: "Dockerfile",
 			Tags: []string{
 				builder.AppImageOutputName(),
 			},
@@ -180,8 +182,8 @@ func TestDockerComponentBuild(t *testing.T) {
 
 	t.Run("happy path - static site", func(t *testing.T) {
 		site := &godo.AppStaticSiteSpec{
-			DockerfilePath: "./Dockerfile",
-			SourceDir:      "./subdir",
+			DockerfilePath: "Dockerfile",
+			SourceDir:      "subdir",
 			Name:           "web",
 			OutputDir:      "/app/public",
 			Envs: []*godo.AppVariableDefinition{
@@ -205,59 +207,78 @@ func TestDockerComponentBuild(t *testing.T) {
 
 		mockClient := NewMockDockerEngineClient(ctrl)
 		logBuf := newLoggableBuffer(t)
+		contextDir := t.TempDir()
+		err := os.Mkdir(filepath.Join(contextDir, "subdir"), 0775)
+		require.NoError(t, err)
+		// Dockerfile is outside of source_dir
+		err = ioutil.WriteFile(filepath.Join(contextDir, "Dockerfile"), []byte("FROM scratch"), 0664)
+		require.NoError(t, err)
+
 		builder := &DockerComponentBuilder{
 			baseComponentBuilder: baseComponentBuilder{
 				cli:        mockClient,
 				spec:       spec,
 				component:  site,
 				logWriter:  &logBuf,
-				contextDir: t.TempDir(),
+				contextDir: contextDir,
 			},
 			dockerComponent: site,
 		}
 
-		// app image build
-		appImageBuild := mockClient.EXPECT().ImageBuild(ctx, gomock.Any(), types.ImageBuildOptions{
-			Dockerfile: site.DockerfilePath,
-			Tags: []string{
-				builder.AppImageOutputName(),
-			},
-			BuildArgs: map[string]*string{
-				"build-arg-1": strPtr("build-val-1"),
-				"override-1":  strPtr("override-1"),
-			},
-		}).Return(types.ImageBuildResponse{
-			Body: io.NopCloser(strings.NewReader("")),
-		}, nil)
-
-		// static site build
-		mockClient.EXPECT().
-			ImageBuild(ctx, gomock.Any(),
-				&delegatedMatcher{
-					Description: "matches static site image build options",
-					MatchesFunc: func(x any) bool {
-						options, ok := x.(types.ImageBuildOptions)
-						if !ok {
-							return false
-						}
-
-						t := &testingT{}
-						assert.Equal(t, "./Dockerfile.static", options.Dockerfile)
-						assert.Equal(t, []string{builder.StaticSiteImageOutputName()}, options.Tags)
-						assert.Equal(t, map[string]*string{
-							"app_image":   strPtr(builder.AppImageOutputName()),
-							"nginx_image": strPtr(StaticSiteNginxImage),
-							"output_dir":  strPtr(site.GetOutputDir()),
-						}, options.BuildArgs)
-						return !t.Failed()
-					},
-				}).
-			DoAndReturn(func(ctx context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
-				// assert the contents of the archive
-				t.Run("static site archive", func(t *testing.T) {
-					assertArchiveContents(t, context, map[string]func(t *testing.T, h *tar.Header, c []byte){
-						"Dockerfile.static": func(t *testing.T, h *tar.Header, c []byte) {
-							assert.Equal(t, `
+		gomock.InOrder(
+			// app image build
+			mockClient.EXPECT().ImageBuild(ctx, gomock.Any(), &delegatedMatcher{
+				Description: "matches app container image build options",
+				MatchesFunc: func(x any) bool {
+					options, ok := x.(types.ImageBuildOptions)
+					if !ok {
+						return false
+					}
+					t := &testingT{}
+					assert.Equal(t, []string{builder.AppImageOutputName()}, options.Tags)
+					assert.Equal(t, map[string]*string{
+						"build-arg-1": strPtr("build-val-1"),
+						"override-1":  strPtr("override-1"),
+					}, options.BuildArgs)
+					return !t.Failed()
+				},
+			}).
+				DoAndReturn(func(ctx context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
+					// options.Dockerfile is added to the archive as a fake .dockerfile.{random} path as it's outside the source dir
+					assert.Regexp(t, regexp.MustCompile(`^\.dockerfile\.[a-z0-9]+$`), options.Dockerfile)
+					return types.ImageBuildResponse{
+						Body: io.NopCloser(strings.NewReader("")),
+					}, nil
+				}),
+
+			// static site build
+			mockClient.EXPECT().
+				ImageBuild(ctx, gomock.Any(),
+					&delegatedMatcher{
+						Description: "matches static site image build options",
+						MatchesFunc: func(x any) bool {
+							options, ok := x.(types.ImageBuildOptions)
+							if !ok {
+								return false
+							}
+
+							t := &testingT{}
+							assert.Equal(t, "./Dockerfile.static", options.Dockerfile)
+							assert.Equal(t, []string{builder.StaticSiteImageOutputName()}, options.Tags)
+							assert.Equal(t, map[string]*string{
+								"app_image":   strPtr(builder.AppImageOutputName()),
+								"nginx_image": strPtr(StaticSiteNginxImage),
+								"output_dir":  strPtr(site.GetOutputDir()),
+							}, options.BuildArgs)
+							return !t.Failed()
+						},
+					}).
+				DoAndReturn(func(ctx context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
+					// assert the contents of the archive
+					t.Run("static site archive", func(t *testing.T) {
+						assertArchiveContents(t, context, map[string]func(t *testing.T, h *tar.Header, c []byte){
+							"Dockerfile.static": func(t *testing.T, h *tar.Header, c []byte) {
+								assert.Equal(t, `
 ARG app_image
 ARG nginx_image
 ARG output_dir
@@ -268,10 +289,10 @@ ARG output_dir
 COPY nginx.conf /etc/nginx/conf.d/default.conf
 COPY --from=content ${output_dir}/ /www
 `,
-								string(c))
-						},
-						"nginx.conf": func(t *testing.T, h *tar.Header, c []byte) {
-							assert.Equal(t, `
+									string(c))
+							},
+							"nginx.conf": func(t *testing.T, h *tar.Header, c []byte) {
+								assert.Equal(t, `
 server {
 	listen 8080;
 	listen [::]:8080;
@@ -286,18 +307,18 @@ server {
 	gzip_static on;
 }
 `,
-								string(c))
-						},
+									string(c))
+							},
+						})
 					})
-				})
 
-				return types.ImageBuildResponse{
-					Body: io.NopCloser(strings.NewReader("")),
-				}, nil
-			}).
-			After(appImageBuild)
+					return types.ImageBuildResponse{
+						Body: io.NopCloser(strings.NewReader("")),
+					}, nil
+				}),
+		)
 
-		_, err := builder.Build(ctx)
+		_, err = builder.Build(ctx)
 		require.NoError(t, err)
 	})
 }