| package imagerefchecker |
| |
| import ( |
| "sync" |
| |
| "github.com/docker/docker/image" |
| "github.com/docker/docker/layer" |
| "github.com/moby/buildkit/cache" |
| ) |
| |
| // LayerGetter abstracts away the snapshotter |
| type LayerGetter interface { |
| GetLayer(string) (layer.Layer, error) |
| } |
| |
| // Opt represents the options needed to create a refchecker |
| type Opt struct { |
| LayerGetter LayerGetter |
| ImageStore image.Store |
| } |
| |
| // New creates new image reference checker that can be used to see if a reference |
| // is being used by any of the images in the image store |
| func New(opt Opt) cache.ExternalRefCheckerFunc { |
| return func() (cache.ExternalRefChecker, error) { |
| return &checker{opt: opt, layers: lchain{}, cache: map[string]bool{}}, nil |
| } |
| } |
| |
| type lchain map[layer.DiffID]lchain |
| |
| func (c lchain) add(ids []layer.DiffID) { |
| if len(ids) == 0 { |
| return |
| } |
| id := ids[0] |
| ch, ok := c[id] |
| if !ok { |
| ch = lchain{} |
| c[id] = ch |
| } |
| ch.add(ids[1:]) |
| } |
| |
| func (c lchain) has(ids []layer.DiffID) bool { |
| if len(ids) == 0 { |
| return true |
| } |
| ch, ok := c[ids[0]] |
| return ok && ch.has(ids[1:]) |
| } |
| |
| type checker struct { |
| opt Opt |
| once sync.Once |
| layers lchain |
| cache map[string]bool |
| } |
| |
| func (c *checker) Exists(key string) bool { |
| if c.opt.ImageStore == nil { |
| return false |
| } |
| |
| c.once.Do(c.init) |
| |
| if b, ok := c.cache[key]; ok { |
| return b |
| } |
| |
| l, err := c.opt.LayerGetter.GetLayer(key) |
| if err != nil || l == nil { |
| c.cache[key] = false |
| return false |
| } |
| |
| ok := c.layers.has(diffIDs(l)) |
| c.cache[key] = ok |
| return ok |
| } |
| |
| func (c *checker) init() { |
| imgs := c.opt.ImageStore.Map() |
| |
| for _, img := range imgs { |
| c.layers.add(img.RootFS.DiffIDs) |
| } |
| } |
| |
| func diffIDs(l layer.Layer) []layer.DiffID { |
| p := l.Parent() |
| if p == nil { |
| return []layer.DiffID{l.DiffID()} |
| } |
| return append(diffIDs(p), l.DiffID()) |
| } |