diff --git a/build/resolver/driver.go b/build/resolver/driver.go index 671b14c5bfe9..7044713b528e 100644 --- a/build/resolver/driver.go +++ b/build/resolver/driver.go @@ -10,6 +10,7 @@ import ( "github.com/containerd/platforms" "github.com/docker/buildx/builder" "github.com/docker/buildx/driver" + "github.com/docker/buildx/util/platformutil" "github.com/docker/buildx/util/progress" "github.com/moby/buildkit/client" gateway "github.com/moby/buildkit/frontend/gateway/client" @@ -147,17 +148,11 @@ func (r *nodeResolver) Resolve(ctx context.Context, optPlatforms map[string][]oc if err != nil { return errors.Wrap(err, "listing workers") } - - ps := make(map[string]ocispecs.Platform, len(ww)) + var ps []ocispecs.Platform for _, w := range ww { - for _, p := range w.Platforms { - pk := platforms.Format(platforms.Normalize(p)) - ps[pk] = p - } - } - for _, p := range ps { - workers[i] = append(workers[i], p) + ps = append(ps, w.Platforms...) } + workers[i] = platformutil.Dedupe(ps) return nil }) } diff --git a/store/nodegroup.go b/store/nodegroup.go index 8c78acc1c94c..d19a30161234 100644 --- a/store/nodegroup.go +++ b/store/nodegroup.go @@ -176,7 +176,7 @@ func (ng *NodeGroup) validateDuplicates(ep string, idx int) error { m := map[string]struct{}{} for _, p := range ng.Nodes[idx].Platforms { - m[platforms.Format(p)] = struct{}{} + m[platforms.FormatAll(platforms.Normalize(p))] = struct{}{} } for i := range ng.Nodes { @@ -213,7 +213,7 @@ func (ng *NodeGroup) nextNodeName() string { func filterPlatforms(in []ocispecs.Platform, m map[string]struct{}) []ocispecs.Platform { out := make([]ocispecs.Platform, 0, len(in)) for _, p := range in { - if _, ok := m[platforms.Format(p)]; !ok { + if _, ok := m[platforms.FormatAll(platforms.Normalize(p))]; !ok { out = append(out, p) } } diff --git a/store/nodegroup_test.go b/store/nodegroup_test.go index 5a55703bafa7..ece584c21e92 100644 --- a/store/nodegroup_test.go +++ b/store/nodegroup_test.go @@ -3,7 +3,9 @@ package store import ( "testing" + "github.com/containerd/platforms" "github.com/docker/buildx/util/platformutil" + ocispecs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/stretchr/testify/require" ) @@ -42,3 +44,25 @@ func TestNodeGroupUpdate(t *testing.T) { require.Equal(t, 1, len(ng.Nodes)) require.Equal(t, []string{"linux/arm64"}, platformutil.Format(ng.Nodes[0].Platforms)) } + +func TestNodeGroupUpdateFiltersOnlyMatchingPlatforms(t *testing.T) { + t.Parallel() + + ng := &NodeGroup{} + err := ng.Update("n1", "ctx-a", []string{"windows(10.0.17763)/amd64", "linux/amd64"}, true, false, nil, "", nil) + require.NoError(t, err) + + err = ng.Update("n2", "ctx-b", []string{"windows(10.0.20348)/amd64", "linux/x86_64"}, true, true, nil, "", nil) + require.NoError(t, err) + + require.Equal(t, []string{"windows(10.0.17763)/amd64"}, formatAll(ng.Nodes[0].Platforms)) + require.Equal(t, []string{"windows(10.0.20348)/amd64", "linux/amd64"}, formatAll(ng.Nodes[1].Platforms)) +} + +func formatAll(pp []ocispecs.Platform) []string { + out := make([]string, 0, len(pp)) + for _, p := range pp { + out = append(out, platforms.FormatAll(p)) + } + return out +} diff --git a/util/platformutil/parse.go b/util/platformutil/parse.go index b95855ffab6a..e8dfeee8cfbd 100644 --- a/util/platformutil/parse.go +++ b/util/platformutil/parse.go @@ -43,7 +43,7 @@ func Dedupe(in []ocispecs.Platform) []ocispecs.Platform { out := make([]ocispecs.Platform, 0, len(in)) for _, p := range in { p := platforms.Normalize(p) - key := platforms.Format(p) + key := platforms.FormatAll(p) if _, ok := m[key]; ok { continue } @@ -58,13 +58,11 @@ func FormatInGroups(gg ...[]ocispecs.Platform) []string { out := make([]string, 0, len(gg)) for i, g := range gg { for _, p := range g { - p := platforms.Normalize(p) - key := platforms.Format(p) - if _, ok := m[key]; ok { + v := platforms.FormatAll(platforms.Normalize(p)) + if _, ok := m[v]; ok { continue } - m[key] = struct{}{} - v := platforms.Format(p) + m[v] = struct{}{} if i == 0 { v += "*" } diff --git a/util/platformutil/parse_test.go b/util/platformutil/parse_test.go new file mode 100644 index 000000000000..1be4b6787c10 --- /dev/null +++ b/util/platformutil/parse_test.go @@ -0,0 +1,61 @@ +package platformutil + +import ( + "testing" + + "github.com/containerd/platforms" + ocispecs "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/stretchr/testify/require" +) + +func TestDedupePreservesOSVersionAndFeatures(t *testing.T) { + t.Parallel() + + got := Dedupe([]ocispecs.Platform{ + platforms.MustParse("windows(10.0.17763)/amd64"), + platforms.MustParse("windows(10.0.20348)/amd64"), + platforms.MustParse("windows(10.0.20348+win32k)/amd64"), + platforms.MustParse("windows(10.0.17763)/amd64"), + platforms.MustParse("linux/x86_64"), + platforms.MustParse("linux/amd64"), + }) + + require.Equal(t, []string{ + "windows(10.0.17763)/amd64", + "windows(10.0.20348)/amd64", + "windows(10.0.20348+win32k)/amd64", + "linux/amd64", + }, formatAll(got)) +} + +func TestFormatInGroupsPreservesOSVersionAndFeatures(t *testing.T) { + t.Parallel() + + got := FormatInGroups( + []ocispecs.Platform{ + platforms.MustParse("windows(10.0.17763)/amd64"), + platforms.MustParse("windows(10.0.20348)/amd64"), + }, + []ocispecs.Platform{ + platforms.MustParse("windows(10.0.20348)/amd64"), + platforms.MustParse("windows(10.0.20348+win32k)/amd64"), + platforms.MustParse("linux/x86_64"), + platforms.MustParse("linux/amd64"), + }, + ) + + require.Equal(t, []string{ + "windows(10.0.17763)/amd64*", + "windows(10.0.20348)/amd64*", + "windows(10.0.20348+win32k)/amd64", + "linux/amd64", + }, got) +} + +func formatAll(pp []ocispecs.Platform) []string { + out := make([]string, 0, len(pp)) + for _, p := range pp { + out = append(out, platforms.FormatAll(p)) + } + return out +}