Skip to content

Commit

Permalink
Refactor imageContexts into two different structs.
Browse files Browse the repository at this point in the history
buildStages now tracks the imageID and runConfig for a build stage

imageMounter tracks image mounts so they can released when the build ends.

Signed-off-by: Daniel Nephin <[email protected]>
  • Loading branch information
dnephin committed May 10, 2017
1 parent ab3a037 commit 6c28e8e
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 152 deletions.
2 changes: 1 addition & 1 deletion api/types/backend/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type BuildConfig struct {
Options *types.ImageBuildOptions
}

// GetImageAndLayerOptions are the options supported by GetImageAndLayer
// GetImageAndLayerOptions are the options supported by GetImageAndReleasableLayer
type GetImageAndLayerOptions struct {
ForcePull bool
AuthConfig map[string]types.AuthConfig
Expand Down
9 changes: 7 additions & 2 deletions builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type Source interface {

// Backend abstracts calls to a Docker Daemon.
type Backend interface {
GetImageAndLayer(ctx context.Context, refOrID string, opts backend.GetImageAndLayerOptions) (Image, ReleaseableLayer, error)
ImageBackend

// ContainerAttachRaw attaches to container.
ContainerAttachRaw(cID string, stdin io.ReadCloser, stdout, stderr io.Writer, stream bool, attached chan struct{}) error
Expand All @@ -60,6 +60,11 @@ type Backend interface {
CopyOnBuild(containerID string, destPath string, srcRoot string, srcPath string, decompress bool) error
}

// ImageBackend are the interface methods required from an image component
type ImageBackend interface {
GetImageAndReleasableLayer(ctx context.Context, refOrID string, opts backend.GetImageAndLayerOptions) (Image, ReleaseableLayer, error)
}

// Result is the output produced by a Builder
type Result struct {
ImageID string
Expand Down Expand Up @@ -89,5 +94,5 @@ type Image interface {
// ReleaseableLayer is an image layer that can be mounted and released
type ReleaseableLayer interface {
Release() error
Mount(string) (string, error)
Mount() (string, error)
}
8 changes: 5 additions & 3 deletions builder/dockerfile/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,12 @@ type Builder struct {
clientCtx context.Context

tmpContainers map[string]struct{}
imageContexts *imageContexts // helper for storing contexts from builds
buildStages *buildStages
disableCommit bool
cacheBusted bool
buildArgs *buildArgs
imageCache builder.ImageCache
imageSources *imageSources
}

// newBuilder creates a new Dockerfile builder from an optional dockerfile and a Options.
Expand All @@ -125,7 +126,8 @@ func newBuilder(clientCtx context.Context, options builderOptions) *Builder {
docker: options.Backend,
tmpContainers: map[string]struct{}{},
buildArgs: newBuildArgs(config.BuildArgs),
imageContexts: &imageContexts{},
buildStages: newBuildStages(),
imageSources: newImageSources(clientCtx, options),
}
return b
}
Expand All @@ -140,7 +142,7 @@ func (b *Builder) resetImageCache() {
// Build runs the Dockerfile builder by parsing the Dockerfile and executing
// the instructions from the file.
func (b *Builder) build(source builder.Source, dockerfile *parser.Result) (*builder.Result, error) {
defer b.imageContexts.unmount()
defer b.imageSources.Unmount()

// TODO: Remove source field from Builder
b.source = source
Expand Down
42 changes: 22 additions & 20 deletions builder/dockerfile/dispatchers.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/strslice"
"github.com/docker/docker/builder"
"github.com/docker/docker/builder/dockerfile/parser"
"github.com/docker/docker/pkg/signal"
"github.com/docker/go-connections/nat"
Expand Down Expand Up @@ -174,14 +174,19 @@ func dispatchCopy(req dispatchRequest) error {

func (b *Builder) getImageMount(fromFlag *Flag) (*imageMount, error) {
if !fromFlag.IsUsed() {
// TODO: this could return the mount in the default case as well
// TODO: this could return the source in the default case as well?
return nil, nil
}
im, err := b.imageContexts.getMount(fromFlag.Value)
if err != nil || im != nil {
return im, err

imageRefOrID := fromFlag.Value
stage, err := b.buildStages.get(fromFlag.Value)
if err != nil {
return nil, err
}
if stage != nil {
imageRefOrID = stage.ImageID()
}
return b.getImage(fromFlag.Value)
return b.imageSources.Get(imageRefOrID)
}

// FROM imagename[:tag | @digest] [AS build-stage-name]
Expand All @@ -201,7 +206,7 @@ func from(req dispatchRequest) error {
if err != nil {
return err
}
if err := req.builder.imageContexts.add(stageName, image); err != nil {
if err := req.builder.buildStages.add(stageName, image); err != nil {
return err
}
req.state.beginStage(stageName, image)
Expand Down Expand Up @@ -229,7 +234,12 @@ func parseBuildStageName(args []string) (string, error) {
return stageName, nil
}

func (b *Builder) getFromImage(shlex *ShellLex, name string) (*imageMount, error) {
// scratchImage is used as a token for the empty base image. It uses buildStage
// as a convenient implementation of builder.Image, but is not actually a
// buildStage.
var scratchImage builder.Image = &buildStage{}

func (b *Builder) getFromImage(shlex *ShellLex, name string) (builder.Image, error) {
substitutionArgs := []string{}
for key, value := range b.buildArgs.GetAllMeta() {
substitutionArgs = append(substitutionArgs, key+"="+value)
Expand All @@ -240,7 +250,7 @@ func (b *Builder) getFromImage(shlex *ShellLex, name string) (*imageMount, error
return nil, err
}

if im, ok := b.imageContexts.byName[name]; ok {
if im, ok := b.buildStages.getByName(name); ok {
return im, nil
}

Expand All @@ -249,21 +259,13 @@ func (b *Builder) getFromImage(shlex *ShellLex, name string) (*imageMount, error
if runtime.GOOS == "windows" {
return nil, errors.New("Windows does not support FROM scratch")
}
return newImageMount(nil, nil), nil
return scratchImage, nil
}
return b.getImage(name)
}

func (b *Builder) getImage(name string) (*imageMount, error) {
image, layer, err := b.docker.GetImageAndLayer(b.clientCtx, name, backend.GetImageAndLayerOptions{
ForcePull: b.options.PullParent,
AuthConfig: b.options.AuthConfigs,
Output: b.Output,
})
imageMount, err := b.imageSources.Get(name)
if err != nil {
return nil, err
}
return newImageMount(image, layer), nil
return imageMount.Image(), nil
}

func processOnBuild(req dispatchRequest) error {
Expand Down
9 changes: 7 additions & 2 deletions builder/dockerfile/dispatchers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,20 @@ func defaultDispatchReq(builder *Builder, args ...string) dispatchRequest {

func newBuilderWithMockBackend() *Builder {
mockBackend := &MockBackend{}
ctx := context.Background()
b := &Builder{
options: &types.ImageBuildOptions{},
docker: mockBackend,
buildArgs: newBuildArgs(make(map[string]*string)),
tmpContainers: make(map[string]struct{}),
Stdout: new(bytes.Buffer),
clientCtx: context.Background(),
clientCtx: ctx,
disableCommit: true,
imageContexts: &imageContexts{},
imageSources: newImageSources(ctx, builderOptions{
Options: &types.ImageBuildOptions{},
Backend: mockBackend,
}),
buildStages: newBuildStages(),
}
return b
}
Expand Down
Loading

0 comments on commit 6c28e8e

Please sign in to comment.