func (n *buildNode) pullCacheLayer(cacheMgr cache.Manager) bool {
	digestPair, err := cacheMgr.PullCache(n.CacheID())
	if err != nil {
		log.Errorf("Failed to fetch intermediate layer with cache ID %s: %s", n.CacheID(), err)
		return false
	} else if digestPair == nil {
		return true
	}
	n.digestPairs = []*image.DigestPair{digestPair}
	return true
}
pullCacheLayer pulls cached layers for this node's digest pair(s).
package builder
import (
	"archive/tar"
	"fmt"
	"strings"
	"time"
	"github.com/uber/makisu/lib/builder/step"
	"github.com/uber/makisu/lib/cache"
	"github.com/uber/makisu/lib/context"
	"github.com/uber/makisu/lib/docker/image"
	"github.com/uber/makisu/lib/log"
	"github.com/uber/makisu/lib/tario"
)
type buildNodeOptions struct {
	skipBuild   bool  
	forceCommit bool  
	modifyFS    bool  
}
type buildNode struct {
	step.BuildStep
	ctx *context.BuildContext
	digestPairs []*image.DigestPair
}
func newBuildNode(ctx *context.BuildContext, step step.BuildStep) *buildNode {
	return &buildNode{
		BuildStep: step,
		ctx:       ctx,
	}
}
func (n *buildNode) Build(
	cacheMgr cache.Manager, prevConfig *image.Config,
	opts *buildNodeOptions) (*image.Config, error) {
	if err := n.ApplyCtxAndConfig(n.ctx, prevConfig); err != nil {
		return nil, fmt.Errorf("apply config: %s", err)
	}
	cached := n.digestPairs != nil
	if cached {
		for _, pair := range n.digestPairs {
			if err := n.applyLayer(pair, opts.modifyFS); err != nil {
				return nil, fmt.Errorf("apply cache: %s", err)
			}
		}
	}
	if opts.skipBuild {
		log.Infof("* Skipping execution; a later step was cached *")
	} else if cached {
		log.Infof("* Skipping execution; cache was applied *")
	} else if err := n.doExecute(cacheMgr, opts); err != nil {
		return nil, fmt.Errorf("do execute: %s", err)
	} else if !n.HasCommit() && !opts.forceCommit {
		log.Infof("* Not committing step %s", n.String())
	} else if err := n.doCommit(cacheMgr, opts); err != nil {
		return nil, fmt.Errorf("do commit: %s", err)
	}
	config, err := n.UpdateCtxAndConfig(n.ctx, prevConfig)
	if err != nil {
		return nil, fmt.Errorf("generate config: %s", err)
	}
	return config, nil
}
func (n *buildNode) doCommit(cacheMgr cache.Manager, opts *buildNodeOptions) error {
	var err error
	n.digestPairs, err = n.Commit(n.ctx)
	if err != nil {
		return fmt.Errorf("commit: %s", err)
	}
	if len(n.digestPairs) > 1 {
		return nil
	}
	if err := n.pushCacheLayer(cacheMgr); err != nil {
		return fmt.Errorf("push cache: %s", err)
	}
	return nil
}
func (n *buildNode) doExecute(cacheMgr cache.Manager, opts *buildNodeOptions) error {
	start := time.Now()
	err := n.Execute(n.ctx, opts.modifyFS)
	if err != nil {
		return fmt.Errorf("execute step: %s", err)
	}
	log.Infow(fmt.Sprintf("* Executed %s", n.String()), "duration", time.Since(start))
	return nil
}
func (n *buildNode) applyLayer(digestPair *image.DigestPair, modifyfs bool) error {
	reader, err := n.ctx.ImageStore.Layers.GetStoreFileReader(digestPair.GzipDescriptor.Digest.Hex())
	if err != nil {
		return fmt.Errorf("get reader from layer: %s", err)
	}
	gzipReader, err := tario.NewGzipReader(reader)
	if err != nil {
		return fmt.Errorf("create gzip reader for layer: %s", err)
	}
	log.Infof("* Applying cache layer %s (unpack=%v)",
		digestPair.GzipDescriptor.Digest.Hex(), modifyfs)
	if err := n.ctx.MemFS.UpdateFromTarReader(tar.NewReader(gzipReader), modifyfs); err != nil {
		return fmt.Errorf("untar reader: %s", err)
	}
	return nil
}
func (n *buildNode) pushCacheLayer(cacheMgr cache.Manager) error {
	var digestPair *image.DigestPair
	if len(n.digestPairs) != 0 {
		digestPair = n.digestPairs[0]
	}
	if digestPair != nil {
		log.Infof("* Committed gzipped layer %s (%d bytes)",
			digestPair.GzipDescriptor.Digest, digestPair.GzipDescriptor.Size)
	}
	log.Infof("* Pushing with cache ID %s", n.CacheID())
	return cacheMgr.PushCache(n.CacheID(), digestPair)
}