mirror of https://github.com/docker/cli.git
Allow Dockerfile from outside build-context
Historically, the Dockerfile had to be insde the build-context, because it was
sent as part of the build-context.
3f6dc81e10
added support for passing the Dockerfile through stdin, in which case the
contents of the Dockerfile is injected into the build-context.
This patch uses the same mechanism for situations where the location of the
Dockerfile is passed, and its path is outside of the build-context.
Before this change:
$ mkdir -p myproject/context myproject/dockerfiles && cd myproject
$ echo "hello" > context/hello
$ echo -e "FROM busybox\nCOPY /hello /\nRUN cat /hello" > dockerfiles/Dockerfile
$ docker build --no-cache -f $PWD/dockerfiles/Dockerfile $PWD/context
unable to prepare context: the Dockerfile (/Users/sebastiaan/projects/test/dockerfile-outside/myproject/dockerfiles/Dockerfile) must be within the build context
After this change:
$ mkdir -p myproject/context myproject/dockerfiles && cd myproject
$ echo "hello" > context/hello
$ echo -e "FROM busybox\nCOPY /hello /\nRUN cat /hello" > dockerfiles/Dockerfile
$ docker build --no-cache -f $PWD/dockerfiles/Dockerfile $PWD/context
Sending build context to Docker daemon 2.607kB
Step 1/3 : FROM busybox
---> 6ad733544a63
Step 2/3 : COPY /hello /
---> 9a5ae1c7be9e
Step 3/3 : RUN cat /hello
---> Running in 20dfef2d180f
hello
Removing intermediate container 20dfef2d180f
---> ce1748f91bb2
Successfully built ce1748f91bb2
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
a0044ba3a7
commit
a1048523d2
|
@ -9,8 +9,10 @@ import (
|
|||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
|
@ -206,6 +208,14 @@ func runBuild(dockerCli command.Cli, options buildOptions) error {
|
|||
buildCtx, relDockerfile, err = build.GetContextFromReader(dockerCli.In(), options.dockerfileName)
|
||||
case isLocalDir(specifiedContext):
|
||||
contextDir, relDockerfile, err = build.GetContextFromLocalDir(specifiedContext, options.dockerfileName)
|
||||
if err == nil && strings.HasPrefix(relDockerfile, ".."+string(filepath.Separator)) {
|
||||
// Dockerfile is outside of build-context; read the Dockerfile and pass it as dockerfileCtx
|
||||
dockerfileCtx, err = os.Open(options.dockerfileName)
|
||||
if err != nil {
|
||||
return errors.Errorf("unable to open Dockerfile: %v", err)
|
||||
}
|
||||
defer dockerfileCtx.Close()
|
||||
}
|
||||
case urlutil.IsGitURL(specifiedContext):
|
||||
tempDir, relDockerfile, err = build.GetContextFromGitURL(specifiedContext, options.dockerfileName)
|
||||
case urlutil.IsURL(specifiedContext):
|
||||
|
@ -253,7 +263,7 @@ func runBuild(dockerCli command.Cli, options buildOptions) error {
|
|||
}
|
||||
}
|
||||
|
||||
// replace Dockerfile if it was added from stdin and there is archive context
|
||||
// replace Dockerfile if it was added from stdin or a file outside the build-context, and there is archive context
|
||||
if dockerfileCtx != nil && buildCtx != nil {
|
||||
buildCtx, relDockerfile, err = build.AddDockerfileToBuildContext(dockerfileCtx, buildCtx)
|
||||
if err != nil {
|
||||
|
@ -261,7 +271,7 @@ func runBuild(dockerCli command.Cli, options buildOptions) error {
|
|||
}
|
||||
}
|
||||
|
||||
// if streaming and dockerfile was not from stdin then read from file
|
||||
// if streaming and Dockerfile was not from stdin then read from file
|
||||
// to the same reader that is usually stdin
|
||||
if options.stream && dockerfileCtx == nil {
|
||||
dockerfileCtx, err = os.Open(relDockerfile)
|
||||
|
|
|
@ -167,6 +167,10 @@ func GetContextFromGitURL(gitURL, dockerfileName string) (string, string, error)
|
|||
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
|
||||
}
|
||||
|
||||
|
@ -318,10 +322,6 @@ func getDockerfileRelPath(absContextDir, givenDockerfile string) (string, error)
|
|||
return "", errors.Errorf("unable to get relative Dockerfile path: %v", err)
|
||||
}
|
||||
|
||||
if strings.HasPrefix(relDockerfile, ".."+string(filepath.Separator)) {
|
||||
return "", errors.Errorf("the Dockerfile (%s) must be within the build context", givenDockerfile)
|
||||
}
|
||||
|
||||
return relDockerfile, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -108,6 +108,56 @@ func TestRunBuildDockerfileFromStdinWithCompress(t *testing.T) {
|
|||
assert.Equal(t, []string{dockerfileName, ".dockerignore", "foo"}, actual)
|
||||
}
|
||||
|
||||
func TestRunBuildDockerfileOutsideContext(t *testing.T) {
|
||||
dir := fs.NewDir(t, t.Name(),
|
||||
fs.WithFile("data", "data file"),
|
||||
)
|
||||
defer dir.Remove()
|
||||
|
||||
// Dockerfile outside of build-context
|
||||
df := fs.NewFile(t, t.Name(),
|
||||
fs.WithContent(`
|
||||
FROM FOOBAR
|
||||
COPY data /data
|
||||
`),
|
||||
)
|
||||
defer df.Remove()
|
||||
|
||||
dest, err := ioutil.TempDir("", t.Name())
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(dest)
|
||||
|
||||
var dockerfileName string
|
||||
fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
|
||||
buffer := new(bytes.Buffer)
|
||||
tee := io.TeeReader(context, buffer)
|
||||
|
||||
assert.NoError(t, archive.Untar(tee, dest, nil))
|
||||
dockerfileName = options.Dockerfile
|
||||
|
||||
body := new(bytes.Buffer)
|
||||
return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
|
||||
}
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})
|
||||
|
||||
options := newBuildOptions()
|
||||
options.context = dir.Path()
|
||||
options.dockerfileName = df.Path()
|
||||
|
||||
err = runBuild(cli, options)
|
||||
require.NoError(t, err)
|
||||
|
||||
files, err := ioutil.ReadDir(dest)
|
||||
require.NoError(t, err)
|
||||
var actual []string
|
||||
for _, fileInfo := range files {
|
||||
actual = append(actual, fileInfo.Name())
|
||||
}
|
||||
sort.Strings(actual)
|
||||
assert.Equal(t, []string{dockerfileName, ".dockerignore", "data"}, actual)
|
||||
}
|
||||
|
||||
// TestRunBuildFromLocalGitHubDirNonExistingRepo tests that build contexts
|
||||
// starting with `github.com/` are special-cased, and the build command attempts
|
||||
// to clone the remote repo.
|
||||
|
|
Loading…
Reference in New Issue