github.com/gdevillele/moby@v1.13.0/daemon/image_history.go (about) 1 package daemon 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/docker/docker/api/types" 8 "github.com/docker/docker/layer" 9 "github.com/docker/docker/reference" 10 ) 11 12 // ImageHistory returns a slice of ImageHistory structures for the specified image 13 // name by walking the image lineage. 14 func (daemon *Daemon) ImageHistory(name string) ([]*types.ImageHistory, error) { 15 start := time.Now() 16 img, err := daemon.GetImage(name) 17 if err != nil { 18 return nil, err 19 } 20 21 history := []*types.ImageHistory{} 22 23 layerCounter := 0 24 rootFS := *img.RootFS 25 rootFS.DiffIDs = nil 26 27 for _, h := range img.History { 28 var layerSize int64 29 30 if !h.EmptyLayer { 31 if len(img.RootFS.DiffIDs) <= layerCounter { 32 return nil, fmt.Errorf("too many non-empty layers in History section") 33 } 34 35 rootFS.Append(img.RootFS.DiffIDs[layerCounter]) 36 l, err := daemon.layerStore.Get(rootFS.ChainID()) 37 if err != nil { 38 return nil, err 39 } 40 layerSize, err = l.DiffSize() 41 layer.ReleaseAndLog(daemon.layerStore, l) 42 if err != nil { 43 return nil, err 44 } 45 46 layerCounter++ 47 } 48 49 history = append([]*types.ImageHistory{{ 50 ID: "<missing>", 51 Created: h.Created.Unix(), 52 CreatedBy: h.CreatedBy, 53 Comment: h.Comment, 54 Size: layerSize, 55 }}, history...) 56 } 57 58 // Fill in image IDs and tags 59 histImg := img 60 id := img.ID() 61 for _, h := range history { 62 h.ID = id.String() 63 64 var tags []string 65 for _, r := range daemon.referenceStore.References(id.Digest()) { 66 if _, ok := r.(reference.NamedTagged); ok { 67 tags = append(tags, r.String()) 68 } 69 } 70 71 h.Tags = tags 72 73 id = histImg.Parent 74 if id == "" { 75 break 76 } 77 histImg, err = daemon.GetImage(id.String()) 78 if err != nil { 79 break 80 } 81 } 82 imageActions.WithValues("history").UpdateSince(start) 83 return history, nil 84 }