Port commands to V2 --format 'table...'

* 'containers mount'
 * 'image history'
 * 'images mount'
 * 'images search'
 * Correct spelling errors

Signed-off-by: Jhon Honce <jhonce@redhat.com>
This commit is contained in:
Jhon Honce
2020-10-05 15:46:50 -07:00
parent 173e3c2faa
commit b490905f26
6 changed files with 82 additions and 94 deletions

View File

@ -6,6 +6,7 @@ import (
"text/tabwriter" "text/tabwriter"
"text/template" "text/template"
"github.com/containers/podman/v2/cmd/podman/parse"
"github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/cmd/podman/utils" "github.com/containers/podman/v2/cmd/podman/utils"
"github.com/containers/podman/v2/cmd/podman/validate" "github.com/containers/podman/v2/cmd/podman/validate"
@ -75,9 +76,6 @@ func init() {
} }
func mount(_ *cobra.Command, args []string) error { func mount(_ *cobra.Command, args []string) error {
var (
errs utils.OutputErrors
)
if len(args) > 0 && mountOpts.Latest { if len(args) > 0 && mountOpts.Latest {
return errors.Errorf("--latest and containers cannot be used together") return errors.Errorf("--latest and containers cannot be used together")
} }
@ -85,7 +83,9 @@ func mount(_ *cobra.Command, args []string) error {
if err != nil { if err != nil {
return err return err
} }
if len(args) > 0 || mountOpts.Latest || mountOpts.All { if len(args) > 0 || mountOpts.Latest || mountOpts.All {
var errs utils.OutputErrors
for _, r := range reports { for _, r := range reports {
if r.Err == nil { if r.Err == nil {
fmt.Println(r.Path) fmt.Println(r.Path)
@ -96,21 +96,21 @@ func mount(_ *cobra.Command, args []string) error {
return errs.PrintErrors() return errs.PrintErrors()
} }
switch mountOpts.Format { switch {
case "json": case parse.MatchesJSONFormat(mountOpts.Format):
return printJSON(reports) return printJSON(reports)
case "": case mountOpts.Format == "":
// do nothing break // print defaults
default: default:
return errors.Errorf("unknown --format argument: %s", mountOpts.Format) return errors.Errorf("unknown --format argument: %q", mountOpts.Format)
} }
mrs := make([]mountReporter, 0, len(reports)) mrs := make([]mountReporter, 0, len(reports))
for _, r := range reports { for _, r := range reports {
mrs = append(mrs, mountReporter{r}) mrs = append(mrs, mountReporter{r})
} }
row := "{{.ID}} {{.Path}}\n"
format := "{{range . }}" + row + "{{end}}" format := "{{range . }}{{.ID}}\t{{.Path}}\n{{end}}"
tmpl, err := template.New("mounts").Parse(format) tmpl, err := template.New("mounts").Parse(format)
if err != nil { if err != nil {
return err return err
@ -139,6 +139,7 @@ func printJSON(reports []*entities.ContainerMountReport) error {
if err != nil { if err != nil {
return err return err
} }
fmt.Println(string(b)) fmt.Println(string(b))
return nil return nil
} }

View File

@ -10,7 +10,9 @@ import (
"time" "time"
"unicode" "unicode"
"github.com/containers/podman/v2/cmd/podman/parse"
"github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/cmd/podman/report"
"github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/domain/entities"
"github.com/docker/go-units" "github.com/docker/go-units"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -28,9 +30,9 @@ var (
Use: "history [flags] IMAGE", Use: "history [flags] IMAGE",
Short: "Show history of a specified image", Short: "Show history of a specified image",
Long: long, Long: long,
Example: "podman history quay.io/fedora/fedora",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: history, RunE: history,
Example: "podman history quay.io/fedora/fedora",
} }
imageHistoryCmd = &cobra.Command{ imageHistoryCmd = &cobra.Command{
@ -39,7 +41,7 @@ var (
Short: historyCmd.Short, Short: historyCmd.Short,
Long: historyCmd.Long, Long: historyCmd.Long,
RunE: historyCmd.RunE, RunE: historyCmd.RunE,
Example: `podman image history imageID`, Example: `podman image history quay.io/fedora/fedora`,
} }
opts = struct { opts = struct {
@ -79,7 +81,7 @@ func history(cmd *cobra.Command, args []string) error {
return err return err
} }
if opts.format == "json" { if parse.MatchesJSONFormat(opts.format) {
var err error var err error
if len(results.Layers) == 0 { if len(results.Layers) == 0 {
_, err = fmt.Fprintf(os.Stdout, "[]\n") _, err = fmt.Fprintf(os.Stdout, "[]\n")
@ -100,69 +102,66 @@ func history(cmd *cobra.Command, args []string) error {
} }
return err return err
} }
hr := make([]historyreporter, 0, len(results.Layers))
for _, l := range results.Layers {
hr = append(hr, historyreporter{l})
}
// Defaults
hdr := "ID\tCREATED\tCREATED BY\tSIZE\tCOMMENT\n"
row := "{{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\n"
hr := make([]historyReporter, 0, len(results.Layers))
for _, l := range results.Layers {
hr = append(hr, historyReporter{l})
}
hdrs := report.Headers(historyReporter{}, map[string]string{
"CreatedBy": "CREATED BY",
})
// Defaults
row := "{{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\n"
switch { switch {
case len(opts.format) > 0: case cmd.Flags().Changed("format"):
hdr = "" row = report.NormalizeFormat(opts.format)
row = opts.format
if !strings.HasSuffix(opts.format, "\n") {
row += "\n"
}
case opts.quiet: case opts.quiet:
hdr = ""
row = "{{.ID}}\n" row = "{{.ID}}\n"
case opts.human:
row = "{{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\n"
case opts.noTrunc:
row = "{{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\n"
} }
format := hdr + "{{range . }}" + row + "{{end}}" format := "{{range . }}" + row + "{{end}}"
tmpl, err := template.New("report").Parse(format) tmpl, err := template.New("report").Parse(format)
if err != nil { if err != nil {
return err return err
} }
w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0) w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0)
err = tmpl.Execute(w, hr) defer w.Flush()
if err != nil {
fmt.Fprintln(os.Stderr, errors.Wrapf(err, "failed to print report")) if !opts.quiet && !cmd.Flags().Changed("format") {
if err := tmpl.Execute(w, hdrs); err != nil {
return errors.Wrapf(err, "failed to write report column headers")
} }
w.Flush() }
return nil return tmpl.Execute(w, hr)
} }
type historyreporter struct { type historyReporter struct {
entities.ImageHistoryLayer entities.ImageHistoryLayer
} }
func (h historyreporter) Created() string { func (h historyReporter) Created() string {
if opts.human { if opts.human {
return units.HumanDuration(time.Since(h.ImageHistoryLayer.Created)) + " ago" return units.HumanDuration(time.Since(h.ImageHistoryLayer.Created)) + " ago"
} }
return h.ImageHistoryLayer.Created.Format(time.RFC3339) return h.ImageHistoryLayer.Created.Format(time.RFC3339)
} }
func (h historyreporter) Size() string { func (h historyReporter) Size() string {
s := units.HumanSizeWithPrecision(float64(h.ImageHistoryLayer.Size), 3) s := units.HumanSizeWithPrecision(float64(h.ImageHistoryLayer.Size), 3)
i := strings.LastIndexFunc(s, unicode.IsNumber) i := strings.LastIndexFunc(s, unicode.IsNumber)
return s[:i+1] + " " + s[i+1:] return s[:i+1] + " " + s[i+1:]
} }
func (h historyreporter) CreatedBy() string { func (h historyReporter) CreatedBy() string {
if len(h.ImageHistoryLayer.CreatedBy) > 45 { if len(h.ImageHistoryLayer.CreatedBy) > 45 {
return h.ImageHistoryLayer.CreatedBy[:45-3] + "..." return h.ImageHistoryLayer.CreatedBy[:45-3] + "..."
} }
return h.ImageHistoryLayer.CreatedBy return h.ImageHistoryLayer.CreatedBy
} }
func (h historyreporter) ID() string { func (h historyReporter) ID() string {
if !opts.noTrunc && len(h.ImageHistoryLayer.ID) >= 12 { if !opts.noTrunc && len(h.ImageHistoryLayer.ID) >= 12 {
return h.ImageHistoryLayer.ID[0:12] return h.ImageHistoryLayer.ID[0:12]
} }

View File

@ -6,6 +6,7 @@ import (
"text/tabwriter" "text/tabwriter"
"text/template" "text/template"
"github.com/containers/podman/v2/cmd/podman/parse"
"github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/cmd/podman/utils" "github.com/containers/podman/v2/cmd/podman/utils"
"github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/domain/entities"
@ -24,7 +25,7 @@ var (
mountCommand = &cobra.Command{ mountCommand = &cobra.Command{
Use: "mount [flags] [IMAGE...]", Use: "mount [flags] [IMAGE...]",
Short: "Mount an images's root filesystem", Short: "Mount an image's root filesystem",
Long: mountDescription, Long: mountDescription,
RunE: mount, RunE: mount,
Example: `podman image mount imgID Example: `podman image mount imgID
@ -56,18 +57,18 @@ func init() {
mountFlags(mountCommand.Flags()) mountFlags(mountCommand.Flags())
} }
func mount(_ *cobra.Command, args []string) error { func mount(cmd *cobra.Command, args []string) error {
var (
errs utils.OutputErrors
)
if len(args) > 0 && mountOpts.All { if len(args) > 0 && mountOpts.All {
return errors.New("when using the --all switch, you may not pass any image names or IDs") return errors.New("when using the --all switch, you may not pass any image names or IDs")
} }
reports, err := registry.ImageEngine().Mount(registry.GetContext(), args, mountOpts) reports, err := registry.ImageEngine().Mount(registry.GetContext(), args, mountOpts)
if err != nil { if err != nil {
return err return err
} }
if len(args) > 0 || mountOpts.All { if len(args) > 0 || mountOpts.All {
var errs utils.OutputErrors
for _, r := range reports { for _, r := range reports {
if r.Err == nil { if r.Err == nil {
fmt.Println(r.Path) fmt.Println(r.Path)
@ -78,22 +79,22 @@ func mount(_ *cobra.Command, args []string) error {
return errs.PrintErrors() return errs.PrintErrors()
} }
switch mountOpts.Format { switch {
case "json": case parse.MatchesJSONFormat(mountOpts.Format):
return printJSON(reports) return printJSON(reports)
case "": case mountOpts.Format == "":
// do nothing break // default format
default: default:
return errors.Errorf("unknown --format argument: %s", mountOpts.Format) return errors.Errorf("unknown --format argument: %q", mountOpts.Format)
} }
mrs := make([]mountReporter, 0, len(reports)) mrs := make([]mountReporter, 0, len(reports))
for _, r := range reports { for _, r := range reports {
mrs = append(mrs, mountReporter{r}) mrs = append(mrs, mountReporter{r})
} }
row := "{{.ID}} {{.Path}}\n"
format := "{{range . }}" + row + "{{end}}" row := "{{range . }}{{.ID}}\t{{.Path}}\n{{end}}"
tmpl, err := template.New("mounts").Parse(format) tmpl, err := template.New("mounts").Parse(row)
if err != nil { if err != nil {
return err return err
} }

View File

@ -2,15 +2,14 @@ package images
import ( import (
"os" "os"
"reflect" "text/tabwriter"
"strings" "text/template"
"github.com/containers/buildah/pkg/formats"
"github.com/containers/common/pkg/auth" "github.com/containers/common/pkg/auth"
"github.com/containers/image/v5/types" "github.com/containers/image/v5/types"
"github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/cmd/podman/report"
"github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/util/camelcase"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
@ -120,41 +119,29 @@ func imageSearch(cmd *cobra.Command, args []string) error {
if err != nil { if err != nil {
return err return err
} }
format := genSearchFormat(searchOptions.Format)
if len(searchReport) == 0 { if len(searchReport) == 0 {
return nil return nil
} }
out := formats.StdoutTemplateArray{Output: searchToGeneric(searchReport), Template: format, Fields: searchHeaderMap()}
return out.Out() hdrs := report.Headers(entities.ImageSearchReport{}, nil)
row := "{{.Index}}\t{{.Name}}\t{{.Description}}\t{{.Stars}}\t{{.Official}}\t{{.Automated}}\n"
if cmd.Flags().Changed("format") {
row = report.NormalizeFormat(searchOptions.Format)
}
row = "{{range .}}" + row + "{{end}}"
tmpl, err := template.New("search").Parse(row)
if err != nil {
return err
}
w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0)
defer w.Flush()
if !cmd.Flags().Changed("format") {
if err := tmpl.Execute(w, hdrs); err != nil {
return errors.Wrapf(err, "failed to write search column headers")
}
} }
// searchHeaderMap returns the headers of a SearchResult. return tmpl.Execute(w, searchReport)
func searchHeaderMap() map[string]string {
s := new(entities.ImageSearchReport)
v := reflect.Indirect(reflect.ValueOf(s))
values := make(map[string]string, v.NumField())
for i := 0; i < v.NumField(); i++ {
key := v.Type().Field(i).Name
value := key
values[key] = strings.ToUpper(strings.Join(camelcase.Split(value), " "))
}
return values
}
func genSearchFormat(format string) string {
if format != "" {
// "\t" from the command line is not being recognized as a tab
// replacing the string "\t" to a tab character if the user passes in "\t"
return strings.Replace(format, `\t`, "\t", -1)
}
return "table {{.Index}}\t{{.Name}}\t{{.Description}}\t{{.Stars}}\t{{.Official}}\t{{.Automated}}\t"
}
func searchToGeneric(params []entities.ImageSearchReport) (genericParams []interface{}) {
for _, v := range params {
genericParams = append(genericParams, interface{}(v))
}
return genericParams
} }

View File

@ -56,7 +56,7 @@ load helpers
# 'image mount', no args, tells us what's mounted # 'image mount', no args, tells us what's mounted
run_podman image mount run_podman image mount
is "$output" "$IMAGE $mount_path" "podman image mount with no args" is "$output" "$IMAGE *$mount_path" "podman image mount with no args"
# Clean up # Clean up
run_podman image umount $IMAGE run_podman image umount $IMAGE