imagecontext.go 3.6 KB

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