Files
kopia/cli/json_output.go
Julio López 948162dce5 refactor(general): minor miscellaneous cleanups (#4074)
Cleanups:

- use non-format variants of Log/Print with no additional args;
- fold in Fprintf call with no args into the following one;
- add missing arg placeholder in format strings;
- use require.Positive instead of Greater(..., 0);
- rename function to fillWithZeros to avoid collision with builtin clear;
- define type for context key to avoid collisions.
2024-08-25 22:10:46 -07:00

126 lines
2.5 KiB
Go

package cli
import (
"encoding/json"
"fmt"
"io"
"github.com/alecthomas/kingpin/v2"
"github.com/kopia/kopia/snapshot"
)
type jsonOutput struct {
jsonOutput bool
jsonIndent bool
jsonVerbose bool // output non-essential stats as part of JSON
out io.Writer
}
func (c *jsonOutput) setup(svc appServices, cmd *kingpin.CmdClause) {
cmd.Flag("json", "Output result in JSON format to stdout").BoolVar(&c.jsonOutput)
cmd.Flag("json-indent", "Output result in indented JSON format to stdout").Hidden().BoolVar(&c.jsonIndent)
cmd.Flag("json-verbose", "Output non-essential data (e.g. statistics) in JSON format").Hidden().BoolVar(&c.jsonVerbose)
c.out = svc.stdout()
}
func (c *jsonOutput) cleanupSnapshotManifestForJSON(v *snapshot.Manifest) interface{} {
m := *v
if !c.jsonVerbose {
return struct {
*snapshot.Manifest
// trick to remove 'stats' completely.
Stats string `json:"stats,omitempty"`
}{Manifest: v}
}
return &m
}
func (c *jsonOutput) cleanupSnapshotManifestListForJSON(manifests []*snapshot.Manifest) interface{} {
var res []interface{}
for _, m := range manifests {
res = append(res, c.cleanupSnapshotManifestForJSON(m))
}
return res
}
func (c *jsonOutput) cleanupForJSON(v interface{}) interface{} {
switch v := v.(type) {
case *snapshot.Manifest:
return c.cleanupSnapshotManifestForJSON(v)
case []*snapshot.Manifest:
return c.cleanupSnapshotManifestListForJSON(v)
default:
return v
}
}
func (c *jsonOutput) jsonBytes(v interface{}) []byte {
return c.jsonIndentedBytes(v, "")
}
func (c *jsonOutput) jsonIndentedBytes(v interface{}, indent string) []byte {
v = c.cleanupForJSON(v)
var (
b []byte
err error
)
if c.jsonIndent {
b, err = json.MarshalIndent(v, indent+"", indent+" ")
} else {
b, err = json.Marshal(v)
}
if err != nil {
panic("error serializing JSON, that should not happen: " + err.Error())
}
return b
}
type jsonList struct {
separator string
o *jsonOutput
}
func (l *jsonList) begin(o *jsonOutput) {
l.o = o
if o.jsonOutput {
fmt.Fprint(l.o.out, "[") //nolint:errcheck
if !o.jsonIndent {
l.separator = "\n "
}
}
}
func (l *jsonList) end() {
if l.o.jsonOutput {
if !l.o.jsonIndent {
fmt.Fprint(l.o.out, "\n") //nolint:errcheck
}
fmt.Fprint(l.o.out, "]") //nolint:errcheck
}
}
func (l *jsonList) emit(v interface{}) {
fmt.Fprintf(l.o.out, "%s%s", l.separator, l.o.jsonBytes(v)) //nolint:errcheck
if l.o.jsonIndent {
l.separator = ","
} else {
l.separator = ",\n "
}
}