mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Add support for FROM
using named block
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
parent
73b4b8ed7f
commit
672ea30a94
4 changed files with 112 additions and 31 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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{}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue