c8d: implement classic builder
<!--
Please make sure you've read and understood our contributing guidelines;
https://github.com/moby/moby/blob/master/CONTRIBUTING.md

** Make sure all your commits include a signature generated with `git commit -s` **

For additional information on our contributing process, read our contributing
guide https://docs.docker.com/opensource/code/

If this is a bug fix, make sure your description includes "fixes #xxxx", or
"closes #xxxx"

Please provide the following information:
-->

**- What I did**

Made the classic builder work with the containerd store

**- How I did it**

**- How to verify it**

**- Description for the changelog**
<!--
Write a short (one line) summary that describes the changes in this
pull request for inclusion in the changelog:
-->


**- A picture of a cute animal (not mandatory but encouraged)**

![image](https://user-images.githubusercontent.com/70572044/231761621-49d0b710-3401-4406-b8bb-8a87a4b870b6.png)

daemon/containerd/cache.go
package containerd

import (
	"context"

	"github.com/docker/docker/builder"
)

// MakeImageCache creates a stateful image cache.
func (i *ImageService) MakeImageCache(ctx context.Context, cacheFrom []string) (builder.ImageCache, error) {
	panic("not implemented")
}

package containerd

import (
	"context"
	"reflect"
	"strings"

	"github.com/docker/docker/api/types/container"
	imagetype "github.com/docker/docker/api/types/image"
	"github.com/docker/docker/builder"
	"github.com/docker/docker/image"
)

// MakeImageCache creates a stateful image cache.
func (i *ImageService) MakeImageCache(ctx context.Context, cacheFrom []string) (builder.ImageCache, error) {
	images := []*image.Image{}
	for _, c := range cacheFrom {
		im, err := i.GetImage(ctx, c, imagetype.GetImageOpts{})
		if err != nil {
			return nil, err
		}
		images = append(images, im)
	}
	return &imageCache{images: images, c: i}, nil
}

type imageCache struct {
	images []*image.Image
	c      *ImageService
}

func (ic *imageCache) GetCache(parentID string, cfg *container.Config) (imageID string, err error) {
	ctx := context.TODO()
	parent, err := ic.c.GetImage(ctx, parentID, imagetype.GetImageOpts{})
	if err != nil {
		return "", err
	}

	for _, localCachedImage := range ic.images {
		if isMatch(localCachedImage, parent, cfg) {
			return localCachedImage.ID().String(), nil
		}
	}

	children, err := ic.c.Children(ctx, parent.ID())
	if err != nil {
		return "", err
	}

	for _, children := range children {
		childImage, err := ic.c.GetImage(ctx, children.String(), imagetype.GetImageOpts{})
		if err != nil {
			return "", err
		}

		if isMatch(childImage, parent, cfg) {
			return children.String(), nil
		}
	}

	return "", nil
}

// isMatch checks whether a given target can be used as cache for the given
// parent image/config combination.
// A target can only be an immediate child of the given parent image. For
// a parent image with `n` history entries, a valid target must have `n+1`
// entries and the extra entry must match the provided config
func isMatch(target, parent *image.Image, cfg *container.Config) bool {
	if target == nil || parent == nil || cfg == nil {
		return false
	}

	if len(target.History) != len(parent.History)+1 ||
		len(target.RootFS.DiffIDs) != len(parent.RootFS.DiffIDs)+1 {
		return false
	}

	for i := range parent.History {
		if !reflect.DeepEqual(parent.History[i], target.History[i]) {
			return false
		}
	}

	childCreatedBy := target.History[len(target.History)-1].CreatedBy
	return childCreatedBy == strings.Join(cfg.Cmd, " ")
}

b is a pointer, which means that we're overwriting object passed to the `GetCache`.
We should make a copy of `cfg` in `GetCache` and pass it instead.