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