|
@@ -1,6 +1,8 @@
|
|
|
package dockerfile
|
|
|
|
|
|
import (
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
"sync"
|
|
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
@@ -14,28 +16,25 @@ import (
|
|
|
type imageContexts struct {
|
|
|
b *Builder
|
|
|
list []*imageMount
|
|
|
- byName map[string]int
|
|
|
+ byName map[string]*imageMount
|
|
|
cache *pathCache
|
|
|
}
|
|
|
|
|
|
-type imageMount struct {
|
|
|
- id string
|
|
|
- ctx builder.Context
|
|
|
- release func() error
|
|
|
-}
|
|
|
-
|
|
|
-func (ic *imageContexts) new(name string) error {
|
|
|
+func (ic *imageContexts) new(name string, increment bool) (*imageMount, error) {
|
|
|
+ im := &imageMount{ic: ic}
|
|
|
if len(name) > 0 {
|
|
|
if ic.byName == nil {
|
|
|
- ic.byName = make(map[string]int)
|
|
|
+ ic.byName = make(map[string]*imageMount)
|
|
|
}
|
|
|
if _, ok := ic.byName[name]; ok {
|
|
|
- return errors.Errorf("duplicate name %s", name)
|
|
|
+ return nil, errors.Errorf("duplicate name %s", name)
|
|
|
}
|
|
|
- ic.byName[name] = len(ic.list)
|
|
|
+ ic.byName[name] = im
|
|
|
}
|
|
|
- ic.list = append(ic.list, &imageMount{})
|
|
|
- return nil
|
|
|
+ if increment {
|
|
|
+ ic.list = append(ic.list, im)
|
|
|
+ }
|
|
|
+ return im, nil
|
|
|
}
|
|
|
|
|
|
func (ic *imageContexts) update(imageID string) {
|
|
@@ -53,59 +52,94 @@ func (ic *imageContexts) validate(i int) error {
|
|
|
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)
|
|
|
+func (ic *imageContexts) get(indexOrName string) (*imageMount, error) {
|
|
|
+ index, err := strconv.Atoi(indexOrName)
|
|
|
+ if err == nil {
|
|
|
+ if err := ic.validate(index); err != nil {
|
|
|
+ return nil, err
|
|
|
}
|
|
|
- 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 ic.list[index], nil
|
|
|
}
|
|
|
- return im.ctx, nil
|
|
|
+ if im, ok := ic.byName[strings.ToLower(indexOrName)]; ok {
|
|
|
+ return im, nil
|
|
|
+ }
|
|
|
+ im, err := mountByRef(ic.b, indexOrName)
|
|
|
+ if err != nil {
|
|
|
+ return nil, errors.Wrapf(err, "invalid from flag value %s", indexOrName)
|
|
|
+ }
|
|
|
+ return im, 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
|
|
|
- }
|
|
|
+ if err := im.unmount(); err != nil {
|
|
|
+ logrus.Error(err)
|
|
|
+ retErr = err
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for _, im := range ic.byName {
|
|
|
+ if err := im.unmount(); err != nil {
|
|
|
+ logrus.Error(err)
|
|
|
+ retErr = err
|
|
|
}
|
|
|
}
|
|
|
return
|
|
|
}
|
|
|
|
|
|
-func (ic *imageContexts) getCache(i int, path string) (interface{}, bool) {
|
|
|
+func (ic *imageContexts) getCache(id, path string) (interface{}, bool) {
|
|
|
if ic.cache != nil {
|
|
|
- im := ic.list[i]
|
|
|
- if im.id == "" {
|
|
|
+ if id == "" {
|
|
|
return nil, false
|
|
|
}
|
|
|
- return ic.cache.get(im.id + path)
|
|
|
+ return ic.cache.get(id + path)
|
|
|
}
|
|
|
return nil, false
|
|
|
}
|
|
|
|
|
|
-func (ic *imageContexts) setCache(i int, path string, v interface{}) {
|
|
|
+func (ic *imageContexts) setCache(id, path string, v interface{}) {
|
|
|
if ic.cache != nil {
|
|
|
- ic.cache.set(ic.list[i].id+path, v)
|
|
|
+ ic.cache.set(id+path, v)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// imageMount is a reference for getting access to a buildcontext that is backed
|
|
|
+// by an existing image
|
|
|
+type imageMount struct {
|
|
|
+ id string
|
|
|
+ ctx builder.Context
|
|
|
+ release func() error
|
|
|
+ ic *imageContexts
|
|
|
+}
|
|
|
+
|
|
|
+func (im *imageMount) context() (builder.Context, error) {
|
|
|
+ if im.ctx == nil {
|
|
|
+ if im.id == "" {
|
|
|
+ return nil, errors.Errorf("could not copy from empty context")
|
|
|
+ }
|
|
|
+ p, release, err := im.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)
|
|
|
+ }
|
|
|
+ im.release = release
|
|
|
+ im.ctx = ctx
|
|
|
+ }
|
|
|
+ return im.ctx, nil
|
|
|
+}
|
|
|
+
|
|
|
+func (im *imageMount) unmount() error {
|
|
|
+ if im.release != nil {
|
|
|
+ if err := im.release(); err != nil {
|
|
|
+ return errors.Wrapf(err, "failed to unmount previous build image %s", im.id)
|
|
|
+ }
|
|
|
+ im.release = nil
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
type pathCache struct {
|
|
|
mu sync.Mutex
|
|
|
items map[string]interface{}
|