github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/daemon/images/image_squash.go (about) 1 package images // import "github.com/docker/docker/daemon/images" 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "time" 7 8 "github.com/docker/docker/image" 9 "github.com/docker/docker/layer" 10 "github.com/pkg/errors" 11 ) 12 13 // SquashImage creates a new image with the diff of the specified image and the specified parent. 14 // This new image contains only the layers from it's parent + 1 extra layer which contains the diff of all the layers in between. 15 // The existing image(s) is not destroyed. 16 // If no parent is specified, a new image with the diff of all the specified image's layers merged into a new layer that has no parents. 17 func (i *ImageService) SquashImage(id, parent string) (string, error) { 18 var ( 19 img *image.Image 20 err error 21 ) 22 if img, err = i.imageStore.Get(image.ID(id)); err != nil { 23 return "", err 24 } 25 26 var parentImg *image.Image 27 var parentChainID layer.ChainID 28 if len(parent) != 0 { 29 parentImg, err = i.imageStore.Get(image.ID(parent)) 30 if err != nil { 31 return "", errors.Wrap(err, "error getting specified parent layer") 32 } 33 parentChainID = parentImg.RootFS.ChainID() 34 } else { 35 rootFS := image.NewRootFS() 36 parentImg = &image.Image{RootFS: rootFS} 37 } 38 l, err := i.layerStore.Get(img.RootFS.ChainID()) 39 if err != nil { 40 return "", errors.Wrap(err, "error getting image layer") 41 } 42 defer i.layerStore.Release(l) 43 44 ts, err := l.TarStreamFrom(parentChainID) 45 if err != nil { 46 return "", errors.Wrapf(err, "error getting tar stream to parent") 47 } 48 defer ts.Close() 49 50 newL, err := i.layerStore.Register(ts, parentChainID) 51 if err != nil { 52 return "", errors.Wrap(err, "error registering layer") 53 } 54 defer i.layerStore.Release(newL) 55 56 newImage := *img 57 newImage.RootFS = nil 58 59 rootFS := *parentImg.RootFS 60 rootFS.DiffIDs = append(rootFS.DiffIDs, newL.DiffID()) 61 newImage.RootFS = &rootFS 62 63 for i, hi := range newImage.History { 64 if i >= len(parentImg.History) { 65 hi.EmptyLayer = true 66 } 67 newImage.History[i] = hi 68 } 69 70 now := time.Now() 71 var historyComment string 72 if len(parent) > 0 { 73 historyComment = fmt.Sprintf("merge %s to %s", id, parent) 74 } else { 75 historyComment = fmt.Sprintf("create new from %s", id) 76 } 77 78 newImage.History = append(newImage.History, image.History{ 79 Created: now, 80 Comment: historyComment, 81 }) 82 newImage.Created = now 83 84 b, err := json.Marshal(&newImage) 85 if err != nil { 86 return "", errors.Wrap(err, "error marshalling image config") 87 } 88 89 newImgID, err := i.imageStore.Create(b) 90 if err != nil { 91 return "", errors.Wrap(err, "error creating new image after squash") 92 } 93 return string(newImgID), nil 94 }