From ca53122338168c867e75de0ce832d80ac7f27428 Mon Sep 17 00:00:00 2001
From: baude <bbaude@redhat.com>
Date: Tue, 29 Jan 2019 15:12:29 -0600
Subject: [PATCH] Fix regression in ps with custom format

Using the table keyword in go templating had regressed and was
no longer working.

Fixes: 2221

Signed-off-by: baude <bbaude@redhat.com>
---
 cmd/podman/images.go |  7 -------
 cmd/podman/ps.go     | 41 ++++++++++++++++++++++++++++++++++++-----
 test/e2e/ps_test.go  |  7 +++++--
 3 files changed, 41 insertions(+), 14 deletions(-)

diff --git a/cmd/podman/images.go b/cmd/podman/images.go
index 031f06618e..d4f405975a 100644
--- a/cmd/podman/images.go
+++ b/cmd/podman/images.go
@@ -188,13 +188,6 @@ func imagesCmd(c *cli.Context) error {
 	}
 
 	opts.outputformat = opts.setOutputFormat()
-	/*
-		podman does not implement --all for images
-
-		intermediate images are only generated during the build process.  they are
-		children to the image once built. until buildah supports caching builds,
-		it will not generate these intermediate images.
-	*/
 	images, err := runtime.GetImages()
 	if err != nil {
 		return errors.Wrapf(err, "unable to get images")
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index 0ad3f4c735..1708c671cf 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -606,19 +606,50 @@ func portsToString(ports []ocicni.PortMapping) string {
 }
 
 func printFormat(format string, containers []shared.PsContainerOutput) error {
-	out := template.New("output")
-	out, err := out.Parse(format + "\n")
+	// return immediately if no containers are present
+	if len(containers) == 0 {
+		return nil
+	}
 
+	// Use a tabwriter to align column format
+	w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
+
+	// Make a map of the field names for the headers
+	headerNames := make(map[string]string)
+	v := reflect.ValueOf(containers[0])
+	t := v.Type()
+	for i := 0; i < t.NumField(); i++ {
+		headerNames[t.Field(i).Name] = t.Field(i).Name
+	}
+
+	// Spit out the header if "table" is present in the format
+	if strings.HasPrefix(format, "table") {
+		hformat := strings.Replace(strings.TrimSpace(format[5:]), " ", "\t", -1)
+		format = hformat
+		headerTmpl, err := template.New("header").Parse(hformat)
+		if err != nil {
+			return err
+		}
+		if err := headerTmpl.Execute(w, headerNames); err != nil {
+			return err
+		}
+		fmt.Fprintln(w, "")
+	}
+
+	// Spit out the data rows now
+	dataTmpl, err := template.New("data").Parse(format)
 	if err != nil {
 		return err
 	}
+
 	for _, container := range containers {
-		if err := out.Execute(os.Stdout, container); err != nil {
+		if err := dataTmpl.Execute(w, container); err != nil {
 			return err
 		}
-
+		fmt.Fprintln(w, "")
 	}
-	return nil
+	// Flush the writer
+	return w.Flush()
 }
 
 func dumpJSON(containers []shared.PsContainerOutput) error {
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index bff2427d55..9b1c55bb41 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -7,6 +7,7 @@ import (
 	"os"
 	"regexp"
 	"sort"
+	"strings"
 
 	. "github.com/containers/libpod/test/utils"
 	"github.com/docker/go-units"
@@ -148,10 +149,12 @@ var _ = Describe("Podman ps", func() {
 		_, ec, _ := podmanTest.RunLsContainer("test1")
 		Expect(ec).To(Equal(0))
 
-		result := podmanTest.Podman([]string{"ps", "-a", "--format", "\"table {{.ID}} {{.Image}} {{.Labels}}\""})
+		result := podmanTest.Podman([]string{"ps", "-a", "--format", "table {{.ID}} {{.Image}} {{.Labels}}"})
 		result.WaitWithDefaultTimeout()
+		Expect(strings.Contains(result.OutputToStringArray()[0], "table")).To(BeFalse())
+		Expect(strings.Contains(result.OutputToStringArray()[0], "ID")).To(BeTrue())
+		Expect(strings.Contains(result.OutputToStringArray()[1], "alpine:latest")).To(BeTrue())
 		Expect(result.ExitCode()).To(Equal(0))
-		Expect(result.IsJSONOutputValid()).To(BeTrue())
 	})
 
 	It("podman ps ancestor filter flag", func() {