Remove package daemonbuilder.

Currently, daemonbuilder package (part of daemon) implemented the
builder backend. However, it was a very thin wrapper around daemon
methods and caused an implementation dependency for api/server build
endpoint. api/server buildrouter should only know about the backend
implementing the /build API endpoint.

Removing daemonbuilder involved moving build specific methods to
respective files in the daemon, where they fit naturally.

Signed-off-by: Anusha Ragunathan <anusha@docker.com>
Upstream-commit: 9c332b164f1aefa2407706adf59d50495d6e02cb
Component: engine
This commit is contained in:
Anusha Ragunathan
2016-01-20 15:32:02 -08:00
parent 62fbfcd843
commit fe296e65a0
21 changed files with 411 additions and 427 deletions

View File

@ -2,6 +2,7 @@ package dockerfile
import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
@ -13,6 +14,7 @@ import (
"github.com/docker/docker/builder"
"github.com/docker/docker/builder/dockerfile/parser"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/reference"
"github.com/docker/engine-api/types"
"github.com/docker/engine-api/types/container"
)
@ -48,6 +50,7 @@ type Builder struct {
Stdout io.Writer
Stderr io.Writer
Output io.Writer
docker builder.Backend
context builder.Context
@ -67,8 +70,17 @@ type Builder struct {
allowedBuildArgs map[string]bool // list of build-time args that are allowed for expansion/substitution and passing to commands in 'run'.
// TODO: remove once docker.Commit can receive a tag
id string
Output io.Writer
id string
}
// BuildManager implements builder.Backend and is shared across all Builder objects.
type BuildManager struct {
backend builder.Backend
}
// NewBuildManager creates a BuildManager.
func NewBuildManager(b builder.Backend) (bm *BuildManager) {
return &BuildManager{backend: b}
}
// NewBuilder creates a new Dockerfile builder from an optional dockerfile and a Config.
@ -103,7 +115,57 @@ func NewBuilder(config *types.ImageBuildOptions, backend builder.Backend, contex
return b, nil
}
// Build runs the Dockerfile builder from a context and a docker object that allows to make calls
// sanitizeRepoAndTags parses the raw "t" parameter received from the client
// to a slice of repoAndTag.
// It also validates each repoName and tag.
func sanitizeRepoAndTags(names []string) ([]reference.Named, error) {
var (
repoAndTags []reference.Named
// This map is used for deduplicating the "-t" parameter.
uniqNames = make(map[string]struct{})
)
for _, repo := range names {
if repo == "" {
continue
}
ref, err := reference.ParseNamed(repo)
if err != nil {
return nil, err
}
ref = reference.WithDefaultTag(ref)
if _, isCanonical := ref.(reference.Canonical); isCanonical {
return nil, errors.New("build tag cannot contain a digest")
}
if _, isTagged := ref.(reference.NamedTagged); !isTagged {
ref, err = reference.WithTag(ref, reference.DefaultTag)
}
nameWithTag := ref.String()
if _, exists := uniqNames[nameWithTag]; !exists {
uniqNames[nameWithTag] = struct{}{}
repoAndTags = append(repoAndTags, ref)
}
}
return repoAndTags, nil
}
// Build creates a NewBuilder, which builds the image.
func (bm *BuildManager) Build(config *types.ImageBuildOptions, context builder.Context, stdout io.Writer, stderr io.Writer, out io.Writer, clientGone <-chan bool) (string, error) {
b, err := NewBuilder(config, bm.backend, context, nil)
if err != nil {
return "", err
}
img, err := b.build(config, context, stdout, stderr, out, clientGone)
return img, err
}
// build runs the Dockerfile builder from a context and a docker object that allows to make calls
// to Docker.
//
// This will (barring errors):
@ -113,10 +175,16 @@ func NewBuilder(config *types.ImageBuildOptions, backend builder.Backend, contex
// * walk the AST and execute it by dispatching to handlers. If Remove
// or ForceRemove is set, additional cleanup around containers happens after
// processing.
// * Tag image, if applicable.
// * Print a happy message and return the image ID.
// * NOT tag the image, that is responsibility of the caller.
//
func (b *Builder) Build() (string, error) {
func (b *Builder) build(config *types.ImageBuildOptions, context builder.Context, stdout io.Writer, stderr io.Writer, out io.Writer, clientGone <-chan bool) (string, error) {
b.options = config
b.context = context
b.Stdout = stdout
b.Stderr = stderr
b.Output = out
// If Dockerfile was not parsed yet, extract it from the Context
if b.dockerfile == nil {
if err := b.readDockerfile(); err != nil {
@ -124,6 +192,24 @@ func (b *Builder) Build() (string, error) {
}
}
finished := make(chan struct{})
defer close(finished)
go func() {
select {
case <-finished:
case <-clientGone:
b.cancelOnce.Do(func() {
close(b.cancelled)
})
}
}()
repoAndTags, err := sanitizeRepoAndTags(config.Tags)
if err != nil {
return "", err
}
var shortImgID string
for i, n := range b.dockerfile.Children {
select {
@ -163,6 +249,12 @@ func (b *Builder) Build() (string, error) {
return "", fmt.Errorf("No image was generated. Is your Dockerfile empty?")
}
for _, rt := range repoAndTags {
if err := b.docker.TagImage(rt, b.image); err != nil {
return "", err
}
}
fmt.Fprintf(b.Stdout, "Successfully built %s\n", shortImgID)
return b.image, nil
}

View File

@ -208,11 +208,11 @@ func from(b *Builder, args []string, attributes map[string]bool, original string
} else {
// TODO: don't use `name`, instead resolve it to a digest
if !b.options.PullParent {
image, err = b.docker.GetImage(name)
image, err = b.docker.GetImageOnBuild(name)
// TODO: shouldn't we error out if error is different from "not found" ?
}
if image == nil {
image, err = b.docker.Pull(name, b.options.AuthConfigs, b.Output)
image, err = b.docker.PullOnBuild(name, b.options.AuthConfigs, b.Output)
if err != nil {
return err
}

View File

@ -205,7 +205,7 @@ func (b *Builder) runContextCommand(args []string, allowRemote bool, allowLocalD
}
for _, info := range infos {
if err := b.docker.BuilderCopy(container.ID, dest, info.FileInfo, info.decompress); err != nil {
if err := b.docker.CopyOnBuild(container.ID, dest, info.FileInfo, info.decompress); err != nil {
return err
}
}
@ -396,10 +396,10 @@ func containsWildcards(name string) bool {
func (b *Builder) processImageFrom(img builder.Image) error {
if img != nil {
b.image = img.ID()
b.image = img.ImageID()
if img.Config() != nil {
b.runConfig = img.Config()
if img.RunConfig() != nil {
b.runConfig = img.RunConfig()
}
}
@ -469,7 +469,7 @@ func (b *Builder) probeCache() (bool, error) {
if !ok || b.options.NoCache || b.cacheBusted {
return false, nil
}
cache, err := c.GetCachedImage(b.image, b.runConfig)
cache, err := c.GetCachedImageOnBuild(b.image, b.runConfig)
if err != nil {
return false, err
}
@ -530,7 +530,7 @@ func (b *Builder) create() (string, error) {
if config.Cmd.Len() > 0 {
// override the entry point that may have been picked up from the base image
if err := b.docker.ContainerUpdateCmd(c.ID, config.Cmd.Slice()); err != nil {
if err := b.docker.ContainerUpdateCmdOnBuild(c.ID, config.Cmd.Slice()); err != nil {
return "", err
}
}
@ -541,7 +541,7 @@ func (b *Builder) create() (string, error) {
func (b *Builder) run(cID string) (err error) {
errCh := make(chan error)
go func() {
errCh <- b.docker.ContainerAttach(cID, nil, b.Stdout, b.Stderr, true)
errCh <- b.docker.ContainerAttachOnBuild(cID, nil, b.Stdout, b.Stderr, true)
}()
finished := make(chan struct{})