mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-05-18 00:47:48 +08:00
commands: add platforms dedupe
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
parent
e773d0eb2a
commit
e40318e2cc
@ -59,7 +59,7 @@ type Inputs struct {
|
|||||||
type DriverInfo struct {
|
type DriverInfo struct {
|
||||||
Driver driver.Driver
|
Driver driver.Driver
|
||||||
Name string
|
Name string
|
||||||
Platform []string // TODO: specs.Platform
|
Platform []specs.Platform
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,10 +11,12 @@ import (
|
|||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/moby/buildkit/util/appcontext"
|
"github.com/moby/buildkit/util/appcontext"
|
||||||
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/tonistiigi/buildx/build"
|
"github.com/tonistiigi/buildx/build"
|
||||||
"github.com/tonistiigi/buildx/driver"
|
"github.com/tonistiigi/buildx/driver"
|
||||||
"github.com/tonistiigi/buildx/store"
|
"github.com/tonistiigi/buildx/store"
|
||||||
|
"github.com/tonistiigi/buildx/util/platformutil"
|
||||||
"github.com/tonistiigi/buildx/util/progress"
|
"github.com/tonistiigi/buildx/util/progress"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
@ -26,7 +28,7 @@ type inspectOptions struct {
|
|||||||
type dinfo struct {
|
type dinfo struct {
|
||||||
di *build.DriverInfo
|
di *build.DriverInfo
|
||||||
info *driver.Info
|
info *driver.Info
|
||||||
platforms []string
|
platforms []specs.Platform
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +114,7 @@ func runInspect(dockerCli command.Cli, in inspectOptions, args []string) error {
|
|||||||
fmt.Fprintf(w, "Error:\t%s\n", err.Error())
|
fmt.Fprintf(w, "Error:\t%s\n", err.Error())
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(w, "Status:\t%s\n", ngi.drivers[i].info.Status)
|
fmt.Fprintf(w, "Status:\t%s\n", ngi.drivers[i].info.Status)
|
||||||
fmt.Fprintf(w, "Platforms:\t%s\n", strings.Join(append(n.Platforms, ngi.drivers[i].platforms...), ", "))
|
fmt.Fprintf(w, "Platforms:\t%s\n", strings.Join(platformutil.Format(platformutil.Dedupe(append(n.Platforms, ngi.drivers[i].platforms...))), ", "))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/moby/buildkit/util/appcontext"
|
"github.com/moby/buildkit/util/appcontext"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/tonistiigi/buildx/store"
|
"github.com/tonistiigi/buildx/store"
|
||||||
|
"github.com/tonistiigi/buildx/util/platformutil"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -129,7 +130,7 @@ func printngi(w io.Writer, ngi *nginfo) {
|
|||||||
if err != "" {
|
if err != "" {
|
||||||
fmt.Fprintf(w, " %s\t%s\t%s\n", n.Name, n.Endpoint, err)
|
fmt.Fprintf(w, " %s\t%s\t%s\n", n.Name, n.Endpoint, err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(w, " %s\t%s\t%s\t%s\n", n.Name, n.Endpoint, status, strings.Join(p, ", "))
|
fmt.Fprintf(w, " %s\t%s\t%s\t%s\n", n.Name, n.Endpoint, status, strings.Join(platformutil.Format(p), ", "))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/containerd/containerd/platforms"
|
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/context/docker"
|
"github.com/docker/cli/cli/context/docker"
|
||||||
dopts "github.com/docker/cli/opts"
|
dopts "github.com/docker/cli/opts"
|
||||||
@ -14,6 +13,7 @@ import (
|
|||||||
"github.com/tonistiigi/buildx/build"
|
"github.com/tonistiigi/buildx/build"
|
||||||
"github.com/tonistiigi/buildx/driver"
|
"github.com/tonistiigi/buildx/driver"
|
||||||
"github.com/tonistiigi/buildx/store"
|
"github.com/tonistiigi/buildx/store"
|
||||||
|
"github.com/tonistiigi/buildx/util/platformutil"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -269,9 +269,10 @@ func loadInfoData(ctx context.Context, d *dinfo) error {
|
|||||||
}
|
}
|
||||||
for _, w := range workers {
|
for _, w := range workers {
|
||||||
for _, p := range w.Platforms {
|
for _, p := range w.Platforms {
|
||||||
d.platforms = append(d.platforms, platforms.Format(p))
|
d.platforms = append(d.platforms, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
d.platforms = platformutil.Dedupe(d.platforms)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,10 @@ package store
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/platforms"
|
||||||
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/tonistiigi/buildx/util/platformutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NodeGroup struct {
|
type NodeGroup struct {
|
||||||
@ -15,7 +18,7 @@ type NodeGroup struct {
|
|||||||
type Node struct {
|
type Node struct {
|
||||||
Name string
|
Name string
|
||||||
Endpoint string
|
Endpoint string
|
||||||
Platforms []string
|
Platforms []specs.Platform
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ng *NodeGroup) Leave(name string) error {
|
func (ng *NodeGroup) Leave(name string) error {
|
||||||
@ -38,16 +41,22 @@ func (ng *NodeGroup) Update(name, endpoint string, platforms []string, endpoints
|
|||||||
}
|
}
|
||||||
ng.Nodes = nil
|
ng.Nodes = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pp, err := platformutil.Parse(platforms)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if i != -1 {
|
if i != -1 {
|
||||||
n := ng.Nodes[i]
|
n := ng.Nodes[i]
|
||||||
if endpointsSet {
|
if endpointsSet {
|
||||||
n.Endpoint = endpoint
|
n.Endpoint = endpoint
|
||||||
}
|
}
|
||||||
if len(platforms) > 0 {
|
if len(platforms) > 0 {
|
||||||
n.Platforms = platforms
|
n.Platforms = pp
|
||||||
}
|
}
|
||||||
ng.Nodes[i] = n
|
ng.Nodes[i] = n
|
||||||
if err := ng.validateDuplicates(endpoint); err != nil {
|
if err := ng.validateDuplicates(endpoint, i); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -57,7 +66,7 @@ func (ng *NodeGroup) Update(name, endpoint string, platforms []string, endpoints
|
|||||||
name = ng.nextNodeName()
|
name = ng.nextNodeName()
|
||||||
}
|
}
|
||||||
|
|
||||||
name, err := ValidateName(name)
|
name, err = ValidateName(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -65,18 +74,17 @@ func (ng *NodeGroup) Update(name, endpoint string, platforms []string, endpoints
|
|||||||
n := Node{
|
n := Node{
|
||||||
Name: name,
|
Name: name,
|
||||||
Endpoint: endpoint,
|
Endpoint: endpoint,
|
||||||
Platforms: platforms,
|
Platforms: pp,
|
||||||
}
|
}
|
||||||
ng.Nodes = append(ng.Nodes, n)
|
ng.Nodes = append(ng.Nodes, n)
|
||||||
|
|
||||||
if err := ng.validateDuplicates(endpoint); err != nil {
|
if err := ng.validateDuplicates(endpoint, len(ng.Nodes)-1); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ng *NodeGroup) validateDuplicates(ep string) error {
|
func (ng *NodeGroup) validateDuplicates(ep string, idx int) error {
|
||||||
// TODO: reset platforms
|
|
||||||
i := 0
|
i := 0
|
||||||
for _, n := range ng.Nodes {
|
for _, n := range ng.Nodes {
|
||||||
if n.Endpoint == ep {
|
if n.Endpoint == ep {
|
||||||
@ -86,6 +94,19 @@ func (ng *NodeGroup) validateDuplicates(ep string) error {
|
|||||||
if i > 1 {
|
if i > 1 {
|
||||||
return errors.Errorf("invalid duplicate endpoint %s", ep)
|
return errors.Errorf("invalid duplicate endpoint %s", ep)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m := map[string]struct{}{}
|
||||||
|
for _, p := range ng.Nodes[idx].Platforms {
|
||||||
|
m[platforms.Format(p)] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range ng.Nodes {
|
||||||
|
if i == idx {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ng.Nodes[i].Platforms = filterPlatforms(ng.Nodes[i].Platforms, m)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,3 +130,13 @@ func (ng *NodeGroup) nextNodeName() string {
|
|||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func filterPlatforms(in []specs.Platform, m map[string]struct{}) []specs.Platform {
|
||||||
|
out := make([]specs.Platform, 0, len(in))
|
||||||
|
for _, p := range in {
|
||||||
|
if _, ok := m[platforms.Format(p)]; !ok {
|
||||||
|
out = append(out, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
42
store/nodegroup_test.go
Normal file
42
store/nodegroup_test.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/tonistiigi/buildx/util/platformutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNodeGroupUpdate(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
ng := &NodeGroup{}
|
||||||
|
err := ng.Update("foo", "foo0", []string{"linux/amd64"}, true, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = ng.Update("foo1", "foo1", []string{"linux/arm64", "linux/arm/v7"}, true, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, len(ng.Nodes), 2)
|
||||||
|
|
||||||
|
// update
|
||||||
|
err = ng.Update("foo", "foo2", []string{"linux/amd64", "linux/arm"}, true, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, len(ng.Nodes), 2)
|
||||||
|
require.Equal(t, []string{"linux/amd64", "linux/arm/v7"}, platformutil.Format(ng.Nodes[0].Platforms))
|
||||||
|
require.Equal(t, []string{"linux/arm64"}, platformutil.Format(ng.Nodes[1].Platforms))
|
||||||
|
|
||||||
|
require.Equal(t, "foo2", ng.Nodes[0].Endpoint)
|
||||||
|
|
||||||
|
// duplicate endpoint
|
||||||
|
err = ng.Update("foo1", "foo2", nil, true, false)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Contains(t, err.Error(), "duplicate endpoint")
|
||||||
|
|
||||||
|
err = ng.Leave("foo")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, len(ng.Nodes), 1)
|
||||||
|
require.Equal(t, []string{"linux/arm64"}, platformutil.Format(ng.Nodes[0].Platforms))
|
||||||
|
}
|
@ -30,3 +30,29 @@ func Parse(platformsStr []string) ([]specs.Platform, error) {
|
|||||||
}
|
}
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Dedupe(in []specs.Platform) []specs.Platform {
|
||||||
|
m := map[string]struct{}{}
|
||||||
|
out := make([]specs.Platform, 0, len(in))
|
||||||
|
for _, p := range in {
|
||||||
|
p := platforms.Normalize(p)
|
||||||
|
key := platforms.Format(p)
|
||||||
|
if _, ok := m[key]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m[key] = struct{}{}
|
||||||
|
out = append(out, p)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func Format(in []specs.Platform) []string {
|
||||||
|
if len(in) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := make([]string, 0, len(in))
|
||||||
|
for _, p := range in {
|
||||||
|
out = append(out, platforms.Format(p))
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user