2018-04-13 21:08:43 +00:00
|
|
|
package cacheimport
|
|
|
|
|
|
|
|
import (
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/containerd/containerd/content"
|
2018-05-11 05:58:41 +00:00
|
|
|
"github.com/moby/buildkit/solver"
|
2018-04-13 21:08:43 +00:00
|
|
|
digest "github.com/opencontainers/go-digest"
|
|
|
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
|
|
)
|
|
|
|
|
|
|
|
func NewCacheChains() *CacheChains {
|
|
|
|
return &CacheChains{visited: map[interface{}]struct{}{}}
|
|
|
|
}
|
|
|
|
|
|
|
|
type CacheChains struct {
|
|
|
|
items []*item
|
|
|
|
visited map[interface{}]struct{}
|
|
|
|
}
|
|
|
|
|
2018-05-08 21:15:46 +00:00
|
|
|
func (c *CacheChains) Add(dgst digest.Digest) solver.CacheExporterRecord {
|
2018-04-13 21:08:43 +00:00
|
|
|
it := &item{c: c, dgst: dgst}
|
|
|
|
c.items = append(c.items, it)
|
|
|
|
return it
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *CacheChains) Visit(v interface{}) {
|
|
|
|
c.visited[v] = struct{}{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *CacheChains) Visited(v interface{}) bool {
|
|
|
|
_, ok := c.visited[v]
|
|
|
|
return ok
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *CacheChains) normalize() error {
|
|
|
|
st := &normalizeState{
|
|
|
|
added: map[*item]*item{},
|
|
|
|
links: map[*item]map[nlink]map[digest.Digest]struct{}{},
|
|
|
|
byKey: map[digest.Digest]*item{},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, it := range c.items {
|
|
|
|
_, err := normalizeItem(it, st)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
items := make([]*item, 0, len(st.byKey))
|
|
|
|
for _, it := range st.byKey {
|
|
|
|
items = append(items, it)
|
|
|
|
}
|
|
|
|
c.items = items
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *CacheChains) Marshal() (*CacheConfig, DescriptorProvider, error) {
|
|
|
|
if err := c.normalize(); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
st := &marshalState{
|
|
|
|
chainsByID: map[string]int{},
|
|
|
|
descriptors: DescriptorProvider{},
|
|
|
|
recordsByItem: map[*item]int{},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, it := range c.items {
|
|
|
|
if err := marshalItem(it, st); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cc := CacheConfig{
|
|
|
|
Layers: st.layers,
|
|
|
|
Records: st.records,
|
|
|
|
}
|
|
|
|
sortConfig(&cc)
|
|
|
|
|
|
|
|
return &cc, st.descriptors, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type DescriptorProvider map[digest.Digest]DescriptorProviderPair
|
|
|
|
|
|
|
|
type DescriptorProviderPair struct {
|
|
|
|
Descriptor ocispec.Descriptor
|
|
|
|
Provider content.Provider
|
|
|
|
}
|
|
|
|
|
|
|
|
type item struct {
|
|
|
|
c *CacheChains
|
|
|
|
dgst digest.Digest
|
|
|
|
|
|
|
|
result *solver.Remote
|
|
|
|
resultTime time.Time
|
|
|
|
|
|
|
|
links []map[link]struct{}
|
|
|
|
}
|
|
|
|
|
|
|
|
type link struct {
|
|
|
|
src *item
|
|
|
|
selector string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *item) AddResult(createdAt time.Time, result *solver.Remote) {
|
|
|
|
c.resultTime = createdAt
|
|
|
|
c.result = result
|
|
|
|
}
|
|
|
|
|
2018-05-08 21:15:46 +00:00
|
|
|
func (c *item) LinkFrom(rec solver.CacheExporterRecord, index int, selector string) {
|
2018-04-13 21:08:43 +00:00
|
|
|
src, ok := rec.(*item)
|
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
if index < len(c.links) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
c.links = append(c.links, map[link]struct{}{})
|
|
|
|
}
|
|
|
|
|
|
|
|
c.links[index][link{src: src, selector: selector}] = struct{}{}
|
|
|
|
}
|
|
|
|
|
2018-05-08 21:15:46 +00:00
|
|
|
var _ solver.CacheExporterTarget = &CacheChains{}
|