diff --git a/cli/cmd/context/ls.go b/cli/cmd/context/ls.go index 935488c4..9001dfca 100644 --- a/cli/cmd/context/ls.go +++ b/cli/cmd/context/ls.go @@ -29,6 +29,7 @@ package context import ( "context" + "errors" "fmt" "os" "sort" @@ -39,10 +40,19 @@ import ( apicontext "github.com/docker/api/context" "github.com/docker/api/context/store" + "github.com/docker/api/formatter" ) type lsOpts struct { quiet bool + json bool +} + +func (o lsOpts) validate() error { + if o.quiet && o.json { + return errors.New(`cannot combine "quiet" and "json" options`) + } + return nil } func listCommand() *cobra.Command { @@ -57,10 +67,17 @@ func listCommand() *cobra.Command { }, } cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false, "Only show context names") + cmd.Flags().BoolVar(&opts.json, "json", false, "Format output as JSON") + return cmd } func runList(ctx context.Context, opts lsOpts) error { + err := opts.validate() + if err != nil { + return err + } + currentContext := apicontext.CurrentContext(ctx) s := store.ContextStore(ctx) contexts, err := s.List() @@ -79,6 +96,15 @@ func runList(ctx context.Context, opts lsOpts) error { return nil } + if opts.json { + j, err := formatter.ToStandardJSON(contexts) + if err != nil { + return err + } + fmt.Println(j) + return nil + } + w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) fmt.Fprintln(w, "NAME\tTYPE\tDESCRIPTION\tDOCKER ENDPOINT\tKUBERNETES ENDPOINT\tORCHESTRATOR") format := "%s\t%s\t%s\t%s\t%s\t%s\n" diff --git a/cli/cmd/inspect.go b/cli/cmd/inspect.go index 60f897d8..525582f2 100644 --- a/cli/cmd/inspect.go +++ b/cli/cmd/inspect.go @@ -2,13 +2,13 @@ package cmd import ( "context" - "encoding/json" "fmt" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/docker/api/client" + "github.com/docker/api/formatter" ) // InspectCommand inspects into containers @@ -36,12 +36,11 @@ func runInspect(ctx context.Context, id string) error { return err } - b, err := json.MarshalIndent(container, "", " ") + j, err := formatter.ToStandardJSON(container) if err != nil { return err } - containerString := string(b) - fmt.Println(containerString) + fmt.Println(j) return nil } diff --git a/cli/cmd/ps.go b/cli/cmd/ps.go index 76691a7e..9100b07d 100644 --- a/cli/cmd/ps.go +++ b/cli/cmd/ps.go @@ -11,11 +11,20 @@ import ( "github.com/docker/api/cli/formatter" "github.com/docker/api/client" + formatter2 "github.com/docker/api/formatter" ) type psOpts struct { all bool quiet bool + json bool +} + +func (o psOpts) validate() error { + if o.quiet && o.json { + return errors.New(`cannot combine "quiet" and "json" options`) + } + return nil } // PsCommand lists containers @@ -31,11 +40,17 @@ func PsCommand() *cobra.Command { cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false, "Only display IDs") cmd.Flags().BoolVarP(&opts.all, "all", "a", false, "Show all containers (default shows just running)") + cmd.Flags().BoolVar(&opts.json, "json", false, "Format output as JSON") return cmd } func runPs(ctx context.Context, opts psOpts) error { + err := opts.validate() + if err != nil { + return err + } + c, err := client.New(ctx) if err != nil { return errors.Wrap(err, "cannot connect to backend") @@ -53,6 +68,15 @@ func runPs(ctx context.Context, opts psOpts) error { return nil } + if opts.json { + j, err := formatter2.ToStandardJSON(containers) + if err != nil { + return err + } + fmt.Println(j) + return nil + } + w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) fmt.Fprintf(w, "CONTAINER ID\tIMAGE\tCOMMAND\tSTATUS\tPORTS\n") format := "%s\t%s\t%s\t%s\t%s\n" diff --git a/cli/cmd/testdata/inspect-out-id.golden b/cli/cmd/testdata/inspect-out-id.golden index 28473f4d..03b45c08 100644 --- a/cli/cmd/testdata/inspect-out-id.golden +++ b/cli/cmd/testdata/inspect-out-id.golden @@ -1,13 +1,13 @@ { - "ID": "id", - "Status": "", - "Image": "nginx", - "Command": "", - "CPUTime": 0, - "MemoryUsage": 0, - "MemoryLimit": 0, - "PidsCurrent": 0, - "PidsLimit": 0, - "Labels": null, - "Ports": null + "ID": "id", + "Status": "", + "Image": "nginx", + "Command": "", + "CPUTime": 0, + "MemoryUsage": 0, + "MemoryLimit": 0, + "PidsCurrent": 0, + "PidsLimit": 0, + "Labels": null, + "Ports": null } diff --git a/formatter/json.go b/formatter/json.go new file mode 100644 index 00000000..892c3521 --- /dev/null +++ b/formatter/json.go @@ -0,0 +1,41 @@ +/* + Copyright (c) 2020 Docker Inc. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH + THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +package formatter + +import "encoding/json" + +const standardIndentation = " " + +// ToStandardJSON return a string with the JSON representation of the interface{} +func ToStandardJSON(i interface{}) (string, error) { + b, err := json.MarshalIndent(i, "", standardIndentation) + if err != nil { + return "", err + } + return string(b), nil +} diff --git a/tests/e2e/testdata/inspect-id.golden b/tests/e2e/testdata/inspect-id.golden index 28473f4d..03b45c08 100644 --- a/tests/e2e/testdata/inspect-id.golden +++ b/tests/e2e/testdata/inspect-id.golden @@ -1,13 +1,13 @@ { - "ID": "id", - "Status": "", - "Image": "nginx", - "Command": "", - "CPUTime": 0, - "MemoryUsage": 0, - "MemoryLimit": 0, - "PidsCurrent": 0, - "PidsLimit": 0, - "Labels": null, - "Ports": null + "ID": "id", + "Status": "", + "Image": "nginx", + "Command": "", + "CPUTime": 0, + "MemoryUsage": 0, + "MemoryLimit": 0, + "PidsCurrent": 0, + "PidsLimit": 0, + "Labels": null, + "Ports": null }