From 088d5af87984e8e8348f3b70004d8107df645f73 Mon Sep 17 00:00:00 2001 From: umohnani8 Date: Thu, 21 Jun 2018 16:11:59 -0400 Subject: Podman history now prints out intermediate image IDs If the intermediate image exists in the store, podman history will show the IDs of the intermediate image of each layer. Signed-off-by: umohnani8 Closes: #982 Approved by: mheon --- libpod/image/image.go | 78 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 4 deletions(-) (limited to 'libpod/image/image.go') diff --git a/libpod/image/image.go b/libpod/image/image.go index c8a929074..57eabe2c8 100644 --- a/libpod/image/image.go +++ b/libpod/image/image.go @@ -608,17 +608,87 @@ func (i *Image) Layer() (*storage.Layer, error) { return i.imageruntime.store.Layer(i.image.TopLayer) } +// History contains the history information of an image +type History struct { + ID string `json:"id"` + Created *time.Time `json:"created"` + CreatedBy string `json:"createdBy"` + Size int64 `json:"size"` + Comment string `json:"comment"` +} + // History gets the history of an image and information about its layers -func (i *Image) History(ctx context.Context) ([]ociv1.History, []types.BlobInfo, error) { +func (i *Image) History(ctx context.Context) ([]*History, error) { img, err := i.toImageRef(ctx) if err != nil { - return nil, nil, err + return nil, err } oci, err := img.OCIConfig(ctx) if err != nil { - return nil, nil, err + return nil, err + } + + // Get the IDs of the images making up the history layers + // if the images exist locally in the store + images, err := i.imageruntime.GetImages() + if err != nil { + return nil, errors.Wrapf(err, "error getting images from store") + } + imageIDs := []string{i.ID()} + if err := i.historyLayerIDs(i.TopLayer(), images, &imageIDs); err != nil { + return nil, errors.Wrap(err, "error getting image IDs for layers in history") } - return oci.History, img.LayerInfos(), nil + + var ( + imageID string + imgIDCount = 0 + size int64 + sizeCount = 1 + allHistory []*History + ) + + for i := len(oci.History) - 1; i >= 0; i-- { + if imgIDCount < len(imageIDs) { + imageID = imageIDs[imgIDCount] + imgIDCount++ + } else { + imageID = "" + } + if !oci.History[i].EmptyLayer { + size = img.LayerInfos()[len(img.LayerInfos())-sizeCount].Size + sizeCount++ + } + allHistory = append(allHistory, &History{ + ID: imageID, + Created: oci.History[i].Created, + CreatedBy: oci.History[i].CreatedBy, + Size: size, + Comment: oci.History[i].Comment, + }) + } + + return allHistory, nil +} + +// historyLayerIDs goes through the images in store and checks if the top layer of an image +// is the same as the parent of topLayerID +func (i *Image) historyLayerIDs(topLayerID string, images []*Image, IDs *[]string) error { + for _, image := range images { + // Get the layer info of topLayerID + layer, err := i.imageruntime.store.Layer(topLayerID) + if err != nil { + return errors.Wrapf(err, "error getting layer info %q", topLayerID) + } + // Check if the parent of layer is equal to the image's top layer + // If so add the image ID to the list of IDs and find the parent of + // the top layer of the image ID added to the list + // Since we are checking for parent, each top layer can only have one parent + if layer.Parent == image.TopLayer() { + *IDs = append(*IDs, image.ID()) + return i.historyLayerIDs(image.TopLayer(), images, IDs) + } + } + return nil } // Dangling returns a bool if the image is "dangling" -- cgit v1.2.3-54-g00ecf