mirror of
https://github.com/moby/buildkit.git
synced 2026-11-06 05:16:45 +00:00
control: handle duplicate inline cache exporter
Inline cache exporter can be set with multiple ways, doesn't have any attributes and can always only run one time. Instead of allowing multiple inline exporters where one gets ignored later when there is an attribute difference, or erroring when attributes are unset, just ignore the extra ones. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
2 files changed
+73
-7
No files matched your search
+17
-6
@@ -425,15 +425,17 @@ func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (*
|
||||
expis = append(expis, expi)
|
||||
}
|
||||
|
||||
if c, err := findDuplicateCacheOptions(req.Cache.Exports); err != nil {
|
||||
rest, dupes, err := findDuplicateCacheOptions(req.Cache.Exports)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if c != nil {
|
||||
} else if len(dupes) > 0 {
|
||||
types := []string{}
|
||||
for _, c := range c {
|
||||
for _, c := range dupes {
|
||||
types = append(types, c.Type)
|
||||
}
|
||||
return nil, errors.Errorf("duplicate cache exports %s", types)
|
||||
}
|
||||
req.Cache.Exports = rest
|
||||
var cacheExporters []llbsolver.RemoteCacheExporter
|
||||
for _, e := range req.Cache.Exports {
|
||||
cacheExporterFunc, ok := c.opt.ResolveCacheExporterFuncs[e.Type]
|
||||
@@ -727,25 +729,34 @@ func toPBCDIDevices(manager *cdidevices.Manager) []*apitypes.CDIDevice {
|
||||
return out
|
||||
}
|
||||
|
||||
func findDuplicateCacheOptions(cacheOpts []*controlapi.CacheOptionsEntry) ([]*controlapi.CacheOptionsEntry, error) {
|
||||
func findDuplicateCacheOptions(cacheOpts []*controlapi.CacheOptionsEntry) ([]*controlapi.CacheOptionsEntry, []*controlapi.CacheOptionsEntry, error) {
|
||||
seen := map[string]*controlapi.CacheOptionsEntry{}
|
||||
duplicate := map[string]struct{}{}
|
||||
hasInline := false
|
||||
rest := make([]*controlapi.CacheOptionsEntry, 0, len(cacheOpts))
|
||||
for _, opt := range cacheOpts {
|
||||
if opt.Type == "inline" && hasInline {
|
||||
continue
|
||||
}
|
||||
k, err := cacheOptKey(opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
if _, ok := seen[k]; ok {
|
||||
duplicate[k] = struct{}{}
|
||||
}
|
||||
seen[k] = opt
|
||||
if opt.Type == "inline" {
|
||||
hasInline = true
|
||||
}
|
||||
rest = append(rest, opt)
|
||||
}
|
||||
|
||||
var duplicates []*controlapi.CacheOptionsEntry
|
||||
for k := range duplicate {
|
||||
duplicates = append(duplicates, seen[k])
|
||||
}
|
||||
return duplicates, nil
|
||||
return rest, duplicates, nil
|
||||
}
|
||||
|
||||
func cacheOptKey(opt *controlapi.CacheOptionsEntry) (string, error) {
|
||||
|
||||
+56
-1
@@ -12,6 +12,7 @@ func TestDuplicateCacheOptions(t *testing.T) {
|
||||
name string
|
||||
opts []*controlapi.CacheOptionsEntry
|
||||
expected []*controlapi.CacheOptionsEntry
|
||||
rest []*controlapi.CacheOptionsEntry
|
||||
}{
|
||||
{
|
||||
name: "avoids unique opts",
|
||||
@@ -74,13 +75,67 @@ func TestDuplicateCacheOptions(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "skip inline with attrs",
|
||||
opts: []*controlapi.CacheOptionsEntry{
|
||||
{
|
||||
Type: "inline",
|
||||
},
|
||||
{
|
||||
Type: "registry",
|
||||
Attrs: map[string]string{
|
||||
"ref": "example.com/ref:v1.0.0",
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "inline",
|
||||
Attrs: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
rest: []*controlapi.CacheOptionsEntry{
|
||||
{
|
||||
Type: "inline",
|
||||
},
|
||||
{
|
||||
Type: "registry",
|
||||
Attrs: map[string]string{
|
||||
"ref": "example.com/ref:v1.0.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "skip inline simple",
|
||||
opts: []*controlapi.CacheOptionsEntry{
|
||||
{
|
||||
Type: "inline",
|
||||
},
|
||||
{
|
||||
Type: "inline",
|
||||
},
|
||||
},
|
||||
rest: []*controlapi.CacheOptionsEntry{
|
||||
{
|
||||
Type: "inline",
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
result, err := findDuplicateCacheOptions(tc.opts)
|
||||
rest, result, err := findDuplicateCacheOptions(tc.opts)
|
||||
require.NoError(t, err)
|
||||
require.ElementsMatch(t, tc.expected, result)
|
||||
if tc.rest != nil {
|
||||
require.ElementsMatch(t, tc.rest, rest)
|
||||
} else if len(result) == 0 {
|
||||
require.ElementsMatch(t, tc.opts, rest)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user