Skip to content

Commit

Permalink
Refactor podman system to report.Formatter
Browse files Browse the repository at this point in the history
[NO NEW TESTS NEEDED]

Support better compatibility output for podman system commands

* Format and content of output from podman version changed to
  be more compatible

See containers#10974
Depends on containers/common#831

Signed-off-by: Jhon Honce <[email protected]>
  • Loading branch information
jwhonce committed Dec 3, 2021
1 parent a50502d commit 7d22cc8
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 103 deletions.
45 changes: 20 additions & 25 deletions cmd/podman/system/connection/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,6 @@ func list(cmd *cobra.Command, _ []string) error {
return err
}

hdrs := []map[string]string{{
"Identity": "Identity",
"Name": "Name",
"URI": "URI",
"Default": "Default",
}}

rows := make([]namedDestination, 0)
for k, v := range cfg.Engine.ServiceDestinations {
def := false
Expand All @@ -82,35 +75,37 @@ func list(cmd *cobra.Command, _ []string) error {
return rows[i].Name < rows[j].Name
})

var format string
switch {
case report.IsJSON(cmd.Flag("format").Value.String()):
rpt := report.New(os.Stdout, cmd.Name())
defer rpt.Flush()

if report.IsJSON(cmd.Flag("format").Value.String()) {
buf, err := registry.JSONLibrary().MarshalIndent(rows, "", " ")
if err == nil {
fmt.Println(string(buf))
}
return err
case cmd.Flags().Changed("format"):
format = report.NormalizeFormat(cmd.Flag("format").Value.String())
default:
format = "{{.Name}}\t{{.URI}}\t{{.Identity}}\t{{.Default}}\n"
}
format = report.EnforceRange(format)

tmpl, err := report.NewTemplate("list").Parse(format)
if err != nil {
return err
if cmd.Flag("format").Changed {
rpt, err = rpt.Parse(report.OriginUser, cmd.Flag("format").Value.String())
} else {
rpt, err = rpt.Parse(report.OriginPodman,
"{{range .}}{{.Name}}\t{{.URI}}\t{{.Identity}}\t{{.Default}}\n{{end -}}")
}

w, err := report.NewWriterDefault(os.Stdout)
if err != nil {
return err
}
defer w.Flush()

isTable := report.HasTable(cmd.Flag("format").Value.String())
if !cmd.Flag("format").Changed || isTable {
_ = tmpl.Execute(w, hdrs)
if rpt.RenderHeaders {
err = rpt.Execute([]map[string]string{{
"Default": "Default",
"Identity": "Identity",
"Name": "Name",
"URI": "URI",
}})
if err != nil {
return err
}
}
return tmpl.Execute(w, rows)
return rpt.Execute(rows)
}
75 changes: 43 additions & 32 deletions cmd/podman/system/df.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,23 +54,19 @@ func df(cmd *cobra.Command, args []string) error {
return err
}

w, err := report.NewWriterDefault(os.Stdout)
if err != nil {
return err
}

if dfOptions.Verbose {
return printVerbose(w, cmd, reports)
return printVerbose(cmd, reports)
}
return printSummary(w, cmd, reports)
return printSummary(cmd, reports)
}

func printSummary(w *report.Writer, cmd *cobra.Command, reports *entities.SystemDfReport) error {
func printSummary(cmd *cobra.Command, reports *entities.SystemDfReport) error {
var (
dfSummaries []*dfSummary
active int
size, reclaimable int64
)

for _, i := range reports.Images {
if i.Containers > 0 {
active++
Expand Down Expand Up @@ -136,17 +132,28 @@ func printSummary(w *report.Writer, cmd *cobra.Command, reports *entities.System
"Size": "SIZE",
"Reclaimable": "RECLAIMABLE",
})
row := "{{.Type}}\t{{.Total}}\t{{.Active}}\t{{.Size}}\t{{.Reclaimable}}\n"

rpt := report.New(os.Stdout, cmd.Name())
defer rpt.Flush()

var err error
if cmd.Flags().Changed("format") {
row = report.NormalizeFormat(dfOptions.Format)
rpt, err = rpt.Parse(report.OriginUser, dfOptions.Format)
} else {
row := "{{range . }}{{.Type}}\t{{.Total}}\t{{.Active}}\t{{.Size}}\t{{.Reclaimable}}\n{{end -}}"
rpt, err = rpt.Parse(report.OriginPodman, row)
}
if err != nil {
return err
}
return writeTemplate(w, cmd, hdrs, row, dfSummaries)
return writeTemplate(rpt, hdrs, dfSummaries)
}

func printVerbose(w *report.Writer, cmd *cobra.Command, reports *entities.SystemDfReport) error {
defer w.Flush()
func printVerbose(cmd *cobra.Command, reports *entities.SystemDfReport) error { // nolint:interfacer
rpt := report.New(os.Stdout, cmd.Name())
defer rpt.Flush()

fmt.Fprint(w, "Images space usage:\n\n")
fmt.Fprint(rpt.Writer(), "Images space usage:\n\n")
// convert to dfImage for output
dfImages := make([]*dfImage, 0, len(reports.Images))
for _, d := range reports.Images {
Expand All @@ -157,12 +164,16 @@ func printVerbose(w *report.Writer, cmd *cobra.Command, reports *entities.System
"SharedSize": "SHARED SIZE",
"UniqueSize": "UNIQUE SIZE",
})
imageRow := "{{.Repository}}\t{{.Tag}}\t{{.ImageID}}\t{{.Created}}\t{{.Size}}\t{{.SharedSize}}\t{{.UniqueSize}}\t{{.Containers}}\n"
if err := writeTemplate(w, cmd, hdrs, imageRow, dfImages); err != nil {
imageRow := "{{range .}}{{.Repository}}\t{{.Tag}}\t{{.ImageID}}\t{{.Created}}\t{{.Size}}\t{{.SharedSize}}\t{{.UniqueSize}}\t{{.Containers}}\n{{end -}}"
rpt, err := rpt.Parse(report.OriginPodman, imageRow)
if err != nil {
return err
}
if err := writeTemplate(rpt, hdrs, dfImages); err != nil {
return nil
}

fmt.Fprint(w, "\nContainers space usage:\n\n")
fmt.Fprint(rpt.Writer(), "\nContainers space usage:\n\n")
// convert to dfContainers for output
dfContainers := make([]*dfContainer, 0, len(reports.Containers))
for _, d := range reports.Containers {
Expand All @@ -173,12 +184,16 @@ func printVerbose(w *report.Writer, cmd *cobra.Command, reports *entities.System
"LocalVolumes": "LOCAL VOLUMES",
"RWSize": "SIZE",
})
containerRow := "{{.ContainerID}}\t{{.Image}}\t{{.Command}}\t{{.LocalVolumes}}\t{{.RWSize}}\t{{.Created}}\t{{.Status}}\t{{.Names}}\n"
if err := writeTemplate(w, cmd, hdrs, containerRow, dfContainers); err != nil {
containerRow := "{{range .}}{{.ContainerID}}\t{{.Image}}\t{{.Command}}\t{{.LocalVolumes}}\t{{.RWSize}}\t{{.Created}}\t{{.Status}}\t{{.Names}}\n{{end -}}"
rpt, err = rpt.Parse(report.OriginPodman, containerRow)
if err != nil {
return err
}
if err := writeTemplate(rpt, hdrs, dfContainers); err != nil {
return nil
}

fmt.Fprint(w, "\nLocal Volumes space usage:\n\n")
fmt.Fprint(rpt.Writer(), "\nLocal Volumes space usage:\n\n")
dfVolumes := make([]*dfVolume, 0, len(reports.Volumes))
// convert to dfVolume for output
for _, d := range reports.Volumes {
Expand All @@ -187,25 +202,21 @@ func printVerbose(w *report.Writer, cmd *cobra.Command, reports *entities.System
hdrs = report.Headers(entities.SystemDfVolumeReport{}, map[string]string{
"VolumeName": "VOLUME NAME",
})
volumeRow := "{{.VolumeName}}\t{{.Links}}\t{{.Size}}\n"
return writeTemplate(w, cmd, hdrs, volumeRow, dfVolumes)
}

func writeTemplate(w *report.Writer, cmd *cobra.Command, hdrs []map[string]string, format string, output interface{}) error {
defer w.Flush()

format = report.EnforceRange(format)
tmpl, err := report.NewTemplate("df").Parse(format)
volumeRow := "{{range .}}{{.VolumeName}}\t{{.Links}}\t{{.Size}}\n{{end -}}"
rpt, err = rpt.Parse(report.OriginPodman, volumeRow)
if err != nil {
return err
}
return writeTemplate(rpt, hdrs, dfVolumes)
}

if !cmd.Flags().Changed("format") {
if err := tmpl.Execute(w, hdrs); err != nil {
func writeTemplate(rpt *report.Formatter, hdrs []map[string]string, output interface{}) error {
if rpt.RenderHeaders {
if err := rpt.Execute(hdrs); err != nil {
return err
}
}
return tmpl.Execute(w, output)
return rpt.Execute(output)
}

type dfImage struct {
Expand Down
8 changes: 4 additions & 4 deletions cmd/podman/system/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,15 @@ func eventsCmd(cmd *cobra.Command, _ []string) error {
errChannel := make(chan error)

var (
tmpl *report.Template
rpt *report.Formatter
doJSON bool
)

if cmd.Flags().Changed("format") {
doJSON = report.IsJSON(eventFormat)
if !doJSON {
var err error
tmpl, err = report.NewTemplate("events").Parse(eventFormat)
rpt, err = report.New(os.Stdout, cmd.Name()).Parse(report.OriginUser, eventFormat)
if err != nil {
return err
}
Expand All @@ -108,10 +108,10 @@ func eventsCmd(cmd *cobra.Command, _ []string) error {
}
fmt.Println(jsonStr)
case cmd.Flags().Changed("format"):
if err := tmpl.Execute(os.Stdout, event); err != nil {
if err := rpt.Execute(event); err != nil {
return err
}
fmt.Println("")
os.Stdout.WriteString("\n")
default:
fmt.Println(event.ToHumanReadable(!noTrunc))
}
Expand Down
6 changes: 5 additions & 1 deletion cmd/podman/system/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package system
import (
"fmt"
"os"
"text/template"

"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/report"
Expand Down Expand Up @@ -84,7 +85,10 @@ func info(cmd *cobra.Command, args []string) error {
}
fmt.Println(string(b))
case cmd.Flags().Changed("format"):
tmpl, err := report.NewTemplate("info").Parse(inFormat)
// Cannot use report.New() as it enforces {{range .}} for OriginUser templates
tmpl := template.New(cmd.Name()).Funcs(template.FuncMap(report.DefaultFuncs))
inFormat = report.NormalizeFormat(inFormat)
tmpl, err := tmpl.Parse(inFormat)
if err != nil {
return err
}
Expand Down
77 changes: 41 additions & 36 deletions cmd/podman/system/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ package system

import (
"fmt"
"io"
"os"
"strings"
"text/template"

"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/report"
"github.com/containers/podman/v3/cmd/podman/common"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -53,54 +52,60 @@ func version(cmd *cobra.Command, args []string) error {
return nil
}

w, err := report.NewWriterDefault(os.Stdout)
if err != nil {
return err
}
defer w.Flush()
if cmd.Flag("format").Changed {
// Cannot use report.New() as it enforces {{range .}} for OriginUser templates
tmpl := template.New(cmd.Name()).Funcs(template.FuncMap(report.DefaultFuncs))

if cmd.Flags().Changed("format") {
row := report.NormalizeFormat(versionFormat)
tmpl, err := report.NewTemplate("version 2.0.0").Parse(row)
versionFormat = report.NormalizeFormat(versionFormat)
tmpl, err := tmpl.Parse(versionFormat)
if err != nil {
return err
}
if err := tmpl.Execute(w, versions); err != nil {
if err := tmpl.Execute(os.Stdout, versions); err != nil {
// On Failure, assume user is using older version of podman version --format and check client
row = strings.ReplaceAll(row, ".Server.", ".")
tmpl, err := report.NewTemplate("version 1.0.0").Parse(row)
versionFormat = strings.ReplaceAll(versionFormat, ".Server.", ".")
tmpl, err := tmpl.Parse(versionFormat)
if err != nil {
return err
}
if err := tmpl.Execute(w, versions.Client); err != nil {
if err := tmpl.Execute(os.Stdout, versions.Client); err != nil {
return err
}
}
return nil
}

if versions.Server != nil {
if _, err := fmt.Fprintf(w, "Client:\n"); err != nil {
return err
}
formatVersion(w, versions.Client)
if _, err := fmt.Fprintf(w, "\nServer:\n"); err != nil {
return err
}
formatVersion(w, versions.Server)
} else {
formatVersion(w, versions.Client)
rpt := report.New(os.Stdout, cmd.Name())
defer rpt.Flush()
rpt, err = rpt.Parse(report.OriginPodman, versionTemplate)
if err != nil {
return err
}
return nil
return rpt.Execute(versions)
}

func formatVersion(w io.Writer, version *define.Version) {
fmt.Fprintf(w, "Version:\t%s\n", version.Version)
fmt.Fprintf(w, "API Version:\t%s\n", version.APIVersion)
fmt.Fprintf(w, "Go Version:\t%s\n", version.GoVersion)
if version.GitCommit != "" {
fmt.Fprintf(w, "Git Commit:\t%s\n", version.GitCommit)
}
fmt.Fprintf(w, "Built:\t%s\n", version.BuiltTime)
fmt.Fprintf(w, "OS/Arch:\t%s\n", version.OsArch)
}
const versionTemplate = `{{with .Client -}}
Client:\tPodman Engine
Version:\t{{.Version}}
API Version:\t{{.APIVersion}}
Go Version:\t{{.GoVersion}}
{{if .GitCommit -}}
Git Commit:\t{{.GitCommit}}
{{- end}}
Built:\t{{.BuiltTime}}
OS/Arch:\t{{.OsArch}}
{{- end}}
{{- if .Server }}{{with .Server}}
Server:\tPodman Engine
Version:\t{{.Version}}
API Version:\t{{.APIVersion}}
Go Version:\t{{.GoVersion}}
{{if .GitCommit -}}
Git Commit:\t{{.GitCommit}}
{{- end}}
Built:\t{{.BuiltTime}}
OS/Arch:\t{{.OsArch}}
{{- end}}{{- end}}
`
8 changes: 3 additions & 5 deletions test/system/001-basic.bats
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@ function setup() {
@test "podman version emits reasonable output" {
run_podman version

# First line of podman-remote is "Client:<blank>".
# First line of podman version is "Client: *Podman Engine".
# Just delete it (i.e. remove the first entry from the 'lines' array)
if is_remote; then
if expr "${lines[0]}" : "Client:" >/dev/null; then
lines=("${lines[@]:1}")
fi
if expr "${lines[0]}" : "Client: *" >/dev/null; then
lines=("${lines[@]:1}")
fi

is "${lines[0]}" "Version:[ ]\+[1-9][0-9.]\+" "Version line 1"
Expand Down

0 comments on commit 7d22cc8

Please sign in to comment.