Modify kpod diff --json to --format json

We want all kpod subcommands to use the formats code to output
formats like json.  Altering kpod diff --json to kpod diff --format json
like the kpod images command.

Signed-off-by: baude <bbaude@redhat.com>
This commit is contained in:
baude 2017-08-14 14:32:00 -05:00
parent f82fe5691a
commit 78c6151519
13 changed files with 267 additions and 237 deletions

View file

@ -1,10 +1,9 @@
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"github.com/containers/storage/pkg/archive" "github.com/containers/storage/pkg/archive"
"github.com/kubernetes-incubator/cri-o/cmd/kpod/formats"
"github.com/kubernetes-incubator/cri-o/libkpod" "github.com/kubernetes-incubator/cri-o/libkpod"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/urfave/cli" "github.com/urfave/cli"
@ -16,6 +15,22 @@ type diffJSONOutput struct {
Deleted []string `json:"deleted,omitempty"` Deleted []string `json:"deleted,omitempty"`
} }
type diffOutputParams struct {
Change archive.ChangeType
Path string
}
type stdoutStruct struct {
output []diffOutputParams
}
func (so stdoutStruct) Out() error {
for _, d := range so.output {
fmt.Printf("%s %s\n", d.Change, d.Path)
}
return nil
}
var ( var (
diffFlags = []cli.Flag{ diffFlags = []cli.Flag{
cli.BoolFlag{ cli.BoolFlag{
@ -23,9 +38,9 @@ var (
Usage: "Save the diff as a tar archive", Usage: "Save the diff as a tar archive",
Hidden: true, Hidden: true,
}, },
cli.BoolFlag{ cli.StringFlag{
Name: "json", Name: "format",
Usage: "Format output as JSON", Usage: "Change the output format.",
}, },
} }
diffDescription = fmt.Sprint(`Displays changes on a container or image's filesystem. The diffDescription = fmt.Sprint(`Displays changes on a container or image's filesystem. The
@ -41,6 +56,23 @@ var (
} }
) )
func formatJSON(output []diffOutputParams) (diffJSONOutput, error) {
jsonStruct := diffJSONOutput{}
for _, output := range output {
switch output.Change {
case archive.ChangeModify:
jsonStruct.Changed = append(jsonStruct.Changed, output.Path)
case archive.ChangeAdd:
jsonStruct.Added = append(jsonStruct.Added, output.Path)
case archive.ChangeDelete:
jsonStruct.Deleted = append(jsonStruct.Deleted, output.Path)
default:
return jsonStruct, errors.Errorf("output kind %q not recognized", output.Change.String())
}
}
return jsonStruct, nil
}
func diffCmd(c *cli.Context) error { func diffCmd(c *cli.Context) error {
if len(c.Args()) != 1 { if len(c.Args()) != 1 {
return errors.Errorf("container, layer, or image name must be specified: kpod diff [options [...]] ID-NAME") return errors.Errorf("container, layer, or image name must be specified: kpod diff [options [...]] ID-NAME")
@ -61,29 +93,35 @@ func diffCmd(c *cli.Context) error {
return errors.Wrapf(err, "could not get changes for %q", to) return errors.Wrapf(err, "could not get changes for %q", to)
} }
if c.Bool("json") { diffOutput := []diffOutputParams{}
jsonStruct := diffJSONOutput{} outputFormat := c.String("format")
for _, change := range changes {
if change.Kind == archive.ChangeModify { for _, change := range changes {
jsonStruct.Changed = append(jsonStruct.Changed, change.Path)
} else if change.Kind == archive.ChangeAdd { params := diffOutputParams{
jsonStruct.Added = append(jsonStruct.Added, change.Path) Change: change.Kind,
} else if change.Kind == archive.ChangeDelete { Path: change.Path,
jsonStruct.Deleted = append(jsonStruct.Deleted, change.Path)
} else {
return errors.Errorf("change kind %q not recognized", change.Kind.String())
}
}
b, err := json.MarshalIndent(jsonStruct, "", " ")
if err != nil {
return errors.Wrapf(err, "could not marshal json for %+v", jsonStruct)
}
fmt.Println(string(b))
} else {
for _, change := range changes {
fmt.Println(change.String())
} }
diffOutput = append(diffOutput, params)
} }
var out formats.Writer
if outputFormat != "" {
switch outputFormat {
case formats.JSONString:
data, err := formatJSON(diffOutput)
if err != nil {
return err
}
out = formats.JSONStruct{Output: data}
default:
return errors.New("only valid format for diff is 'json'")
}
} else {
out = stdoutStruct{output: diffOutput}
}
formats.Writer(out).Out()
return nil return nil
} }

View file

@ -3,6 +3,7 @@ package formats
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/ghodss/yaml"
"os" "os"
"strings" "strings"
"text/template" "text/template"
@ -10,25 +11,45 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
// JSONString const to save on duplicate variable names
const JSONString string = "json"
// Writer interface for outputs // Writer interface for outputs
type Writer interface { type Writer interface {
Out() error Out() error
} }
// JSONstruct for JSON output // JSONStructArray for JSON output
type JSONstruct struct { type JSONStructArray struct {
Output []interface{} Output []interface{}
} }
// StdoutTemplate for Go template output // StdoutTemplateArray for Go template output
type StdoutTemplate struct { type StdoutTemplateArray struct {
Output []interface{} Output []interface{}
Template string Template string
Fields map[string]string Fields map[string]string
} }
// Out method for JSON // JSONStruct for JSON output
func (j JSONstruct) Out() error { type JSONStruct struct {
Output interface{}
}
// StdoutTemplate for Go template output
type StdoutTemplate struct {
Output interface{}
Template string
Fields map[string]string
}
// YAMLStruct for YAML output
type YAMLStruct struct {
Output interface{}
}
// Out method for JSON Arrays
func (j JSONStructArray) Out() error {
data, err := json.MarshalIndent(j.Output, "", " ") data, err := json.MarshalIndent(j.Output, "", " ")
if err != nil { if err != nil {
return err return err
@ -38,7 +59,7 @@ func (j JSONstruct) Out() error {
} }
// Out method for Go templates // Out method for Go templates
func (t StdoutTemplate) Out() error { func (t StdoutTemplateArray) Out() error {
if strings.HasPrefix(t.Template, "table") { if strings.HasPrefix(t.Template, "table") {
t.Template = strings.TrimSpace(t.Template[5:]) t.Template = strings.TrimSpace(t.Template[5:])
headerTmpl, err := template.New("header").Funcs(headerFunctions).Parse(t.Template) headerTmpl, err := template.New("header").Funcs(headerFunctions).Parse(t.Template)
@ -67,3 +88,39 @@ func (t StdoutTemplate) Out() error {
return nil return nil
} }
// Out method for JSON struct
func (j JSONStruct) Out() error {
data, err := json.MarshalIndent(j.Output, "", " ")
if err != nil {
return err
}
fmt.Printf("%s\n", data)
return nil
}
//Out method for Go templates
func (t StdoutTemplate) Out() error {
tmpl, err := template.New("image").Parse(t.Template)
if err != nil {
return errors.Wrapf(err, "template parsing error")
}
err = tmpl.Execute(os.Stdout, t.Output)
if err != nil {
return err
}
fmt.Println()
return nil
}
// Out method for YAML
func (y YAMLStruct) Out() error {
var buf []byte
var err error
buf, err = yaml.Marshal(y.Output)
if err != nil {
return err
}
fmt.Println(string(buf))
return nil
}

View file

@ -3,17 +3,15 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings" "reflect"
"text/template"
"time"
"os"
"strconv" "strconv"
"strings"
"time"
is "github.com/containers/image/storage" is "github.com/containers/image/storage"
"github.com/containers/storage" "github.com/containers/storage"
units "github.com/docker/go-units" units "github.com/docker/go-units"
"github.com/kubernetes-incubator/cri-o/cmd/kpod/formats"
"github.com/kubernetes-incubator/cri-o/libkpod/common" "github.com/kubernetes-incubator/cri-o/libkpod/common"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -27,20 +25,20 @@ const (
// historyOutputParams stores info about each layer // historyOutputParams stores info about each layer
type historyOutputParams struct { type historyOutputParams struct {
ID string `json:"id"` ID string `json:"id"`
Created *time.Time `json:"created"` Created string `json:"created"`
CreatedBy string `json:"createdby"` CreatedBy string `json:"createdby"`
Size int64 `json:"size"` Size string `json:"size"`
Comment string `json:"comment"` Comment string `json:"comment"`
} }
// historyOptions stores cli flag values // historyOptions stores cli flag values
type historyOptions struct { type historyOptions struct {
image string image string
human bool human bool
noTrunc bool truncate bool
quiet bool quiet bool
format string format string
} }
var ( var (
@ -50,7 +48,7 @@ var (
Usage: "Display sizes and dates in human readable format", Usage: "Display sizes and dates in human readable format",
}, },
cli.BoolFlag{ cli.BoolFlag{
Name: "no-trunc", Name: "no-trunc, notruncate",
Usage: "Do not truncate the output", Usage: "Do not truncate the output",
}, },
cli.BoolFlag{ cli.BoolFlag{
@ -59,11 +57,7 @@ var (
}, },
cli.StringFlag{ cli.StringFlag{
Name: "format", Name: "format",
Usage: "Pretty-print history of the image using a Go template", Usage: "Change the output to JSON or a Go template",
},
cli.BoolFlag{
Name: "json",
Usage: "Print the history in JSON format",
}, },
} }
@ -93,23 +87,19 @@ func historyCmd(c *cli.Context) error {
if c.IsSet("human") { if c.IsSet("human") {
human = c.Bool("human") human = c.Bool("human")
} }
noTruncate := false
truncate := true
if c.IsSet("no-trunc") { if c.IsSet("no-trunc") {
noTruncate = c.Bool("no-trunc") truncate = !c.Bool("no-trunc")
} }
quiet := false quiet := false
if c.IsSet("quiet") { if c.IsSet("quiet") {
quiet = c.Bool("quiet") quiet = c.Bool("quiet")
} }
json := false
if c.IsSet("json") {
json = c.Bool("json")
}
format := "" format := ""
if c.IsSet("format") { if c.IsSet("format") {
format = c.String("format") format = c.String("format")
} }
args := c.Args() args := c.Args()
if len(args) == 0 { if len(args) == 0 {
logrus.Errorf("an image name must be specified") logrus.Errorf("an image name must be specified")
@ -122,98 +112,29 @@ func historyCmd(c *cli.Context) error {
imgName := args[0] imgName := args[0]
opts := historyOptions{ opts := historyOptions{
image: imgName, image: imgName,
human: human, human: human,
noTrunc: noTruncate, truncate: truncate,
quiet: quiet, quiet: quiet,
format: format, format: format,
}
var history []byte
if json {
history, err = createJSON(store, opts)
fmt.Println(string(history))
} else {
if format == "" && !quiet {
outputHeading(noTruncate)
}
err = outputHistory(store, opts)
} }
err = outputHistory(store, opts)
return err return err
} }
// outputHeader outputs the heading func genHistoryFormat(quiet, truncate, human bool) (format string) {
func outputHeading(noTrunc bool) { if quiet {
if !noTrunc { return "{{.ID}}"
fmt.Printf("%-12s\t\t%-16s\t\t%-45s\t\t", "IMAGE", "CREATED", "CREATED BY") }
fmt.Printf("%-16s\t\t%s\n", "SIZE", "COMMENT")
if truncate {
format = "table {{ .ID | printf \"%-12.12s\" }} {{ .Created | printf \"%-16s\" }} {{ .CreatedBy | " +
"printf \"%-45.45s\" }} {{ .Size | printf \"%-16s\" }} {{ .Comment | printf \"%s\" }}"
} else { } else {
fmt.Printf("%-64s\t%-18s\t%-60s\t", "IMAGE", "CREATED", "CREATED BY") format = "table {{ .ID | printf \"%-64s\" }} {{ .Created | printf \"%-18s\" }} {{ .CreatedBy | " +
fmt.Printf("%-16s\t%s\n", "SIZE", "COMMENT") "printf \"%-60s\" }} {{ .Size | printf \"%-16s\" }} {{ .Comment | printf \"%s\"}}"
} }
} return
// outputString outputs the information in historyOutputParams
func outputString(noTrunc, human bool, params historyOutputParams) {
var (
createdTime string
outputSize string
)
if human {
createdTime = outputHumanTime(params.Created) + " ago"
outputSize = units.HumanSize(float64(params.Size))
} else {
createdTime = outputTime(params.Created)
outputSize = strconv.FormatInt(params.Size, 10)
}
if !noTrunc {
fmt.Printf("%-12.12s\t\t%-16s\t\t%-45.45s\t\t", params.ID, createdTime, params.CreatedBy)
fmt.Printf("%-16s\t\t%s\n", outputSize, params.Comment)
} else {
fmt.Printf("%-64s\t%-18s\t%-60s\t", params.ID, createdTime, params.CreatedBy)
fmt.Printf("%-16s\t%s\n\n", outputSize, params.Comment)
}
}
// outputWithTemplate is called when --format is given a template
func outputWithTemplate(format string, params historyOutputParams, human bool) error {
templ, err := template.New("history").Parse(format)
if err != nil {
return errors.Wrapf(err, "error parsing template")
}
createdTime := outputTime(params.Created)
outputSize := strconv.FormatInt(params.Size, 10)
if human {
createdTime = outputHumanTime(params.Created) + " ago"
outputSize = units.HumanSize(float64(params.Size))
}
// templParams is used to store the info from params and the time and
// size that have been converted to type string for when the human flag
// is set
templParams := struct {
ID string
Created string
CreatedBy string
Size string
Comment string
}{
params.ID,
createdTime,
params.CreatedBy,
outputSize,
params.Comment,
}
if err = templ.Execute(os.Stdout, templParams); err != nil {
return err
}
fmt.Println()
return nil
} }
// outputTime displays the time stamp in "2017-06-20T20:24:10Z" format // outputTime displays the time stamp in "2017-06-20T20:24:10Z" format
@ -229,10 +150,12 @@ func outputHumanTime(tm *time.Time) string {
// createJSON retrieves the history of the image and returns a JSON object // createJSON retrieves the history of the image and returns a JSON object
func createJSON(store storage.Store, opts historyOptions) ([]byte, error) { func createJSON(store storage.Store, opts historyOptions) ([]byte, error) {
var ( var (
size int64 size int64
img *storage.Image img *storage.Image
imageID string imageID string
layerAll []historyOutputParams layerAll []historyOutputParams
createdTime string
outputSize string
) )
ref, err := is.Transport.ParseStoreReference(store, opts.image) ref, err := is.Transport.ParseStoreReference(store, opts.image)
@ -275,11 +198,18 @@ func createJSON(store storage.Store, opts historyOptions) ([]byte, error) {
size = 0 size = 0
} }
if opts.human {
createdTime = outputHumanTime(history[i].Created) + " ago"
outputSize = units.HumanSize(float64(size))
} else {
createdTime = outputTime(history[i].Created)
outputSize = strconv.FormatInt(size, 10)
}
params := historyOutputParams{ params := historyOutputParams{
ID: imageID, ID: imageID,
Created: history[i].Created, Created: createdTime,
CreatedBy: history[i].CreatedBy, CreatedBy: history[i].CreatedBy,
Size: size, Size: outputSize,
Comment: history[i].Comment, Comment: history[i].Comment,
} }
@ -298,6 +228,15 @@ func createJSON(store storage.Store, opts historyOptions) ([]byte, error) {
return output, nil return output, nil
} }
// historyToGeneric makes an empty array of interfaces for output
func historyToGeneric(params []historyOutputParams) []interface{} {
genericParams := make([]interface{}, len(params))
for i, v := range params {
genericParams[i] = interface{}(v)
}
return genericParams
}
// outputHistory gets the history of the image from the JSON object // outputHistory gets the history of the image from the JSON object
// and pretty prints it to the screen // and pretty prints it to the screen
func outputHistory(store storage.Store, opts historyOptions) error { func outputHistory(store storage.Store, opts historyOptions) error {
@ -316,27 +255,25 @@ func outputHistory(store storage.Store, opts historyOptions) error {
return errors.Errorf("error Unmarshalling JSON: %v", err) return errors.Errorf("error Unmarshalling JSON: %v", err)
} }
historyOutput := []historyOutputParams{}
historyFormat := opts.format
if historyFormat == "" {
historyFormat = genHistoryFormat(opts.quiet, opts.truncate, opts.human)
}
for i := 0; i < len(history); i++ { for i := 0; i < len(history); i++ {
imageID = history[i].ID imageID = history[i].ID
outputCreatedBy = strings.Join(strings.Fields(history[i].CreatedBy), " ") outputCreatedBy = strings.Join(strings.Fields(history[i].CreatedBy), " ")
if !opts.noTrunc && len(outputCreatedBy) > createdByTruncLength { if opts.truncate && len(outputCreatedBy) > createdByTruncLength {
outputCreatedBy = outputCreatedBy[:createdByTruncLength-3] + "..." outputCreatedBy = outputCreatedBy[:createdByTruncLength-3] + "..."
} }
if !opts.noTrunc && i == 0 { if opts.truncate && i == 0 {
imageID = history[i].ID[:idTruncLength] imageID = history[i].ID[:idTruncLength]
} }
if opts.quiet {
if !opts.noTrunc {
fmt.Printf("%-12.12s\n", imageID)
} else {
fmt.Printf("%-s\n", imageID)
}
continue
}
params := historyOutputParams{ params := historyOutputParams{
ID: imageID, ID: imageID,
Created: history[i].Created, Created: history[i].Created,
@ -344,15 +281,28 @@ func outputHistory(store storage.Store, opts historyOptions) error {
Size: history[i].Size, Size: history[i].Size,
Comment: history[i].Comment, Comment: history[i].Comment,
} }
historyOutput = append(historyOutput, params)
if len(opts.format) > 0 {
if err = outputWithTemplate(opts.format, params, opts.human); err != nil {
return errors.Errorf("error outputing with template: %v", err)
}
continue
}
outputString(opts.noTrunc, opts.human, params)
} }
var out formats.Writer
switch opts.format {
case formats.JSONString:
out = formats.JSONStructArray{Output: historyToGeneric(historyOutput)}
default:
out = formats.StdoutTemplateArray{Output: historyToGeneric(historyOutput), Template: historyFormat, Fields: historyOutput[0].headerMap()}
}
formats.Writer(out).Out()
return nil return nil
} }
func (h *historyOutputParams) headerMap() map[string]string {
v := reflect.Indirect(reflect.ValueOf(h))
values := make(map[string]string)
for h := 0; h < v.NumField(); h++ {
key := v.Type().Field(h).Name
value := key
values[key] = fmt.Sprintf("%s ", strings.ToUpper(splitCamelCase(value)))
}
return values
}

View file

@ -33,7 +33,7 @@ var (
}, },
cli.StringFlag{ cli.StringFlag{
Name: "format", Name: "format",
Usage: "Change the output format.", Usage: "Change the output format to JSON or a Go template",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "filter, f", Name: "filter, f",
@ -160,10 +160,10 @@ func outputImages(store storage.Store, images []storage.Image, truncate, digests
var out formats.Writer var out formats.Writer
switch outputFormat { switch outputFormat {
case "json": case formats.JSONString:
out = formats.JSONstruct{Output: toGeneric(imageOutput)} out = formats.JSONStructArray{Output: toGeneric(imageOutput)}
default: default:
out = formats.StdoutTemplate{Output: toGeneric(imageOutput), Template: outputFormat, Fields: imageOutput[0].headerMap()} out = formats.StdoutTemplateArray{Output: toGeneric(imageOutput), Template: outputFormat, Fields: imageOutput[0].headerMap()}
} }
formats.Writer(out).Out() formats.Writer(out).Out()

View file

@ -2,14 +2,13 @@ package main
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"runtime" "runtime"
"github.com/docker/docker/pkg/system" "github.com/docker/docker/pkg/system"
"github.com/ghodss/yaml" "github.com/kubernetes-incubator/cri-o/cmd/kpod/formats"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -29,9 +28,9 @@ var (
Name: "debug, D", Name: "debug, D",
Usage: "display additional debug information", Usage: "display additional debug information",
}, },
cli.BoolFlag{ cli.StringFlag{
Name: "json", Name: "format",
Usage: "output as JSON instead of the default YAML", Usage: "Change the output format to JSON or a Go template",
}, },
} }
) )
@ -57,17 +56,18 @@ func infoCmd(c *cli.Context) error {
info[thisName] = thisInfo info[thisName] = thisInfo
} }
var buf []byte var out formats.Writer
var err error infoOutputFormat := c.String("format")
if c.Bool("json") { switch infoOutputFormat {
buf, err = json.MarshalIndent(info, "", " ") case formats.JSONString:
} else { out = formats.JSONStruct{Output: info}
buf, err = yaml.Marshal(info) case "":
out = formats.YAMLStruct{Output: info}
default:
out = formats.StdoutTemplate{Output: info, Template: infoOutputFormat}
} }
if err != nil {
return err formats.Writer(out).Out()
}
fmt.Println(string(buf))
return nil return nil
} }

View file

@ -1,11 +1,7 @@
package main package main
import ( import (
"encoding/json" "github.com/kubernetes-incubator/cri-o/cmd/kpod/formats"
"fmt"
"os"
"text/template"
"github.com/kubernetes-incubator/cri-o/libkpod" "github.com/kubernetes-incubator/cri-o/libkpod"
libkpodimage "github.com/kubernetes-incubator/cri-o/libkpod/image" libkpodimage "github.com/kubernetes-incubator/cri-o/libkpod/image"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -13,9 +9,6 @@ import (
) )
const ( const (
defaultFormat = `Container: {{.Container}}
ID: {{.ContainerID}}
`
inspectTypeContainer = "container" inspectTypeContainer = "container"
inspectTypeImage = "image" inspectTypeImage = "image"
inspectAll = "all" inspectAll = "all"
@ -30,8 +23,7 @@ var (
}, },
cli.StringFlag{ cli.StringFlag{
Name: "format, f", Name: "format, f",
Value: defaultFormat, Usage: "Change the output format to a Go template",
Usage: "Format the output using the given go template",
}, },
cli.BoolFlag{ cli.BoolFlag{
Name: "size", Name: "size",
@ -60,10 +52,6 @@ func inspectCmd(c *cli.Context) error {
itemType := c.String("type") itemType := c.String("type")
size := c.Bool("size") size := c.Bool("size")
format := defaultFormat
if c.String("format") != "" {
format = c.String("format")
}
switch itemType { switch itemType {
case inspectTypeContainer: case inspectTypeContainer:
@ -73,8 +61,6 @@ func inspectCmd(c *cli.Context) error {
return errors.Errorf("the only recognized types are %q, %q, and %q", inspectTypeContainer, inspectTypeImage, inspectAll) return errors.Errorf("the only recognized types are %q, %q, and %q", inspectTypeContainer, inspectTypeImage, inspectAll)
} }
t := template.Must(template.New("format").Parse(format))
name := args[0] name := args[0]
config, err := getConfig(c) config, err := getConfig(c)
@ -89,6 +75,7 @@ func inspectCmd(c *cli.Context) error {
return errors.Wrapf(err, "could not update list of containers") return errors.Wrapf(err, "could not update list of containers")
} }
outputFormat := c.String("format")
var data interface{} var data interface{}
switch itemType { switch itemType {
case inspectTypeContainer: case inspectTypeContainer:
@ -115,18 +102,15 @@ func inspectCmd(c *cli.Context) error {
} }
} }
if c.IsSet("format") { var out formats.Writer
if err = t.Execute(os.Stdout, data); err != nil { if outputFormat != "" && outputFormat != formats.JSONString {
return err //template
} out = formats.StdoutTemplate{Output: data, Template: outputFormat}
fmt.Println() } else {
return nil // default is json output
out = formats.JSONStruct{Output: data}
} }
d, err := json.MarshalIndent(data, "", " ") formats.Writer(out).Out()
if err != nil { return nil
return errors.Wrapf(err, "error encoding build container as json")
}
_, err = fmt.Println(string(d))
return err
} }

View file

@ -4,6 +4,7 @@ import (
js "encoding/json" js "encoding/json"
"fmt" "fmt"
of "github.com/kubernetes-incubator/cri-o/cmd/kpod/formats"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -28,7 +29,7 @@ var (
}, },
cli.StringFlag{ cli.StringFlag{
Name: "format", Name: "format",
Usage: "Print mounted containers in specified format", Usage: "Change the output format to Go template",
}, },
} }
mountCommand = cli.Command{ mountCommand = cli.Command{
@ -55,7 +56,7 @@ func mountCmd(c *cli.Context) error {
} }
args := c.Args() args := c.Args()
json := c.String("format") == "json" json := c.String("format") == of.JSONString
if !formats[c.String("format")] { if !formats[c.String("format")] {
return errors.Errorf("%q is not a supported format", c.String("format")) return errors.Errorf("%q is not a supported format", c.String("format"))
} }

View file

@ -35,10 +35,10 @@ _kpod_info() {
local boolean_options=" local boolean_options="
--help --help
-h -h
--json
--debug --debug
" "
local options_with_args=" local options_with_args="
--format
" "
local all_options="$options_with_args $boolean_options" local all_options="$options_with_args $boolean_options"

View file

@ -13,9 +13,9 @@ Displays changes on a container or image's filesystem. The container or image w
## OPTIONS ## OPTIONS
**--json** **--format**
Format output as json Alter the output into a different format. The only valid format for diff is `json`.
## EXAMPLE ## EXAMPLE
@ -26,7 +26,7 @@ C /usr/local
C /usr/local/bin C /usr/local/bin
A /usr/local/bin/docker-entrypoint.sh A /usr/local/bin/docker-entrypoint.sh
kpod diff --json redis:alpine kpod diff --format json redis:alpine
{ {
"changed": [ "changed": [
"/usr", "/usr",

View file

@ -47,10 +47,8 @@ Valid placeholders for the Go template are listed below:
Print the numeric IDs only Print the numeric IDs only
**--format** **--format**
Pretty-print history of the image using a Go template Alter the output for a format like 'json' or a Go template.
**--json**
Print the history in JSON form
## COMMANDS ## COMMANDS
@ -60,6 +58,8 @@ Valid placeholders for the Go template are listed below:
**kpod history --format "{{.ID}} {{.Created}}" debian** **kpod history --format "{{.ID}} {{.Created}}" debian**
**kpod history --format json debian**
## history ## history
Show the history of an image Show the history of an image

View file

@ -21,16 +21,16 @@ Information display here pertain to the host, current storage stats, and build o
Show additional information Show additional information
**--json** **--format**
Output as JSON instead of the default YAML", Change output format to "json" or a Go template.
## EXAMPLE ## EXAMPLE
`kpod info` `kpod info`
`kpod info --debug --json | jq .host.kernel` `kpod info --debug --format json| jq .host.kernel`
## SEE ALSO ## SEE ALSO
crio(8), crio.conf(5) crio(8), crio.conf(5)

View file

@ -73,7 +73,7 @@ function teardown() {
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
} }
@test "kpod history with format" { @test "kpod history with Go template format" {
run ${KPOD_BINARY} ${KPOD_OPTIONS} pull $IMAGE run ${KPOD_BINARY} ${KPOD_OPTIONS} pull $IMAGE
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
run ${KPOD_BINARY} ${KPOD_OPTIONS} history --format "{{.ID}} {{.Created}}" $IMAGE run ${KPOD_BINARY} ${KPOD_OPTIONS} history --format "{{.ID}} {{.Created}}" $IMAGE
@ -116,7 +116,7 @@ function teardown() {
@test "kpod history json flag" { @test "kpod history json flag" {
run ${KPOD_BINARY} ${KPOD_OPTIONS} pull $IMAGE run ${KPOD_BINARY} ${KPOD_OPTIONS} pull $IMAGE
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} history --json $IMAGE | python -m json.tool" run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} history --format json $IMAGE | python -m json.tool"
echo "$output" echo "$output"
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
run ${KPOD_BINARY} $KPOD_OPTIONS rmi $IMAGE run ${KPOD_BINARY} $KPOD_OPTIONS rmi $IMAGE

View file

@ -29,8 +29,8 @@ function teardown() {
@test "test diff with json output" { @test "test diff with json output" {
run ${KPOD_BINARY} $KPOD_OPTIONS pull $IMAGE run ${KPOD_BINARY} $KPOD_OPTIONS pull $IMAGE
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
# run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} diff --json $IMAGE | python -m json.tool" # run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} diff --format json $IMAGE | python -m json.tool"
run ${KPOD_BINARY} $KPOD_OPTIONS diff --json $IMAGE run ${KPOD_BINARY} $KPOD_OPTIONS diff --format json $IMAGE
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
echo "$output" echo "$output"
run ${KKPOD_BINARY} $KPOD_OPTIONS rmi $IMAGE run ${KKPOD_BINARY} $KPOD_OPTIONS rmi $IMAGE