github.com/rawahars/moby@v24.0.4+incompatible/daemon/containerd/image_history.go (about)

     1  package containerd
     2  
     3  import (
     4  	"context"
     5  	"sort"
     6  
     7  	cplatforms "github.com/containerd/containerd/platforms"
     8  	"github.com/docker/distribution/reference"
     9  	imagetype "github.com/docker/docker/api/types/image"
    10  	"github.com/docker/docker/errdefs"
    11  	"github.com/docker/docker/pkg/platforms"
    12  	"github.com/opencontainers/image-spec/identity"
    13  	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
    14  	"github.com/pkg/errors"
    15  )
    16  
    17  // ImageHistory returns a slice of HistoryResponseItem structures for the
    18  // specified image name by walking the image lineage.
    19  func (i *ImageService) ImageHistory(ctx context.Context, name string) ([]*imagetype.HistoryResponseItem, error) {
    20  	desc, err := i.resolveImage(ctx, name)
    21  	if err != nil {
    22  		return nil, err
    23  	}
    24  
    25  	cs := i.client.ContentStore()
    26  	// TODO: pass platform in from the CLI
    27  	platform := platforms.AllPlatformsWithPreference(cplatforms.Default())
    28  
    29  	var presentImages []ocispec.Image
    30  	err = i.walkImageManifests(ctx, desc, func(img *ImageManifest) error {
    31  		conf, err := img.Config(ctx)
    32  		if err != nil {
    33  			return err
    34  		}
    35  		var ociimage ocispec.Image
    36  		if err := readConfig(ctx, cs, conf, &ociimage); err != nil {
    37  			return err
    38  		}
    39  		presentImages = append(presentImages, ociimage)
    40  		return nil
    41  	})
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  	if len(presentImages) == 0 {
    46  		return nil, errdefs.NotFound(errors.New("failed to find image manifest"))
    47  	}
    48  
    49  	sort.SliceStable(presentImages, func(i, j int) bool {
    50  		return platform.Less(presentImages[i].Platform, presentImages[j].Platform)
    51  	})
    52  	ociimage := presentImages[0]
    53  
    54  	var (
    55  		history []*imagetype.HistoryResponseItem
    56  		sizes   []int64
    57  	)
    58  	s := i.client.SnapshotService(i.snapshotter)
    59  
    60  	diffIDs := ociimage.RootFS.DiffIDs
    61  	for i := range diffIDs {
    62  		chainID := identity.ChainID(diffIDs[0 : i+1]).String()
    63  
    64  		use, err := s.Usage(ctx, chainID)
    65  		if err != nil {
    66  			return nil, err
    67  		}
    68  
    69  		sizes = append(sizes, use.Size)
    70  	}
    71  
    72  	for _, h := range ociimage.History {
    73  		size := int64(0)
    74  		if !h.EmptyLayer {
    75  			if len(sizes) == 0 {
    76  				return nil, errors.New("unable to find the size of the layer")
    77  			}
    78  			size = sizes[0]
    79  			sizes = sizes[1:]
    80  		}
    81  
    82  		history = append([]*imagetype.HistoryResponseItem{{
    83  			ID:        "<missing>",
    84  			Comment:   h.Comment,
    85  			CreatedBy: h.CreatedBy,
    86  			Created:   h.Created.Unix(),
    87  			Size:      size,
    88  			Tags:      nil,
    89  		}}, history...)
    90  	}
    91  
    92  	if len(history) != 0 {
    93  		history[0].ID = desc.Target.Digest.String()
    94  
    95  		tagged, err := i.client.ImageService().List(ctx, "target.digest=="+desc.Target.Digest.String())
    96  		if err != nil {
    97  			return nil, err
    98  		}
    99  
   100  		var tags []string
   101  		for _, t := range tagged {
   102  			if isDanglingImage(t) {
   103  				continue
   104  			}
   105  			name, err := reference.ParseNamed(t.Name)
   106  			if err != nil {
   107  				return nil, err
   108  			}
   109  			tags = append(tags, reference.FamiliarString(name))
   110  		}
   111  		history[0].Tags = tags
   112  	}
   113  
   114  	return history, nil
   115  }