Add support for `FROM` using named block

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi 2017-03-22 18:36:08 -07:00
parent 73b4b8ed7f
commit 672ea30a94
4 changed files with 112 additions and 31 deletions

View File

@ -227,27 +227,28 @@ func from(b *Builder, args []string, attributes map[string]bool, original string
return err
}
// Windows cannot support a container with no base image.
if name == api.NoBaseImageSpecifier {
if runtime.GOOS == "windows" {
return errors.New("Windows does not support FROM scratch")
if im, ok := b.imageContexts.byName[name]; ok {
if len(im.ImageID()) > 0 {
image = im
}
b.image = ""
b.noBaseImage = true
} else {
// TODO: don't use `name`, instead resolve it to a digest
if !b.options.PullParent {
image, _ = b.docker.GetImageOnBuild(name)
// TODO: shouldn't we error out if error is different from "not found" ?
}
if image == nil {
// Windows cannot support a container with no base image.
if name == api.NoBaseImageSpecifier {
if runtime.GOOS == "windows" {
return errors.New("Windows does not support FROM scratch")
}
b.image = ""
b.noBaseImage = true
} else {
var err error
image, err = b.docker.PullOnBuild(b.clientCtx, name, b.options.AuthConfigs, b.Output)
image, err = pullOrGetImage(b, name)
if err != nil {
return err
}
}
b.imageContexts.update(image.ImageID())
}
if image != nil {
b.imageContexts.update(image.ImageID(), image.RunConfig())
}
b.from = image
@ -838,16 +839,9 @@ func getShell(c *container.Config) []string {
// mountByRef creates an imageMount from a reference. pulling the image if needed.
func mountByRef(b *Builder, name string) (*imageMount, error) {
var image builder.Image
if !b.options.PullParent {
image, _ = b.docker.GetImageOnBuild(name)
}
if image == nil {
var err error
image, err = b.docker.PullOnBuild(b.clientCtx, name, b.options.AuthConfigs, b.Output)
if err != nil {
return nil, err
}
image, err := pullOrGetImage(b, name)
if err != nil {
return nil, err
}
im, err := b.imageContexts.new("", false)
if err != nil {
@ -856,3 +850,19 @@ func mountByRef(b *Builder, name string) (*imageMount, error) {
im.id = image.ImageID()
return im, nil
}
func pullOrGetImage(b *Builder, name string) (builder.Image, error) {
var image builder.Image
if !b.options.PullParent {
image, _ = b.docker.GetImageOnBuild(name)
// TODO: shouldn't we error out if error is different from "not found" ?
}
if image == nil {
var err error
image, err = b.docker.PullOnBuild(b.clientCtx, name, b.options.AuthConfigs, b.Output)
if err != nil {
return nil, err
}
}
return image, nil
}

View File

@ -6,6 +6,7 @@ import (
"sync"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/builder"
"github.com/docker/docker/builder/remotecontext"
"github.com/pkg/errors"
@ -37,8 +38,9 @@ func (ic *imageContexts) new(name string, increment bool) (*imageMount, error) {
return im, nil
}
func (ic *imageContexts) update(imageID string) {
func (ic *imageContexts) update(imageID string, runConfig *container.Config) {
ic.list[len(ic.list)-1].id = imageID
ic.list[len(ic.list)-1].runConfig = runConfig
}
func (ic *imageContexts) validate(i int) error {
@ -105,10 +107,11 @@ func (ic *imageContexts) setCache(id, path string, v interface{}) {
// imageMount is a reference for getting access to a buildcontext that is backed
// by an existing image
type imageMount struct {
id string
ctx builder.Context
release func() error
ic *imageContexts
id string
ctx builder.Context
release func() error
ic *imageContexts
runConfig *container.Config
}
func (im *imageMount) context() (builder.Context, error) {
@ -140,6 +143,13 @@ func (im *imageMount) unmount() error {
return nil
}
func (im *imageMount) ImageID() string {
return im.id
}
func (im *imageMount) RunConfig() *container.Config {
return im.runConfig
}
type pathCache struct {
mu sync.Mutex
items map[string]interface{}

View File

@ -85,7 +85,7 @@ func (b *Builder) commit(id string, autoCmd strslice.StrSlice, comment string) e
}
b.image = imageID
b.imageContexts.update(imageID)
b.imageContexts.update(imageID, &autoConfig)
return nil
}
@ -497,7 +497,7 @@ func (b *Builder) probeCache() (bool, error) {
fmt.Fprint(b.Stdout, " ---> Using cache\n")
logrus.Debugf("[BUILDER] Use cached version: %s", b.runConfig.Cmd)
b.image = string(cache)
b.imageContexts.update(b.image)
b.imageContexts.update(b.image, b.runConfig)
return true, nil
}

View File

@ -5941,6 +5941,67 @@ func (s *DockerSuite) TestBuildCopyFromImplicitFrom(c *check.C) {
}
}
func (s *DockerRegistrySuite) TestBuildCopyFromImplicitPullingFrom(c *check.C) {
repoName := fmt.Sprintf("%v/dockercli/testf", privateRegistryURL)
dockerfile := `
FROM busybox
COPY foo bar`
ctx := fakeContext(c, dockerfile, map[string]string{
"Dockerfile": dockerfile,
"foo": "abc",
})
defer ctx.Close()
result := buildImage(repoName, withExternalBuildContext(ctx))
result.Assert(c, icmd.Success)
dockerCmd(c, "push", repoName)
dockerCmd(c, "rmi", repoName)
dockerfile = `
FROM busybox
COPY --from=%s bar baz`
ctx = fakeContext(c, fmt.Sprintf(dockerfile, repoName), map[string]string{
"Dockerfile": dockerfile,
})
defer ctx.Close()
result = buildImage("build1", withExternalBuildContext(ctx))
result.Assert(c, icmd.Success)
dockerCmdWithResult("run", "build1", "cat", "baz").Assert(c, icmd.Expected{Out: "abc"})
}
func (s *DockerSuite) TestBuildFromPreviousBlock(c *check.C) {
dockerfile := `
FROM busybox as foo
COPY foo /
FROM foo as foo1
RUN echo 1 >> foo
FROM foo as foO2
RUN echo 2 >> foo
FROM foo
COPY --from=foo1 foo f1
COPY --from=FOo2 foo f2
` // foo2 case also tests that names are canse insensitive
ctx := fakeContext(c, dockerfile, map[string]string{
"Dockerfile": dockerfile,
"foo": "bar",
})
defer ctx.Close()
result := buildImage("build1", withExternalBuildContext(ctx))
result.Assert(c, icmd.Success)
dockerCmdWithResult("run", "build1", "cat", "foo").Assert(c, icmd.Expected{Out: "bar"})
dockerCmdWithResult("run", "build1", "cat", "f1").Assert(c, icmd.Expected{Out: "bar1"})
dockerCmdWithResult("run", "build1", "cat", "f2").Assert(c, icmd.Expected{Out: "bar2"})
}
// TestBuildOpaqueDirectory tests that a build succeeds which
// creates opaque directories.
// See https://github.com/docker/docker/issues/25244