imagecontext.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. package dockerfile
  2. import (
  3. "strconv"
  4. "strings"
  5. "github.com/Sirupsen/logrus"
  6. "github.com/docker/docker/api/types/container"
  7. "github.com/docker/docker/builder"
  8. "github.com/docker/docker/builder/remotecontext"
  9. "github.com/pkg/errors"
  10. )
  11. type pathCache interface {
  12. Load(key interface{}) (value interface{}, ok bool)
  13. Store(key, value interface{})
  14. }
  15. // imageContexts is a helper for stacking up built image rootfs and reusing
  16. // them as contexts
  17. type imageContexts struct {
  18. b *Builder
  19. list []*imageMount // indexed list of stages
  20. implicitMounts []*imageMount // implicitly mounted images
  21. byName map[string]*imageMount
  22. cache pathCache
  23. }
  24. func (ic *imageContexts) newImageMount(id string) *imageMount {
  25. return &imageMount{ic: ic, id: id}
  26. }
  27. func (ic *imageContexts) add(name string) (*imageMount, error) {
  28. im := &imageMount{ic: ic}
  29. if len(name) > 0 {
  30. if ic.byName == nil {
  31. ic.byName = make(map[string]*imageMount)
  32. }
  33. if _, ok := ic.byName[name]; ok {
  34. return nil, errors.Errorf("duplicate name %s", name)
  35. }
  36. ic.byName[name] = im
  37. }
  38. ic.list = append(ic.list, im)
  39. return im, nil
  40. }
  41. func (ic *imageContexts) update(imageID string, runConfig *container.Config) {
  42. ic.list[len(ic.list)-1].id = imageID
  43. ic.list[len(ic.list)-1].runConfig = runConfig
  44. }
  45. func (ic *imageContexts) validate(i int) error {
  46. if i < 0 || i >= len(ic.list)-1 {
  47. var extraMsg string
  48. if i == len(ic.list)-1 {
  49. extraMsg = " refers current build block"
  50. }
  51. return errors.Errorf("invalid from flag value %d%s", i, extraMsg)
  52. }
  53. return nil
  54. }
  55. func (ic *imageContexts) get(indexOrName string) (*imageMount, error) {
  56. index, err := strconv.Atoi(indexOrName)
  57. if err == nil {
  58. if err := ic.validate(index); err != nil {
  59. return nil, err
  60. }
  61. return ic.list[index], nil
  62. }
  63. if im, ok := ic.byName[strings.ToLower(indexOrName)]; ok {
  64. return im, nil
  65. }
  66. im, err := mountByRef(ic.b, indexOrName)
  67. if err != nil {
  68. return nil, errors.Wrapf(err, "invalid from flag value %s", indexOrName)
  69. }
  70. ic.implicitMounts = append(ic.implicitMounts, im)
  71. return im, nil
  72. }
  73. func (ic *imageContexts) unmount() (retErr error) {
  74. for _, iml := range append([][]*imageMount{}, ic.list, ic.implicitMounts) {
  75. for _, im := range iml {
  76. if err := im.unmount(); err != nil {
  77. logrus.Error(err)
  78. retErr = err
  79. }
  80. }
  81. }
  82. for _, im := range ic.byName {
  83. if err := im.unmount(); err != nil {
  84. logrus.Error(err)
  85. retErr = err
  86. }
  87. }
  88. return
  89. }
  90. func (ic *imageContexts) getCache(id, path string) (interface{}, bool) {
  91. if ic.cache != nil {
  92. if id == "" {
  93. return nil, false
  94. }
  95. return ic.cache.Load(id + path)
  96. }
  97. return nil, false
  98. }
  99. func (ic *imageContexts) setCache(id, path string, v interface{}) {
  100. if ic.cache != nil {
  101. ic.cache.Store(id+path, v)
  102. }
  103. }
  104. // imageMount is a reference for getting access to a buildcontext that is backed
  105. // by an existing image
  106. type imageMount struct {
  107. id string
  108. source builder.Source
  109. release func() error
  110. ic *imageContexts
  111. runConfig *container.Config
  112. }
  113. func (im *imageMount) context() (builder.Source, error) {
  114. if im.source == nil {
  115. if im.id == "" {
  116. return nil, errors.Errorf("could not copy from empty context")
  117. }
  118. p, release, err := im.ic.b.docker.MountImage(im.id)
  119. if err != nil {
  120. return nil, errors.Wrapf(err, "failed to mount %s", im.id)
  121. }
  122. source, err := remotecontext.NewLazyContext(p)
  123. if err != nil {
  124. return nil, errors.Wrapf(err, "failed to create lazycontext for %s", p)
  125. }
  126. im.release = release
  127. im.source = source
  128. }
  129. return im.source, nil
  130. }
  131. func (im *imageMount) unmount() error {
  132. if im.release != nil {
  133. if err := im.release(); err != nil {
  134. return errors.Wrapf(err, "failed to unmount previous build image %s", im.id)
  135. }
  136. im.release = nil
  137. }
  138. return nil
  139. }
  140. func (im *imageMount) ImageID() string {
  141. return im.id
  142. }
  143. func (im *imageMount) RunConfig() *container.Config {
  144. return im.runConfig
  145. }