summaryrefslogtreecommitdiff
path: root/vendor/github.com/projectatomic/buildah/imagebuildah/build.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/projectatomic/buildah/imagebuildah/build.go')
-rw-r--r--vendor/github.com/projectatomic/buildah/imagebuildah/build.go118
1 files changed, 83 insertions, 35 deletions
diff --git a/vendor/github.com/projectatomic/buildah/imagebuildah/build.go b/vendor/github.com/projectatomic/buildah/imagebuildah/build.go
index 2c75fcfe1..e7fad7f67 100644
--- a/vendor/github.com/projectatomic/buildah/imagebuildah/build.go
+++ b/vendor/github.com/projectatomic/buildah/imagebuildah/build.go
@@ -11,6 +11,7 @@ import (
"strings"
"time"
+ cp "github.com/containers/image/copy"
is "github.com/containers/image/storage"
"github.com/containers/image/transports"
"github.com/containers/image/transports/alltransports"
@@ -697,6 +698,33 @@ func (b *Executor) Delete() (err error) {
return err
}
+// resolveNameToImageRef creates a types.ImageReference from b.output
+func (b *Executor) resolveNameToImageRef() (types.ImageReference, error) {
+ var (
+ imageRef types.ImageReference
+ err error
+ )
+ if b.output != "" {
+ imageRef, err = alltransports.ParseImageName(b.output)
+ if err != nil {
+ candidates := util.ResolveName(b.output, "", b.systemContext, b.store)
+ if len(candidates) == 0 {
+ return imageRef, errors.Errorf("error parsing target image name %q", b.output)
+ }
+ imageRef2, err2 := is.Transport.ParseStoreReference(b.store, candidates[0])
+ if err2 != nil {
+ return imageRef, errors.Wrapf(err, "error parsing target image name %q", b.output)
+ }
+ return imageRef2, nil
+ }
+ }
+ imageRef, err = is.Transport.ParseStoreReference(b.store, "@"+stringid.GenerateRandomID())
+ if err != nil {
+ return imageRef, errors.Wrapf(err, "error parsing reference for image to be written")
+ }
+ return imageRef, nil
+}
+
// Execute runs each of the steps in the parsed tree, in turn.
func (b *Executor) Execute(ctx context.Context, ib *imagebuilder.Builder, node *parser.Node) error {
checkForLayers := true
@@ -745,18 +773,31 @@ func (b *Executor) Execute(ctx context.Context, ib *imagebuilder.Builder, node *
return errors.Wrap(err, "error checking if cached image exists from a previous build")
}
}
+
+ if cacheID != "" {
+ fmt.Fprintf(b.out, "--> Using cache %s\n", cacheID)
+ }
+
+ // If a cache is found for the last step, that means nothing in the
+ // Dockerfile changed. Just create a copy of the existing image and
+ // save it with the new name passed in by the user.
+ if cacheID != "" && i == len(children)-1 {
+ if err := b.copyExistingImage(ctx, cacheID); err != nil {
+ return err
+ }
+ break
+ }
+
if cacheID == "" || !checkForLayers {
checkForLayers = false
err := ib.Run(step, b, requiresStart)
if err != nil {
return errors.Wrapf(err, "error building at step %+v", *step)
}
- } else {
- b.log("Using cache %s", cacheID)
}
- // Commit if at the last step of the Dockerfile and a cached image is found.
- // Also commit steps if no cache is found.
- if (cacheID != "" && i == len(children)-1) || cacheID == "" {
+
+ // Commit if no cache is found
+ if cacheID == "" {
imgID, err = b.Commit(ctx, ib, getCreatedBy(node))
if err != nil {
return errors.Wrapf(err, "error committing container for step %+v", *step)
@@ -785,6 +826,32 @@ func (b *Executor) Execute(ctx context.Context, ib *imagebuilder.Builder, node *
return nil
}
+// copyExistingImage creates a copy of an image already in store
+func (b *Executor) copyExistingImage(ctx context.Context, cacheID string) error {
+ // Get the destination Image Reference
+ dest, err := b.resolveNameToImageRef()
+ if err != nil {
+ return err
+ }
+
+ policyContext, err := util.GetPolicyContext(b.systemContext)
+ if err != nil {
+ return err
+ }
+ defer policyContext.Destroy()
+
+ // Look up the source image, expecting it to be in local storage
+ src, err := is.Transport.ParseStoreReference(b.store, cacheID)
+ if err != nil {
+ return errors.Wrapf(err, "error getting source imageReference for %q", cacheID)
+ }
+ if err := cp.Image(ctx, policyContext, dest, src, nil); err != nil {
+ return errors.Wrapf(err, "error copying image %q", cacheID)
+ }
+ b.log("COMMIT %s", b.output)
+ return nil
+}
+
// layerExists returns true if an intermediate image of currNode exists in the image store from a previous build.
// It verifies tihis by checking the parent of the top layer of the image and the history.
func (b *Executor) layerExists(ctx context.Context, currNode *parser.Node, children []*parser.Node) (string, error) {
@@ -958,30 +1025,11 @@ func urlContentModified(url string, historyTime *time.Time) (bool, error) {
// Commit writes the container's contents to an image, using a passed-in tag as
// the name if there is one, generating a unique ID-based one otherwise.
func (b *Executor) Commit(ctx context.Context, ib *imagebuilder.Builder, createdBy string) (string, error) {
- var (
- imageRef types.ImageReference
- err error
- )
-
- if b.output != "" {
- imageRef, err = alltransports.ParseImageName(b.output)
- if err != nil {
- candidates := util.ResolveName(b.output, "", b.systemContext, b.store)
- if len(candidates) == 0 {
- return "", errors.Errorf("error parsing target image name %q", b.output)
- }
- imageRef2, err2 := is.Transport.ParseStoreReference(b.store, candidates[0])
- if err2 != nil {
- return "", errors.Wrapf(err, "error parsing target image name %q", b.output)
- }
- imageRef = imageRef2
- }
- } else {
- imageRef, err = is.Transport.ParseStoreReference(b.store, "@"+stringid.GenerateRandomID())
- if err != nil {
- return "", errors.Wrapf(err, "error parsing reference for image to be written")
- }
+ imageRef, err := b.resolveNameToImageRef()
+ if err != nil {
+ return "", err
}
+
if ib.Author != "" {
b.builder.SetMaintainer(ib.Author)
}
@@ -1062,7 +1110,7 @@ func (b *Executor) Commit(ctx context.Context, ib *imagebuilder.Builder, created
return "", err
}
if options.IIDFile == "" && imgID != "" {
- fmt.Fprintf(b.out, "%s\n", imgID)
+ fmt.Fprintf(b.out, "--> %s\n", imgID)
}
return imgID, nil
}
@@ -1089,12 +1137,12 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) error
return err
}
}
- if b.layers || b.noCache {
- return nil
- }
- _, err := stageExecutor.Commit(ctx, stages[len(stages)-1].Builder, "")
- if err != nil {
- return err
+
+ if !b.layers && !b.noCache {
+ _, err := stageExecutor.Commit(ctx, stages[len(stages)-1].Builder, "")
+ if err != nil {
+ return err
+ }
}
// If building with layers and b.removeIntermediateCtrs is true
// only remove intermediate container for each step if an error