moby--moby/builder/dockerfile/imagecontext.go

122 lines
2.5 KiB
Go
Raw Normal View History

package dockerfile
import (
"sync"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/builder"
"github.com/docker/docker/builder/remotecontext"
"github.com/pkg/errors"
)
// imageContexts is a helper for stacking up built image rootfs and reusing
// them as contexts
type imageContexts struct {
b *Builder
list []*imageMount
cache *pathCache
}
type imageMount struct {
id string
ctx builder.Context
release func() error
}
func (ic *imageContexts) new() {
ic.list = append(ic.list, &imageMount{})
}
func (ic *imageContexts) update(imageID string) {
ic.list[len(ic.list)-1].id = imageID
}
func (ic *imageContexts) validate(i int) error {
if i < 0 || i >= len(ic.list)-1 {
var extraMsg string
if i == len(ic.list)-1 {
extraMsg = " refers current build block"
}
return errors.Errorf("invalid from flag value %d%s", i, extraMsg)
}
return nil
}
func (ic *imageContexts) context(i int) (builder.Context, error) {
if err := ic.validate(i); err != nil {
return nil, err
}
im := ic.list[i]
if im.ctx == nil {
if im.id == "" {
return nil, errors.Errorf("could not copy from empty context")
}
p, release, err := ic.b.docker.MountImage(im.id)
if err != nil {
return nil, errors.Wrapf(err, "failed to mount %s", im.id)
}
ctx, err := remotecontext.NewLazyContext(p)
if err != nil {
return nil, errors.Wrapf(err, "failed to create lazycontext for %s", p)
}
logrus.Debugf("mounted image: %s %s", im.id, p)
im.release = release
im.ctx = ctx
}
return im.ctx, nil
}
func (ic *imageContexts) unmount() (retErr error) {
for _, im := range ic.list {
if im.release != nil {
if err := im.release(); err != nil {
logrus.Error(errors.Wrapf(err, "failed to unmount previous build image"))
retErr = err
}
}
}
return
}
func (ic *imageContexts) getCache(i int, path string) (interface{}, bool) {
if ic.cache != nil {
im := ic.list[i]
if im.id == "" {
return nil, false
}
return ic.cache.get(im.id + path)
}
return nil, false
}
func (ic *imageContexts) setCache(i int, path string, v interface{}) {
if ic.cache != nil {
ic.cache.set(ic.list[i].id+path, v)
}
}
type pathCache struct {
mu sync.Mutex
items map[string]interface{}
}
func (c *pathCache) set(k string, v interface{}) {
c.mu.Lock()
if c.items == nil {
c.items = make(map[string]interface{})
}
c.items[k] = v
c.mu.Unlock()
}
func (c *pathCache) get(k string) (interface{}, bool) {
c.mu.Lock()
if c.items == nil {
c.mu.Unlock()
return nil, false
}
v, ok := c.items[k]
c.mu.Unlock()
return v, ok
}