From 3929ba61e6e3e1b5cbaf0f585fa159f9e77342de Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Mon, 1 Nov 2021 15:10:34 +0900 Subject: [PATCH] Allow `--format=json` as an alias of `--format={{json .}}` Signed-off-by: Akihiro Suda --- cmd/nerdctl/container_inspect.go | 3 +++ cmd/nerdctl/events.go | 6 ++++-- cmd/nerdctl/fmtutil.go | 14 +++++++++++++- cmd/nerdctl/image_inspect.go | 3 +++ cmd/nerdctl/images.go | 6 ++++-- cmd/nerdctl/info.go | 6 ++++-- cmd/nerdctl/info_test.go | 30 +++++++++++++++++++----------- cmd/nerdctl/inspect.go | 3 +++ cmd/nerdctl/network_inspect.go | 3 +++ cmd/nerdctl/network_ls.go | 6 ++++-- cmd/nerdctl/ps.go | 6 ++++-- cmd/nerdctl/version.go | 6 ++++-- cmd/nerdctl/volume_inspect.go | 3 +++ cmd/nerdctl/volume_ls.go | 6 ++++-- 14 files changed, 75 insertions(+), 26 deletions(-) diff --git a/cmd/nerdctl/container_inspect.go b/cmd/nerdctl/container_inspect.go index c3c7ae663a9..ab7f15cec14 100644 --- a/cmd/nerdctl/container_inspect.go +++ b/cmd/nerdctl/container_inspect.go @@ -43,6 +43,9 @@ func newContainerInspectCommand() *cobra.Command { return []string{"dockercompat", "native"}, cobra.ShellCompDirectiveNoFileComp }) containerInspectCommand.Flags().StringP("format", "f", "", "Format the output using the given Go template, e.g, '{{json .}}'") + containerInspectCommand.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{"json"}, cobra.ShellCompDirectiveNoFileComp + }) return containerInspectCommand } diff --git a/cmd/nerdctl/events.go b/cmd/nerdctl/events.go index 8cc4b47d726..be6e6832c9e 100644 --- a/cmd/nerdctl/events.go +++ b/cmd/nerdctl/events.go @@ -27,7 +27,6 @@ import ( "github.com/containerd/containerd/events" "github.com/containerd/containerd/log" "github.com/containerd/typeurl" - "github.com/docker/cli/templates" "github.com/spf13/cobra" @@ -48,6 +47,9 @@ func newEventsCommand() *cobra.Command { SilenceErrors: true, } eventsCommand.Flags().String("format", "", "Format the output using the given Go template, e.g, '{{json .}}'") + eventsCommand.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{"json"}, cobra.ShellCompDirectiveNoFileComp + }) return eventsCommand } @@ -83,7 +85,7 @@ func eventsAction(cmd *cobra.Command, args []string) error { case "raw", "table": return errors.New("unsupported format: \"raw\" and \"table\"") default: - tmpl, err = templates.Parse(format) + tmpl, err = parseTemplate(format) if err != nil { return err } diff --git a/cmd/nerdctl/fmtutil.go b/cmd/nerdctl/fmtutil.go index a3f82160419..8d3cfabd512 100644 --- a/cmd/nerdctl/fmtutil.go +++ b/cmd/nerdctl/fmtutil.go @@ -68,7 +68,7 @@ func formatSlice(cmd *cobra.Command, x []interface{}) error { return errors.New("unsupported format: \"raw\" and \"table\"") default: var err error - tmpl, err = templates.Parse(format) + tmpl, err = parseTemplate(format) if err != nil { return err } @@ -84,3 +84,15 @@ func formatSlice(cmd *cobra.Command, x []interface{}) error { } return nil } + +// parseTemplate wraps github.com/docker/cli/templates.Parse() to allow `json` as an alias of `{{json .}}`. +// parseTemplate can be removed when https://github.com/docker/cli/pull/3355 gets merged and tagged (Docker 22.XX). +func parseTemplate(format string) (*template.Template, error) { + aliases := map[string]string{ + "json": "{{json .}}", + } + if alias, ok := aliases[format]; ok { + format = alias + } + return templates.Parse(format) +} diff --git a/cmd/nerdctl/image_inspect.go b/cmd/nerdctl/image_inspect.go index f8b3687df5b..1f4e586a8e3 100644 --- a/cmd/nerdctl/image_inspect.go +++ b/cmd/nerdctl/image_inspect.go @@ -46,6 +46,9 @@ func newImageInspectCommand() *cobra.Command { return []string{"dockercompat", "native"}, cobra.ShellCompDirectiveNoFileComp }) imageInspectCommand.Flags().StringP("format", "f", "", "Format the output using the given Go template, e.g, '{{json .}}'") + imageInspectCommand.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{"json"}, cobra.ShellCompDirectiveNoFileComp + }) // #region platform flags imageInspectCommand.Flags().String("platform", "", "Inspect a specific platform") // not a slice, and there is no --all-platforms diff --git a/cmd/nerdctl/images.go b/cmd/nerdctl/images.go index 7cd2d682205..9c955219d6a 100644 --- a/cmd/nerdctl/images.go +++ b/cmd/nerdctl/images.go @@ -38,7 +38,6 @@ import ( "github.com/containerd/containerd/snapshots" "github.com/containerd/nerdctl/pkg/formatter" "github.com/containerd/nerdctl/pkg/imgutil" - "github.com/docker/cli/templates" "github.com/opencontainers/image-spec/identity" v1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/sirupsen/logrus" @@ -63,6 +62,9 @@ func newImagesCommand() *cobra.Command { imagesCommand.Flags().Bool("no-trunc", false, "Don't truncate output") // Alias "-f" is reserved for "--filter" imagesCommand.Flags().String("format", "", "Format the output using the given Go template, e.g, '{{json .}}'") + imagesCommand.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{"json"}, cobra.ShellCompDirectiveNoFileComp + }) imagesCommand.Flags().Bool("digests", false, "Show digests (compatible with Docker, unlike ID)") return imagesCommand @@ -152,7 +154,7 @@ func printImages(ctx context.Context, cmd *cobra.Command, client *containerd.Cli return errors.New("format and quiet must not be specified together") } var err error - tmpl, err = templates.Parse(format) + tmpl, err = parseTemplate(format) if err != nil { return err } diff --git a/cmd/nerdctl/info.go b/cmd/nerdctl/info.go index 696f030f3e6..ac0160eafb5 100644 --- a/cmd/nerdctl/info.go +++ b/cmd/nerdctl/info.go @@ -25,7 +25,6 @@ import ( "github.com/containerd/nerdctl/pkg/infoutil" "github.com/containerd/nerdctl/pkg/strutil" - "github.com/docker/cli/templates" "github.com/docker/go-units" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -41,6 +40,9 @@ func newInfoCommand() *cobra.Command { SilenceErrors: true, } infoCommand.Flags().StringP("format", "f", "", "Format the output using the given Go template, e.g, '{{json .}}'") + infoCommand.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{"json"}, cobra.ShellCompDirectiveNoFileComp + }) return infoCommand } @@ -56,7 +58,7 @@ func infoAction(cmd *cobra.Command, args []string) error { return err } if format != "" { - tmpl, err = templates.Parse(format) + tmpl, err = parseTemplate(format) if err != nil { return err } diff --git a/cmd/nerdctl/info_test.go b/cmd/nerdctl/info_test.go index 958101378fd..7606b0ed601 100644 --- a/cmd/nerdctl/info_test.go +++ b/cmd/nerdctl/info_test.go @@ -27,19 +27,27 @@ import ( "github.com/containerd/nerdctl/pkg/testutil" ) +func testInfoJSON(stdout string) error { + var info dockercompat.Info + if err := json.Unmarshal([]byte(stdout), &info); err != nil { + return err + } + unameM := infoutil.UnameM() + if info.Architecture != unameM { + return fmt.Errorf("expected info.Architecture to be %q, got %q", unameM, info.Architecture) + } + return nil +} + func TestInfo(t *testing.T) { base := testutil.NewBase(t) - base.Cmd("info", "--format", "{{json .}}").AssertOutWithFunc(func(stdout string) error { - var info dockercompat.Info - if err := json.Unmarshal([]byte(stdout), &info); err != nil { - return err - } - unameM := infoutil.UnameM() - if info.Architecture != unameM { - return fmt.Errorf("expected info.Architecture to be %q, got %q", unameM, info.Architecture) - } - return nil - }) + base.Cmd("info", "--format", "{{json .}}").AssertOutWithFunc(testInfoJSON) +} + +func TestInfoConvenienceForm(t *testing.T) { + testutil.DockerIncompatible(t) // until https://github.com/docker/cli/pull/3355 gets merged + base := testutil.NewBase(t) + base.Cmd("info", "--format", "json").AssertOutWithFunc(testInfoJSON) } func TestInfoWithNamespace(t *testing.T) { diff --git a/cmd/nerdctl/inspect.go b/cmd/nerdctl/inspect.go index dc90a03b6aa..d3801620cd9 100644 --- a/cmd/nerdctl/inspect.go +++ b/cmd/nerdctl/inspect.go @@ -43,6 +43,9 @@ func newInspectCommand() *cobra.Command { func addInspectFlags(cmd *cobra.Command) { cmd.Flags().StringP("format", "f", "", "Format the output using the given Go template, e.g, '{{json .}}'") + cmd.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{"json"}, cobra.ShellCompDirectiveNoFileComp + }) cmd.Flags().String("mode", "dockercompat", `Inspect mode, "dockercompat" for Docker-compatible output, "native" for containerd-native output`) cmd.RegisterFlagCompletionFunc("mode", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return []string{"dockercompat", "native"}, cobra.ShellCompDirectiveNoFileComp diff --git a/cmd/nerdctl/network_inspect.go b/cmd/nerdctl/network_inspect.go index af76f3763a7..a6db19edaa6 100644 --- a/cmd/nerdctl/network_inspect.go +++ b/cmd/nerdctl/network_inspect.go @@ -42,6 +42,9 @@ func newNetworkInspectCommand() *cobra.Command { return []string{"dockercompat", "native"}, cobra.ShellCompDirectiveNoFileComp }) networkInspectCommand.Flags().StringP("format", "f", "", "Format the output using the given Go template, e.g, '{{json .}}'") + networkInspectCommand.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{"json"}, cobra.ShellCompDirectiveNoFileComp + }) return networkInspectCommand } diff --git a/cmd/nerdctl/network_ls.go b/cmd/nerdctl/network_ls.go index b102efe31d4..78d8717aaa2 100644 --- a/cmd/nerdctl/network_ls.go +++ b/cmd/nerdctl/network_ls.go @@ -25,7 +25,6 @@ import ( "text/template" "github.com/containerd/nerdctl/pkg/netutil" - "github.com/docker/cli/templates" "github.com/spf13/cobra" ) @@ -43,6 +42,9 @@ func newNetworkLsCommand() *cobra.Command { cmd.Flags().BoolP("quiet", "q", false, "Only display network IDs") // Alias "-f" is reserved for "--filter" cmd.Flags().String("format", "", "Format the output using the given Go template, e.g, '{{json .}}'") + cmd.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{"json"}, cobra.ShellCompDirectiveNoFileComp + }) return cmd } @@ -78,7 +80,7 @@ func networkLsAction(cmd *cobra.Command, args []string) error { return errors.New("format and quiet must not be specified together") } var err error - tmpl, err = templates.Parse(format) + tmpl, err = parseTemplate(format) if err != nil { return err } diff --git a/cmd/nerdctl/ps.go b/cmd/nerdctl/ps.go index dec06cdd877..6098e22da67 100644 --- a/cmd/nerdctl/ps.go +++ b/cmd/nerdctl/ps.go @@ -31,7 +31,6 @@ import ( "github.com/containerd/containerd" "github.com/containerd/nerdctl/pkg/formatter" "github.com/containerd/nerdctl/pkg/labels" - "github.com/docker/cli/templates" "github.com/spf13/cobra" ) @@ -50,6 +49,9 @@ func newPsCommand() *cobra.Command { psCommand.Flags().BoolP("quiet", "q", false, "Only display container IDs") // Alias "-f" is reserved for "--filter" psCommand.Flags().String("format", "", "Format the output using the given Go template, e.g, '{{json .}}'") + psCommand.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{"json"}, cobra.ShellCompDirectiveNoFileComp + }) return psCommand } @@ -112,7 +114,7 @@ func printContainers(ctx context.Context, cmd *cobra.Command, containers []conta return errors.New("format and quiet must not be specified together") } var err error - tmpl, err = templates.Parse(format) + tmpl, err = parseTemplate(format) if err != nil { return err } diff --git a/cmd/nerdctl/version.go b/cmd/nerdctl/version.go index cd1180f4733..da2c73d73df 100644 --- a/cmd/nerdctl/version.go +++ b/cmd/nerdctl/version.go @@ -25,7 +25,6 @@ import ( "github.com/containerd/nerdctl/pkg/infoutil" "github.com/containerd/nerdctl/pkg/inspecttypes/dockercompat" - "github.com/docker/cli/templates" "github.com/spf13/cobra" ) @@ -39,6 +38,9 @@ func newVersionCommand() *cobra.Command { SilenceErrors: true, } versionCommand.Flags().StringP("format", "f", "", "Format the output using the given Go template, e.g, '{{json .}}'") + versionCommand.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{"json"}, cobra.ShellCompDirectiveNoFileComp + }) return versionCommand } @@ -52,7 +54,7 @@ func versionAction(cmd *cobra.Command, args []string) error { } if format != "" { var err error - tmpl, err = templates.Parse(format) + tmpl, err = parseTemplate(format) if err != nil { return err } diff --git a/cmd/nerdctl/volume_inspect.go b/cmd/nerdctl/volume_inspect.go index 78123088033..1e199bfab8a 100644 --- a/cmd/nerdctl/volume_inspect.go +++ b/cmd/nerdctl/volume_inspect.go @@ -33,6 +33,9 @@ func newVolumeInspectCommand() *cobra.Command { SilenceErrors: true, } volumeInspectCommand.Flags().StringP("format", "f", "", "Format the output using the given Go template, e.g, '{{json .}}'") + volumeInspectCommand.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{"json"}, cobra.ShellCompDirectiveNoFileComp + }) return volumeInspectCommand } diff --git a/cmd/nerdctl/volume_ls.go b/cmd/nerdctl/volume_ls.go index 286abedae33..0dc9d8e8c73 100644 --- a/cmd/nerdctl/volume_ls.go +++ b/cmd/nerdctl/volume_ls.go @@ -24,7 +24,6 @@ import ( "text/template" "github.com/containerd/nerdctl/pkg/inspecttypes/native" - "github.com/docker/cli/templates" "github.com/spf13/cobra" ) @@ -42,6 +41,9 @@ func newVolumeLsCommand() *cobra.Command { volumeLsCommand.Flags().BoolP("quiet", "q", false, "Only display volume names") // Alias "-f" is reserved for "--filter" volumeLsCommand.Flags().String("format", "", "Format the output using the given go template") + volumeLsCommand.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{"json"}, cobra.ShellCompDirectiveNoFileComp + }) return volumeLsCommand } @@ -78,7 +80,7 @@ func volumeLsAction(cmd *cobra.Command, args []string) error { return errors.New("format and quiet must not be specified together") } var err error - tmpl, err = templates.Parse(format) + tmpl, err = parseTemplate(format) if err != nil { return err }