Merge pull request #365 from chancez/add_list_format
diff --git a/action/list.go b/action/list.go
index a2d35c7..8ff6c69 100644
--- a/action/list.go
+++ b/action/list.go
@@ -1,6 +1,7 @@
 package action
 
 import (
+	"encoding/json"
 	"path/filepath"
 	"sort"
 
@@ -13,8 +14,8 @@
 // Params:
 //  - dir (string): basedir
 //  - deep (bool): whether to do a deep scan or a shallow scan
-func List(basedir string, deep bool) {
-
+//  - format (string): The format to output (text, json, json-pretty)
+func List(basedir string, deep bool, format string) {
 	basedir, err := filepath.Abs(basedir)
 	if err != nil {
 		msg.Die("Could not read directory: %s", err)
@@ -27,34 +28,71 @@
 	h := &dependency.DefaultMissingPackageHandler{Missing: []string{}, Gopath: []string{}}
 	r.Handler = h
 
-	sortable, err := r.ResolveLocal(deep)
+	localPkgs, err := r.ResolveLocal(deep)
 	if err != nil {
 		msg.Die("Error listing dependencies: %s", err)
 	}
-
-	msg.Info("Sorting...")
-	sort.Strings(sortable)
-
-	msg.Puts("INSTALLED packages:")
-	for _, k := range sortable {
-		v, err := filepath.Rel(basedir, k)
+	sort.Strings(localPkgs)
+	installed := make([]string, len(localPkgs))
+	for i, pkg := range localPkgs {
+		relPkg, err := filepath.Rel(basedir, pkg)
 		if err != nil {
-			//msg.Warn("Failed to Rel path: %s", err)
-			v = k
+			// msg.Warn("Failed to Rel path: %s", err)
+			relPkg = pkg
 		}
-		msg.Puts("\t%s", v)
+		installed[i] = relPkg
+	}
+	l := PackageList{
+		Installed: installed,
+		Missing:   h.Missing,
+		Gopath:    h.Gopath,
 	}
 
-	if len(h.Missing) > 0 {
-		msg.Puts("\nMISSING packages:")
-		for _, pkg := range h.Missing {
+	outputList(l, format)
+}
+
+// PackageList contains the packages being used by their location
+type PackageList struct {
+	Installed []string `json:"installed"`
+	Missing   []string `json:"missing"`
+	Gopath    []string `json:"gopath"`
+}
+
+const (
+	textFormat       = "text"
+	jsonFormat       = "json"
+	jsonPrettyFormat = "json-pretty"
+)
+
+func outputList(l PackageList, format string) {
+	switch format {
+	case textFormat:
+		msg.Puts("INSTALLED packages:")
+		for _, pkg := range l.Installed {
 			msg.Puts("\t%s", pkg)
 		}
-	}
-	if len(h.Gopath) > 0 {
-		msg.Puts("\nGOPATH packages:")
-		for _, pkg := range h.Gopath {
-			msg.Puts("\t%s", pkg)
+
+		if len(l.Missing) > 0 {
+			msg.Puts("\nMISSING packages:")
+			for _, pkg := range l.Missing {
+				msg.Puts("\t%s", pkg)
+			}
 		}
+		if len(l.Gopath) > 0 {
+			msg.Puts("\nGOPATH packages:")
+			for _, pkg := range l.Gopath {
+				msg.Puts("\t%s", pkg)
+			}
+		}
+	case jsonFormat:
+		json.NewEncoder(msg.Default.Stdout).Encode(l)
+	case jsonPrettyFormat:
+		b, err := json.MarshalIndent(l, "", "  ")
+		if err != nil {
+			msg.Die("could not unmarshal package list: %s", err)
+		}
+		msg.Puts(string(b))
+	default:
+		msg.Die("invalid output format: must be one of: json|json-pretty|text")
 	}
 }
diff --git a/action/list_test.go b/action/list_test.go
index 6792210..69e3eaf 100644
--- a/action/list_test.go
+++ b/action/list_test.go
@@ -2,20 +2,49 @@
 
 import (
 	"bytes"
+	"encoding/json"
 	"testing"
 
 	"github.com/Masterminds/glide/msg"
 )
 
 func TestList(t *testing.T) {
-	var buf bytes.Buffer
-	old := msg.Default.Stdout
 	msg.Default.PanicOnDie = true
+	old := msg.Default.Stdout
+	defer func() {
+		msg.Default.Stdout = old
+	}()
+
+	var buf bytes.Buffer
 	msg.Default.Stdout = &buf
-	List("../", false)
+	List("../", false, "text")
 	if buf.Len() < 5 {
 		t.Error("Expected some data to be found.")
 	}
-	// TODO: We should capture and test output.
-	msg.Default.Stdout = old
+
+	var buf2 bytes.Buffer
+	msg.Default.Stdout = &buf2
+	List("../", false, "json")
+	j := buf2.Bytes()
+	var o PackageList
+	err := json.Unmarshal(j, &o)
+	if err != nil {
+		t.Errorf("Error unmarshaling json list: %s", err)
+	}
+	if len(o.Installed) == 0 {
+		t.Error("No packages found on json list")
+	}
+
+	var buf3 bytes.Buffer
+	msg.Default.Stdout = &buf3
+	List("../", false, "json-pretty")
+	j = buf3.Bytes()
+	var o2 PackageList
+	err = json.Unmarshal(j, &o2)
+	if err != nil {
+		t.Errorf("Error unmarshaling json-pretty list: %s", err)
+	}
+	if len(o2.Installed) == 0 {
+		t.Error("No packages found on json-pretty list")
+	}
 }
diff --git a/glide.go b/glide.go
index 2981837..f0647e4 100644
--- a/glide.go
+++ b/glide.go
@@ -592,7 +592,14 @@
 			vendor are only included if they are used by the project.
 			`,
 			Action: func(c *cli.Context) {
-				action.List(".", true)
+				action.List(".", true, c.String("output"))
+			},
+			Flags: []cli.Flag{
+				cli.StringFlag{
+					Name:  "output, o",
+					Usage: "Output format. One of: json|json-pretty|text",
+					Value: "text",
+				},
 			},
 		},
 		{