mirror of
https://github.com/containers/podman.git
synced 2025-06-20 00:51:16 +08:00
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:
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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]
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user