github.com/cookieai-jar/moby@v17.12.1-ce-rc2+incompatible/api/server/backend/build/backend.go (about)

     1  package build
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/docker/distribution/reference"
     7  	"github.com/docker/docker/api/types"
     8  	"github.com/docker/docker/api/types/backend"
     9  	"github.com/docker/docker/builder"
    10  	"github.com/docker/docker/builder/fscache"
    11  	"github.com/docker/docker/image"
    12  	"github.com/docker/docker/pkg/stringid"
    13  	"github.com/pkg/errors"
    14  	"golang.org/x/net/context"
    15  )
    16  
    17  // ImageComponent provides an interface for working with images
    18  type ImageComponent interface {
    19  	SquashImage(from string, to string) (string, error)
    20  	TagImageWithReference(image.ID, string, reference.Named) error
    21  }
    22  
    23  // Builder defines interface for running a build
    24  type Builder interface {
    25  	Build(context.Context, backend.BuildConfig) (*builder.Result, error)
    26  }
    27  
    28  // Backend provides build functionality to the API router
    29  type Backend struct {
    30  	builder        Builder
    31  	fsCache        *fscache.FSCache
    32  	imageComponent ImageComponent
    33  }
    34  
    35  // NewBackend creates a new build backend from components
    36  func NewBackend(components ImageComponent, builder Builder, fsCache *fscache.FSCache) (*Backend, error) {
    37  	return &Backend{imageComponent: components, builder: builder, fsCache: fsCache}, nil
    38  }
    39  
    40  // Build builds an image from a Source
    41  func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string, error) {
    42  	options := config.Options
    43  	tagger, err := NewTagger(b.imageComponent, config.ProgressWriter.StdoutFormatter, options.Tags)
    44  	if err != nil {
    45  		return "", err
    46  	}
    47  
    48  	build, err := b.builder.Build(ctx, config)
    49  	if err != nil {
    50  		return "", err
    51  	}
    52  
    53  	var imageID = build.ImageID
    54  	if options.Squash {
    55  		if imageID, err = squashBuild(build, b.imageComponent); err != nil {
    56  			return "", err
    57  		}
    58  		if config.ProgressWriter.AuxFormatter != nil {
    59  			if err = config.ProgressWriter.AuxFormatter.Emit(types.BuildResult{ID: imageID}); err != nil {
    60  				return "", err
    61  			}
    62  		}
    63  	}
    64  
    65  	stdout := config.ProgressWriter.StdoutFormatter
    66  	fmt.Fprintf(stdout, "Successfully built %s\n", stringid.TruncateID(imageID))
    67  	err = tagger.TagImages(image.ID(imageID))
    68  	return imageID, err
    69  }
    70  
    71  // PruneCache removes all cached build sources
    72  func (b *Backend) PruneCache(ctx context.Context) (*types.BuildCachePruneReport, error) {
    73  	size, err := b.fsCache.Prune(ctx)
    74  	if err != nil {
    75  		return nil, errors.Wrap(err, "failed to prune build cache")
    76  	}
    77  	return &types.BuildCachePruneReport{SpaceReclaimed: size}, nil
    78  }
    79  
    80  func squashBuild(build *builder.Result, imageComponent ImageComponent) (string, error) {
    81  	var fromID string
    82  	if build.FromImage != nil {
    83  		fromID = build.FromImage.ImageID()
    84  	}
    85  	imageID, err := imageComponent.SquashImage(build.ImageID, fromID)
    86  	if err != nil {
    87  		return "", errors.Wrap(err, "error squashing image")
    88  	}
    89  	return imageID, nil
    90  }