Skip to content

Commit

Permalink
ls: no-trunc opt
Browse files Browse the repository at this point in the history
Signed-off-by: CrazyMax <[email protected]>
  • Loading branch information
crazy-max committed Nov 30, 2023
1 parent d826375 commit cda6a69
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 11 deletions.
80 changes: 72 additions & 8 deletions commands/ls.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ const (
)

type lsOptions struct {
format string
format string
noTrunc bool
}

func runLs(dockerCli command.Cli, in lsOptions) error {
Expand Down Expand Up @@ -75,7 +76,7 @@ func runLs(dockerCli command.Cli, in lsOptions) error {
return err
}

if hasErrors, err := lsPrint(dockerCli, current, builders, in.format); err != nil {
if hasErrors, err := lsPrint(dockerCli, current, builders, in); err != nil {
return err
} else if hasErrors {
_, _ = fmt.Fprintf(dockerCli.Err(), "\n")
Expand Down Expand Up @@ -110,21 +111,23 @@ func lsCmd(dockerCli command.Cli) *cobra.Command {

flags := cmd.Flags()
flags.StringVar(&options.format, "format", formatter.TableFormatKey, "Format the output")
flags.BoolVar(&options.noTrunc, "no-trunc", false, "Don't truncate output")

// hide builder persistent flag for this command
cobrautil.HideInheritedFlags(cmd, "builder")

return cmd
}

func lsPrint(dockerCli command.Cli, current *store.NodeGroup, builders []*builder.Builder, format string) (hasErrors bool, _ error) {
if format == formatter.TableFormatKey {
format = lsDefaultTableFormat
func lsPrint(dockerCli command.Cli, current *store.NodeGroup, builders []*builder.Builder, in lsOptions) (hasErrors bool, _ error) {
if in.format == formatter.TableFormatKey {
in.format = lsDefaultTableFormat
}

ctx := formatter.Context{
Output: dockerCli.Out(),
Format: formatter.Format(format),
Format: formatter.Format(in.format),
Trunc: !in.noTrunc,
}

sort.SliceStable(builders, func(i, j int) bool {
Expand All @@ -141,11 +144,12 @@ func lsPrint(dockerCli command.Cli, current *store.NodeGroup, builders []*builde
render := func(format func(subContext formatter.SubContext) error) error {
for _, b := range builders {
if err := format(&lsContext{
format: ctx.Format,
trunc: ctx.Trunc,
Builder: &lsBuilder{
Builder: b,
Current: b.Name == current.Name,
},
format: ctx.Format,
}); err != nil {
return err
}
Expand All @@ -163,6 +167,7 @@ func lsPrint(dockerCli command.Cli, current *store.NodeGroup, builders []*builde
}
if err := format(&lsContext{
format: ctx.Format,
trunc: ctx.Trunc,
Builder: &lsBuilder{
Builder: b,
Current: b.Name == current.Name,
Expand Down Expand Up @@ -199,6 +204,7 @@ type lsContext struct {
Builder *lsBuilder

format formatter.Format
trunc bool
node builder.Node
}

Expand Down Expand Up @@ -264,7 +270,17 @@ func (c *lsContext) Platforms() string {
if c.node.Name == "" {
return ""
}
return strings.Join(platformutil.FormatInGroups(c.node.Node.Platforms, c.node.Platforms), ", ")
platforms := platformutil.FormatInGroups(c.node.Node.Platforms, c.node.Platforms)
if c.trunc && c.format.IsTable() {
tplatforms := truncPlatforms(platforms, 4)
left := len(platforms) - len(tplatforms)
out := strings.Join(tplatforms, ", ")
if left > 0 {
out += fmt.Sprintf(", (+%d)", left)
}
return out
}
return strings.Join(platforms, ", ")
}

func (c *lsContext) Error() string {
Expand All @@ -275,3 +291,51 @@ func (c *lsContext) Error() string {
}
return ""
}

func truncPlatforms(platforms []string, max int) []string {
majorPlatforms := map[string]struct{}{
"linux/amd64": {},
"linux/arm64": {},
"linux/arm/v7": {},
"linux/mips64": {},
"linux/ppc64le": {},
"linux/riscv64": {},
"linux/s390x": {},
}
var res []string
var left []string
m := map[string]struct{}{}
for _, p := range platforms {
if len(res) >= max {
break
}
pp := strings.TrimSuffix(p, "*")
if _, ok := m[pp]; ok {
continue
}
if _, ok := majorPlatforms[pp]; ok {
res = append(res, p)
m[pp] = struct{}{}
} else {
left = append(left, p)
}
}
if len(left) > 0 && len(res) < max {
cl := max - len(res)
if cl > len(left) {
cl = len(left)
}
res = append(res, left[:cl]...)
}
sort.SliceStable(res, func(i, j int) bool {
ipref := strings.HasSuffix(res[i], "*")
jpref := strings.HasSuffix(res[j], "*")
if ipref && !jpref {
return true
} else if !ipref && jpref {
return false
}
return i < j
})
return res
}
72 changes: 72 additions & 0 deletions commands/ls_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package commands

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestTruncPlatforms(t *testing.T) {
tests := []struct {
name string
platforms []string
expected []string
truncated bool
max int
}{
{
name: "arm64 preferred and emulated",
platforms: []string{"linux/arm64*", "linux/amd64", "linux/amd64/v2", "linux/riscv64", "linux/ppc64le", "linux/s390x", "linux/386", "linux/mips64le", "linux/mips64", "linux/arm/v7", "linux/arm/v6"},
expected: []string{"linux/arm64*", "linux/amd64", "linux/riscv64", "linux/ppc64le"},
truncated: true,
max: 4,
},
{
name: "riscv64 preferred only",
platforms: []string{"linux/riscv64*"},
expected: []string{"linux/riscv64*"},
max: 4,
},
{
name: "amd64 no preferred and emulated",
platforms: []string{"linux/amd64", "linux/amd64/v2", "linux/amd64/v3", "linux/386", "linux/arm64", "linux/riscv64", "linux/ppc64le", "linux/s390x", "linux/mips64le", "linux/mips64", "linux/arm/v7", "linux/arm/v6"},
expected: []string{"linux/amd64", "linux/arm64", "linux/riscv64", "linux/ppc64le"},
truncated: true,
max: 4,
},
{
name: "amd64 no preferred",
platforms: []string{"linux/amd64", "linux/386"},
expected: []string{"linux/amd64", "linux/386"},
max: 4,
},
{
name: "arm64 no preferred",
platforms: []string{"linux/arm64", "linux/arm/v7", "linux/arm/v6"},
expected: []string{"linux/arm64", "linux/arm/v7", "linux/arm/v6"},
max: 4,
},
{
name: "all preferred",
platforms: []string{"darwin/arm64*", "linux/arm64*", "linux/arm/v5*", "linux/arm/v6*", "linux/arm/v7*", "windows/arm64*"},
expected: []string{"linux/arm64*", "linux/arm/v7*", "darwin/arm64*", "linux/arm/v5*"},
truncated: true,
max: 4,
},
{
name: "no major preferred",
platforms: []string{"linux/amd64/v2*", "linux/arm/v6*", "linux/mips64le*", "linux/amd64", "linux/amd64/v3", "linux/386", "linux/arm64", "linux/riscv64", "linux/ppc64le", "linux/s390x", "linux/mips64", "linux/arm/v7"},
expected: []string{"linux/amd64", "linux/arm64", "linux/riscv64", "linux/ppc64le"},
truncated: true,
max: 4,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
tplatforms, truncated := truncPlatforms(tt.platforms, tt.max)
assert.Equal(t, tt.expected, tplatforms)
assert.Equal(t, tt.truncated, truncated)
})
}
}
7 changes: 4 additions & 3 deletions docs/reference/buildx_ls.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ List builder instances

### Options

| Name | Type | Default | Description |
|:----------------------|:---------|:--------|:------------------|
| [`--format`](#format) | `string` | `table` | Format the output |
| Name | Type | Default | Description |
|:----------------------|:---------|:--------|:----------------------|
| [`--format`](#format) | `string` | `table` | Format the output |
| `--no-trunc` | | | Don't truncate output |


<!---MARKER_GEN_END-->
Expand Down

0 comments on commit cda6a69

Please sign in to comment.