summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com>2022-09-13 20:26:24 +0200
committerGitHub <noreply@github.com>2022-09-13 20:26:24 +0200
commitad529f31d82796c17c5a3dde5fed20b84d5bd256 (patch)
tree6d6f50a8e9c9d5d9de2b5bb248d3f54b8ee755fe
parent6e382d9ec2e6eb79a72537544341e496368b6c63 (diff)
parent9d41b95d72ef29870e6c325557c89c2db818a371 (diff)
downloadpodman-ad529f31d82796c17c5a3dde5fed20b84d5bd256.tar.gz
podman-ad529f31d82796c17c5a3dde5fed20b84d5bd256.tar.bz2
podman-ad529f31d82796c17c5a3dde5fed20b84d5bd256.zip
Merge pull request #15673 from Luap99/template
Fix go template parsing with "\n" in it
-rw-r--r--cmd/podman/auto-update.go28
-rw-r--r--cmd/podman/inspect/inspect.go33
-rw-r--r--cmd/podman/machine/info.go12
-rw-r--r--cmd/podman/machine/inspect.go20
-rw-r--r--cmd/podman/machine/list.go40
-rw-r--r--cmd/podman/networks/list.go31
-rw-r--r--cmd/podman/secrets/inspect.go13
-rw-r--r--cmd/podman/secrets/list.go32
-rw-r--r--cmd/podman/system/info.go13
-rw-r--r--cmd/podman/system/version.go19
-rw-r--r--cmd/podman/volumes/list.go30
-rw-r--r--pkg/machine/e2e/inspect_test.go8
-rw-r--r--test/e2e/volume_ls_test.go5
-rw-r--r--test/system/610-format.bats169
14 files changed, 286 insertions, 167 deletions
diff --git a/cmd/podman/auto-update.go b/cmd/podman/auto-update.go
index 88ef0ec88..6a0446422 100644
--- a/cmd/podman/auto-update.go
+++ b/cmd/podman/auto-update.go
@@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
"os"
- "strings"
"github.com/containers/common/pkg/auth"
"github.com/containers/common/pkg/completion"
@@ -104,15 +103,15 @@ func reportsToOutput(allReports []*entities.AutoUpdateReport) []autoUpdateOutput
}
func writeTemplate(allReports []*entities.AutoUpdateReport, inputFormat string) error {
- var format string
- var printHeader bool
+ rpt := report.New(os.Stdout, "auto-update")
+ defer rpt.Flush()
output := reportsToOutput(allReports)
+ var err error
switch inputFormat {
case "":
- rows := []string{"{{.Unit}}", "{{.Container}}", "{{.Image}}", "{{.Policy}}", "{{.Updated}}"}
- format = "{{range . }}" + strings.Join(rows, "\t") + "\n{{end -}}"
- printHeader = true
+ format := "{{range . }}\t{{.Unit}}\t{{.Container}}\t{{.Image}}\t{{.Policy}}\t{{.Updated}}\n{{end -}}"
+ rpt, err = rpt.Parse(report.OriginPodman, format)
case "json":
prettyJSON, err := json.MarshalIndent(output, "", " ")
if err != nil {
@@ -121,26 +120,17 @@ func writeTemplate(allReports []*entities.AutoUpdateReport, inputFormat string)
fmt.Println(string(prettyJSON))
return nil
default:
- format = "{{range . }}" + inputFormat + "\n{{end -}}"
+ rpt, err = rpt.Parse(report.OriginUser, inputFormat)
}
-
- tmpl, err := report.NewTemplate("auto-update").Parse(format)
- if err != nil {
- return err
- }
-
- w, err := report.NewWriterDefault(os.Stdout)
if err != nil {
return err
}
- defer w.Flush()
- if printHeader {
+ if rpt.RenderHeaders {
headers := report.Headers(autoUpdateOutput{}, nil)
- if err := tmpl.Execute(w, headers); err != nil {
+ if err := rpt.Execute(headers); err != nil {
return err
}
}
-
- return tmpl.Execute(w, output)
+ return rpt.Execute(output)
}
diff --git a/cmd/podman/inspect/inspect.go b/cmd/podman/inspect/inspect.go
index ccabd7614..22b2c9055 100644
--- a/cmd/podman/inspect/inspect.go
+++ b/cmd/podman/inspect/inspect.go
@@ -8,7 +8,6 @@ import (
"os"
"regexp"
"strings"
- "text/template"
"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/report"
@@ -16,7 +15,6 @@ import (
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/cmd/podman/validate"
"github.com/containers/podman/v4/pkg/domain/entities"
- "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -176,13 +174,18 @@ func (i *inspector) inspect(namesOrIDs []string) error {
}
default:
// Landing here implies user has given a custom --format
- row := inspectNormalize(i.options.Format, tmpType)
- row = report.NormalizeFormat(row)
- row = report.EnforceRange(row)
- err = printTmpl(tmpType, row, data)
+ var rpt *report.Formatter
+ format := inspectNormalize(i.options.Format, i.options.Type)
+ rpt, err = report.New(os.Stdout, "inspect").Parse(report.OriginUser, format)
+ if err != nil {
+ return err
+ }
+ defer rpt.Flush()
+
+ err = rpt.Execute(data)
}
if err != nil {
- logrus.Errorf("Printing inspect output: %v", err)
+ errs = append(errs, fmt.Errorf("printing inspect output: %w", err))
}
if len(errs) > 0 {
@@ -205,22 +208,6 @@ func printJSON(data interface{}) error {
return enc.Encode(data)
}
-func printTmpl(typ, row string, data []interface{}) error {
- // We cannot use c/common/reports here, too many levels of interface{}
- t, err := template.New(typ + " inspect").Funcs(template.FuncMap(report.DefaultFuncs)).Parse(row)
- if err != nil {
- return err
- }
-
- w, err := report.NewWriterDefault(os.Stdout)
- if err != nil {
- return err
- }
- err = t.Execute(w, data)
- w.Flush()
- return err
-}
-
func (i *inspector) inspectAll(ctx context.Context, namesOrIDs []string) ([]interface{}, []error, error) {
var data []interface{}
allErrs := []error{}
diff --git a/cmd/podman/machine/info.go b/cmd/podman/machine/info.go
index 1151f9e86..9c7454379 100644
--- a/cmd/podman/machine/info.go
+++ b/cmd/podman/machine/info.go
@@ -5,7 +5,6 @@ package machine
import (
"fmt"
- "html/template"
"os"
"runtime"
@@ -75,13 +74,16 @@ func info(cmd *cobra.Command, args []string) error {
}
fmt.Println(string(b))
case cmd.Flags().Changed("format"):
- tmpl := template.New(cmd.Name()).Funcs(template.FuncMap(report.DefaultFuncs))
- inFormat = report.NormalizeFormat(inFormat)
- tmpl, err := tmpl.Parse(inFormat)
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
+
+ // Use OriginUnknown so it does not add an extra range since it
+ // will only be called for a single element and not a slice.
+ rpt, err = rpt.Parse(report.OriginUnknown, inFormat)
if err != nil {
return err
}
- return tmpl.Execute(os.Stdout, info)
+ return rpt.Execute(info)
default:
b, err := yaml.Marshal(info)
if err != nil {
diff --git a/cmd/podman/machine/inspect.go b/cmd/podman/machine/inspect.go
index d69c382f2..410bb3889 100644
--- a/cmd/podman/machine/inspect.go
+++ b/cmd/podman/machine/inspect.go
@@ -11,7 +11,6 @@ import (
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/cmd/podman/utils"
"github.com/containers/podman/v4/pkg/machine"
- "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -66,28 +65,23 @@ func inspect(cmd *cobra.Command, args []string) error {
}
vms = append(vms, *ii)
}
+
switch {
case cmd.Flag("format").Changed:
- row := report.NormalizeFormat(inspectFlag.format)
- row = report.EnforceRange(row)
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
- tmpl, err := report.NewTemplate("Machine inspect").Parse(row)
+ rpt, err := rpt.Parse(report.OriginUser, inspectFlag.format)
if err != nil {
return err
}
- w, err := report.NewWriterDefault(os.Stdout)
- if err != nil {
- return err
- }
-
- if err := tmpl.Execute(w, vms); err != nil {
- logrus.Error(err)
+ if err := rpt.Execute(vms); err != nil {
+ errs = append(errs, err)
}
- w.Flush()
default:
if err := printJSON(vms); err != nil {
- logrus.Error(err)
+ errs = append(errs, err)
}
}
return errs.PrintErrors()
diff --git a/cmd/podman/machine/list.go b/cmd/podman/machine/list.go
index dd4a86697..ddc9ce246 100644
--- a/cmd/podman/machine/list.go
+++ b/cmd/podman/machine/list.go
@@ -53,7 +53,7 @@ func init() {
flags := lsCmd.Flags()
formatFlagName := "format"
- flags.StringVar(&listFlag.format, formatFlagName, "{{.Name}}\t{{.VMType}}\t{{.Created}}\t{{.LastUp}}\t{{.CPUs}}\t{{.Memory}}\t{{.DiskSize}}\n", "Format volume output using JSON or a Go template")
+ flags.StringVar(&listFlag.format, formatFlagName, "{{range .}}{{.Name}}\t{{.VMType}}\t{{.Created}}\t{{.LastUp}}\t{{.CPUs}}\t{{.Memory}}\t{{.DiskSize}}\n{{end -}}", "Format volume output using JSON or a Go template")
_ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.ListReporter{}))
flags.BoolVar(&listFlag.noHeading, "noheading", false, "Do not print headers")
flags.BoolVarP(&listFlag.quiet, "quiet", "q", false, "Show only machine names")
@@ -66,10 +66,6 @@ func list(cmd *cobra.Command, args []string) error {
err error
)
- if listFlag.quiet {
- listFlag.format = "{{.Name}}\n"
- }
-
provider := GetSystemDefaultProvider()
listResponse, err = provider.List(opts)
if err != nil {
@@ -115,37 +111,29 @@ func outputTemplate(cmd *cobra.Command, responses []*entities.ListReporter) erro
"Memory": "MEMORY",
"DiskSize": "DISK SIZE",
})
- printHeader := !listFlag.noHeading
- if listFlag.quiet {
- printHeader = false
- }
- var row string
+
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
+
+ var err error
switch {
- case cmd.Flags().Changed("format"):
- row = cmd.Flag("format").Value.String()
- printHeader = report.HasTable(row)
- row = report.NormalizeFormat(row)
+ case cmd.Flag("format").Changed:
+ rpt, err = rpt.Parse(report.OriginUser, listFlag.format)
+ case listFlag.quiet:
+ rpt, err = rpt.Parse(report.OriginUser, "{{.Name}}\n")
default:
- row = cmd.Flag("format").Value.String()
+ rpt, err = rpt.Parse(report.OriginPodman, listFlag.format)
}
- format := report.EnforceRange(row)
-
- tmpl, err := report.NewTemplate("list").Parse(format)
if err != nil {
return err
}
- w, err := report.NewWriterDefault(os.Stdout)
- if err != nil {
- return err
- }
- defer w.Flush()
- if printHeader {
- if err := tmpl.Execute(w, headers); err != nil {
+ if rpt.RenderHeaders && !listFlag.noHeading {
+ if err := rpt.Execute(headers); err != nil {
return fmt.Errorf("failed to write report column headers: %w", err)
}
}
- return tmpl.Execute(w, responses)
+ return rpt.Execute(responses)
}
func strTime(t time.Time) string {
diff --git a/cmd/podman/networks/list.go b/cmd/podman/networks/list.go
index 5d4be2a81..951583cfb 100644
--- a/cmd/podman/networks/list.go
+++ b/cmd/podman/networks/list.go
@@ -122,36 +122,27 @@ func templateOut(cmd *cobra.Command, responses []types.Network) error {
"ID": "network id",
})
- renderHeaders := report.HasTable(networkListOptions.Format)
- var row string
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
+
+ var err error
switch {
- case cmd.Flags().Changed("format"):
- row = report.NormalizeFormat(networkListOptions.Format)
+ case cmd.Flag("format").Changed:
+ rpt, err = rpt.Parse(report.OriginUser, networkListOptions.Format)
default:
- // 'podman network ls' equivalent to 'podman network ls --format="table {{.ID}} {{.Name}} {{.Version}} {{.Plugins}}" '
- row = "{{.ID}}\t{{.Name}}\t{{.Driver}}\n"
- renderHeaders = true
+ rpt, err = rpt.Parse(report.OriginPodman, "{{range .}}{{.ID}}\t{{.Name}}\t{{.Driver}}\n{{end -}}")
}
- format := report.EnforceRange(row)
-
- tmpl, err := report.NewTemplate("list").Parse(format)
- if err != nil {
- return err
- }
-
- w, err := report.NewWriterDefault(os.Stdout)
if err != nil {
return err
}
- defer w.Flush()
noHeading, _ := cmd.Flags().GetBool("noheading")
- if !noHeading && renderHeaders {
- if err := tmpl.Execute(w, headers); err != nil {
- return err
+ if rpt.RenderHeaders && !noHeading {
+ if err := rpt.Execute(headers); err != nil {
+ return fmt.Errorf("failed to write report column headers: %w", err)
}
}
- return tmpl.Execute(w, nlprs)
+ return rpt.Execute(nlprs)
}
// ListPrintReports returns the network list report
diff --git a/cmd/podman/secrets/inspect.go b/cmd/podman/secrets/inspect.go
index c99e555ba..f4c395b0f 100644
--- a/cmd/podman/secrets/inspect.go
+++ b/cmd/podman/secrets/inspect.go
@@ -47,20 +47,15 @@ func inspect(cmd *cobra.Command, args []string) error {
}
if cmd.Flags().Changed("format") {
- row := report.NormalizeFormat(format)
- formatted := report.EnforceRange(row)
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
- tmpl, err := report.NewTemplate("inspect").Parse(formatted)
+ rpt, err := rpt.Parse(report.OriginUser, format)
if err != nil {
return err
}
- w, err := report.NewWriterDefault(os.Stdout)
- if err != nil {
- return err
- }
- defer w.Flush()
- if err := tmpl.Execute(w, inspected); err != nil {
+ if err := rpt.Execute(inspected); err != nil {
return err
}
} else {
diff --git a/cmd/podman/secrets/list.go b/cmd/podman/secrets/list.go
index afa9b8887..1833cc544 100644
--- a/cmd/podman/secrets/list.go
+++ b/cmd/podman/secrets/list.go
@@ -46,7 +46,7 @@ func init() {
flags := lsCmd.Flags()
formatFlagName := "format"
- flags.StringVar(&listFlag.format, formatFlagName, "{{.ID}}\t{{.Name}}\t{{.Driver}}\t{{.CreatedAt}}\t{{.UpdatedAt}}\t\n", "Format volume output using Go template")
+ flags.StringVar(&listFlag.format, formatFlagName, "{{range .}}{{.ID}}\t{{.Name}}\t{{.Driver}}\t{{.CreatedAt}}\t{{.UpdatedAt}}\n{{end -}}", "Format volume output using Go template")
_ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.SecretInfoReport{}))
filterFlagName := "filter"
@@ -105,31 +105,25 @@ func outputTemplate(cmd *cobra.Command, responses []*entities.SecretListReport)
"UpdatedAt": "UPDATED",
})
- row := cmd.Flag("format").Value.String()
- if cmd.Flags().Changed("format") {
- row = report.NormalizeFormat(row)
- }
- format := report.EnforceRange(row)
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
- tmpl, err := report.NewTemplate("list").Parse(format)
- if err != nil {
- return err
+ var err error
+ switch {
+ case cmd.Flag("format").Changed:
+ rpt, err = rpt.Parse(report.OriginUser, listFlag.format)
+ default:
+ rpt, err = rpt.Parse(report.OriginPodman, listFlag.format)
}
-
- w, err := report.NewWriterDefault(os.Stdout)
if err != nil {
return err
}
- defer w.Flush()
-
- if cmd.Flags().Changed("format") && !report.HasTable(listFlag.format) {
- listFlag.noHeading = true
- }
- if !listFlag.noHeading {
- if err := tmpl.Execute(w, headers); err != nil {
+ noHeading, _ := cmd.Flags().GetBool("noheading")
+ if rpt.RenderHeaders && !noHeading {
+ if err := rpt.Execute(headers); err != nil {
return fmt.Errorf("failed to write report column headers: %w", err)
}
}
- return tmpl.Execute(w, responses)
+ return rpt.Execute(responses)
}
diff --git a/cmd/podman/system/info.go b/cmd/podman/system/info.go
index 296fa4def..9613d5e56 100644
--- a/cmd/podman/system/info.go
+++ b/cmd/podman/system/info.go
@@ -3,7 +3,6 @@ package system
import (
"fmt"
"os"
- "text/template"
"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/report"
@@ -86,14 +85,16 @@ func info(cmd *cobra.Command, args []string) error {
}
fmt.Println(string(b))
case cmd.Flags().Changed("format"):
- // 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)
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
+
+ // Use OriginUnknown so it does not add an extra range since it
+ // will only be called for a single element and not a slice.
+ rpt, err = rpt.Parse(report.OriginUnknown, inFormat)
if err != nil {
return err
}
- return tmpl.Execute(os.Stdout, info)
+ return rpt.Execute(info)
default:
b, err := yaml.Marshal(info)
if err != nil {
diff --git a/cmd/podman/system/version.go b/cmd/podman/system/version.go
index 7202b2c08..33ab0f757 100644
--- a/cmd/podman/system/version.go
+++ b/cmd/podman/system/version.go
@@ -4,7 +4,6 @@ import (
"fmt"
"os"
"strings"
- "text/template"
"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/report"
@@ -12,6 +11,7 @@ import (
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/cmd/podman/validate"
"github.com/containers/podman/v4/pkg/domain/entities"
+ "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -53,22 +53,25 @@ func version(cmd *cobra.Command, args []string) error {
}
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))
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
- versionFormat = report.NormalizeFormat(versionFormat)
- tmpl, err := tmpl.Parse(versionFormat)
+ // Use OriginUnknown so it does not add an extra range since it
+ // will only be called for a single element and not a slice.
+ rpt, err = rpt.Parse(report.OriginUnknown, versionFormat)
if err != nil {
return err
}
- if err := tmpl.Execute(os.Stdout, versions); err != nil {
+ if err := rpt.Execute(versions); err != nil {
+ // only log at debug since we fall back to the client only template
+ logrus.Debugf("Failed to execute template: %v", err)
// On Failure, assume user is using older version of podman version --format and check client
versionFormat = strings.ReplaceAll(versionFormat, ".Server.", ".")
- tmpl, err := tmpl.Parse(versionFormat)
+ rpt, err := rpt.Parse(report.OriginUnknown, versionFormat)
if err != nil {
return err
}
- if err := tmpl.Execute(os.Stdout, versions.Client); err != nil {
+ if err := rpt.Execute(versions.Client); err != nil {
return err
}
}
diff --git a/cmd/podman/volumes/list.go b/cmd/podman/volumes/list.go
index 06118513d..70041834b 100644
--- a/cmd/podman/volumes/list.go
+++ b/cmd/podman/volumes/list.go
@@ -55,7 +55,7 @@ func init() {
_ = lsCommand.RegisterFlagCompletionFunc(filterFlagName, common.AutocompleteVolumeFilters)
formatFlagName := "format"
- flags.StringVar(&cliOpts.Format, formatFlagName, "{{.Driver}}\t{{.Name}}\n", "Format volume output using Go template")
+ flags.StringVar(&cliOpts.Format, formatFlagName, "{{range .}}{{.Driver}}\t{{.Name}}\n{{end -}}", "Format volume output using Go template")
_ = lsCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.VolumeListReport{}))
flags.Bool("noheading", false, "Do not print headers")
@@ -95,34 +95,28 @@ func outputTemplate(cmd *cobra.Command, responses []*entities.VolumeListReport)
"Name": "VOLUME NAME",
})
- var row string
+ rpt := report.New(os.Stdout, cmd.Name())
+ defer rpt.Flush()
+
+ var err error
switch {
+ case cmd.Flag("format").Changed:
+ rpt, err = rpt.Parse(report.OriginUser, cliOpts.Format)
case cliOpts.Quiet:
- row = "{{.Name}}\n"
- case cmd.Flags().Changed("format"):
- row = report.NormalizeFormat(cliOpts.Format)
+ rpt, err = rpt.Parse(report.OriginUser, "{{.Name}}\n")
default:
- row = cmd.Flag("format").Value.String()
+ rpt, err = rpt.Parse(report.OriginPodman, cliOpts.Format)
}
- format := report.EnforceRange(row)
-
- tmpl, err := report.NewTemplate("list").Parse(format)
- if err != nil {
- return err
- }
-
- w, err := report.NewWriterDefault(os.Stdout)
if err != nil {
return err
}
- defer w.Flush()
- if !(noHeading || cliOpts.Quiet || cmd.Flag("format").Changed) {
- if err := tmpl.Execute(w, headers); err != nil {
+ if (rpt.RenderHeaders) && !noHeading {
+ if err := rpt.Execute(headers); err != nil {
return fmt.Errorf("failed to write report column headers: %w", err)
}
}
- return tmpl.Execute(w, responses)
+ return rpt.Execute(responses)
}
func outputJSON(vols []*entities.VolumeListReport) error {
diff --git a/pkg/machine/e2e/inspect_test.go b/pkg/machine/e2e/inspect_test.go
index 0ab928205..fac9f7ebe 100644
--- a/pkg/machine/e2e/inspect_test.go
+++ b/pkg/machine/e2e/inspect_test.go
@@ -75,5 +75,13 @@ var _ = Describe("podman machine stop", func() {
Expect(err).To(BeNil())
Expect(inspectSession).To(Exit(0))
Expect(inspectSession.Bytes()).To(ContainSubstring(name))
+
+ // check invalid template returns error
+ inspect = new(inspectMachine)
+ inspect = inspect.withFormat("{{.Abcde}}")
+ inspectSession, err = mb.setName(name).setCmd(inspect).run()
+ Expect(err).To(BeNil())
+ Expect(inspectSession).To(Exit(125))
+ Expect(inspectSession.errorToString()).To(ContainSubstring("can't evaluate field Abcde in type machine.InspectInfo"))
})
})
diff --git a/test/e2e/volume_ls_test.go b/test/e2e/volume_ls_test.go
index dcfb13f4e..24ea50b26 100644
--- a/test/e2e/volume_ls_test.go
+++ b/test/e2e/volume_ls_test.go
@@ -75,7 +75,10 @@ var _ = Describe("Podman volume ls", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- Expect(session.OutputToStringArray()).To(HaveLen(1), session.OutputToString())
+ arr := session.OutputToStringArray()
+ Expect(arr).To(HaveLen(2))
+ Expect(arr[0]).To(ContainSubstring("NAME"))
+ Expect(arr[1]).To(ContainSubstring("myvol"))
})
It("podman ls volume with --filter flag", func() {
diff --git a/test/system/610-format.bats b/test/system/610-format.bats
new file mode 100644
index 000000000..096d0228b
--- /dev/null
+++ b/test/system/610-format.bats
@@ -0,0 +1,169 @@
+#!/usr/bin/env bats -*- bats -*-
+#
+# PR #15673: For all commands that accept --format '{{.GoTemplate}}',
+# invoke with --format '{{"\n"}}' and make sure they don't choke.
+#
+
+load helpers
+
+function teardown() {
+ # In case test fails: standard teardown does not wipe machines or secrets
+ run_podman '?' machine rm -f mymachine
+ run_podman '?' secret rm mysecret
+
+ basic_teardown
+}
+
+# Most commands can't just be run with --format; they need an argument or
+# option. This table defines what those are.
+#
+# FIXME: once you've finished fixing them all, remove the SKIPs (just
+# remove the entire lines, except for pod-inspect, just remove the SKIP
+# but leave "mypod")
+extra_args_table="
+history | $IMAGE
+image history | $IMAGE
+image inspect | $IMAGE
+container inspect | mycontainer
+machine inspect | mymachine
+
+volume inspect | -a
+secret inspect | mysecret
+network inspect | podman
+ps | -a
+
+image search | sdfsdf
+search | sdfsdf
+
+pod inspect | mypod
+
+container stats | --no-stream
+pod stats | --no-stream
+stats | --no-stream
+events | --stream=false --events-backend=file
+"
+
+# Main test loop. Recursively runs 'podman [subcommand] help', looks for:
+# > '[command]', which indicates, recurse; or
+# > '--format', in which case we
+# > check autocompletion, look for Go templates, in which case we
+# > run the command with --format '{{"\n"}}' and make sure it passes
+function check_subcommand() {
+ for cmd in $(_podman_commands "$@"); do
+ # Special case: 'podman machine' can't be run as root. No override.
+ if [[ "$cmd" = "machine" ]]; then
+ if ! is_rootless; then
+ unset extra_args["podman machine inspect"]
+ continue
+ fi
+ fi
+
+ # Human-readable podman command string, with multiple spaces collapsed
+ command_string="podman $* $cmd"
+ command_string=${command_string// / } # 'podman x' -> 'podman x'
+
+ # Run --help, decide if this is a subcommand with subcommands
+ run_podman "$@" $cmd --help
+ local full_help="$output"
+
+ # The line immediately after 'Usage:' gives us a 1-line synopsis
+ usage=$(echo "$full_help" | grep -A1 '^Usage:' | tail -1)
+ assert "$usage" != "" "podman $cmd: no Usage message found"
+
+ # Strip off the leading command string; we no longer need it
+ usage=$(sed -e "s/^ $command_string \?//" <<<"$usage")
+
+ # If usage ends in '[command]', recurse into subcommands
+ if expr "$usage" : '\[command\]' >/dev/null; then
+ # (except for 'podman help', which is a special case)
+ if [[ $cmd != "help" ]]; then
+ check_subcommand "$@" $cmd
+ fi
+ continue
+ fi
+
+ # Not a subcommand-subcommand. Look for --format option
+ if [[ ! "$output" =~ "--format" ]]; then
+ continue
+ fi
+
+ # Have --format. Make sure it's a Go-template option, not like --push
+ run_podman __completeNoDesc "$@" "$cmd" --format '{{.'
+ if [[ ! "$output" =~ \{\{\.[A-Z] ]]; then
+ continue
+ fi
+
+ # Got one.
+ dprint "$command_string has --format"
+
+ # Whatever is needed to make a runnable command
+ local extra=${extra_args[$command_string]}
+ if [[ -n "$extra" ]]; then
+ # Cross off our list
+ unset extra_args["$command_string"]
+ fi
+
+ # This is what does the work. We run with '?' so we can offer
+ # better error messages than just "exited with error status".
+ run_podman '?' "$@" "$cmd" $extra --format '{{"\n"}}'
+
+ # Output must always be empty.
+ #
+ # - If you see "unterminated quoted string" here, there's a
+ # regression, and you need to fix --format (see PR #15673)
+ #
+ # - If you see any other error, it probably means that someone
+ # added a new podman subcommand that supports --format but
+ # needs some sort of option or argument to actually run.
+ # See 'extra_args_table' at the top of this script.
+ #
+ assert "$output" = "" "$command_string --format '{{\"\n\"}}'"
+
+ # *Now* check exit status. This should never, ever, ever trigger!
+ # If it does, it means the podman command failed without an err msg!
+ assert "$status" = "0" \
+ "$command_string --format '{{\"\n\"}}' failed with no output!"
+ done
+}
+
+# Test entry point
+@test "check Go template formatting" {
+ skip_if_remote
+ if is_ubuntu; then
+ skip 'ubuntu VMs do not have qemu (exec: "qemu-system-x86_64": executable file not found in $PATH)'
+ fi
+
+ # Convert the table at top to an associative array, keyed on subcommand
+ declare -A extra_args
+ while read subcommand extra; do
+ extra_args["podman $subcommand"]=$extra
+ done < <(parse_table "$extra_args_table")
+
+ # Setup: some commands need a container, pod, machine, or secret
+ run_podman run -d --name mycontainer $IMAGE top
+ run_podman pod create mypod
+ run_podman secret create mysecret /etc/hosts
+ if is_rootless; then
+ run_podman machine init --image-path=/dev/null mymachine
+ fi
+
+ # Run the test
+ check_subcommand
+
+ # Clean up
+ run_podman pod rm mypod
+ run_podman rmi $(pause_image)
+ run_podman rm -f -t0 mycontainer
+ run_podman secret rm mysecret
+ if is_rootless; then
+ run_podman machine rm -f mymachine
+ fi
+
+ # Make sure there are no leftover commands in our table - this would
+ # indicate a typo in the table, or a flaw in our logic such that
+ # we're not actually recursing.
+ local leftovers="${!extra_args[@]}"
+ assert "$leftovers" = "" "Did not find (or test) subcommands:"
+}
+
+# vim: filetype=sh