Merge pull request #386 from Masterminds/fix/help-indentation

Fixed help text display indentation
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/action/project_info.go b/action/project_info.go
new file mode 100644
index 0000000..5e0995e
--- /dev/null
+++ b/action/project_info.go
@@ -0,0 +1,39 @@
+package action
+
+import (
+	"bytes"
+
+	"github.com/Masterminds/glide/msg"
+)
+
+func Info(format string) {
+	conf := EnsureConfig()
+	var buffer bytes.Buffer
+	varInit := false
+	for _, var_format := range format {
+		if varInit {
+			switch var_format {
+			case 'n':
+				buffer.WriteString(conf.Name)
+			case 'd':
+				buffer.WriteString(conf.Description)
+			case 'h':
+				buffer.WriteString(conf.Home)
+			case 'l':
+				buffer.WriteString(conf.License)
+			default:
+				msg.Die("Invalid format %s", string(var_format))
+			}
+		} else {
+			switch var_format {
+			case '%':
+				varInit = true
+				continue
+			default:
+				buffer.WriteString(string(var_format))
+			}
+		}
+		varInit = false
+	}
+	msg.Puts(buffer.String())
+}
diff --git a/glide.go b/glide.go
index d6220fa..e205796 100644
--- a/glide.go
+++ b/glide.go
@@ -52,7 +52,7 @@
 	"os/user"
 )
 
-var version = "0.10.2"
+var version = "0.11.0-dev"
 
 const usage = `The lightweight vendor package manager for your Go projects.
 
@@ -587,7 +587,56 @@
    Directories that begin with . or _ are ignored, as are testdata directories. Packages in
    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",
+				},
+			},
+		},
+		{
+			Name:  "info",
+			Usage: "Info prints information about this project",
+			Flags: []cli.Flag{
+				cli.StringFlag{
+					Name:  "format, f",
+					Usage: `Format of the information wanted (required).`,
+				},
+			},
+			Description: `A format containing the text with replacement variables
+   has to be passed in. Those variables are:
+
+       %n - name
+       %d - description
+       %h - homepage
+       %l - license
+
+   For example, given a project with the following glide.yaml:
+
+       package: foo
+       homepage: https://example.com
+       license: MIT
+       description: Some example description
+
+   Then running the following commands:
+
+       glide info -f %n
+          prints 'foo'
+
+       glide info -f "License: %l"
+          prints 'License: MIT'
+
+       glide info -f "%n - %d - %h - %l"
+          prints 'foo - Some example description - https://example.com - MIT'`,
+			Action: func(c *cli.Context) {
+				if c.IsSet("format") {
+					action.Info(c.String("format"))
+				} else {
+					cli.ShowCommandHelp(c, c.Command.Name)
+				}
 			},
 		},
 		{