diff --git a/cmd/dep/status.go b/cmd/dep/status.go index 238dc967ba..6856fe36a6 100644 --- a/cmd/dep/status.go +++ b/cmd/dep/status.go @@ -9,13 +9,14 @@ import ( "encoding/json" "flag" "fmt" - "html/template" "io" "io/ioutil" "log" "sort" + "strings" "sync" "text/tabwriter" + "text/template" "github.com/golang/dep" "github.com/golang/dep/gps" @@ -23,6 +24,8 @@ import ( "github.com/pkg/errors" ) +const availableTemplateVariables = "ProjectRoot, Constraint, Version, Revision, Latest, and PackageCount." + const statusShortHelp = `Report the status of the project's dependencies` const statusLongHelp = ` With no arguments, print the status of each dependency of the project. @@ -34,9 +37,43 @@ With no arguments, print the status of each dependency of the project. LATEST Latest VCS revision available PKGS USED Number of packages from this project that are actually used +You may use the -f flag to create a custom format for the output of the +dep status command. The available fields you can utilize are as follows: +` + availableTemplateVariables + ` + Status returns exit code zero if all dependencies are in a "good state". ` +const statusExamples = ` +dep status + + Displays a table of the various dependencies in the project along with + their properties such as the constraints they are bound by and the + revision they are at. + +dep status -f='{{if eq .Constraint "master"}}{{.ProjectRoot}} {{end}}' + + Display the list of package names constrained on the master branch. + The -f flag allows you to use Go templates along with it's various + constructs for formating the output data. Available flags are as follows: + ` + availableTemplateVariables + ` + +dep status -json + + Displays the dependency information in JSON format as a list of + project objects. Each project object contains keys which correspond + to the table column names from the standard 'dep status' command. + +Linux: dep status -dot | dot -T png | display +MacOS: dep status -dot | dot -T png | open -f -a /Applications/Preview.app +Windows: dep status -dot | dot -T png -o status.png; start status.png + + Generate a visual representation of the dependency tree using GraphViz. + (Note: in order for this example to work you must first have graphviz + installed on your system) + +` + const ( shortRev uint8 = iota longRev @@ -56,6 +93,7 @@ func (cmd *statusCommand) LongHelp() string { return statusLongHelp } func (cmd *statusCommand) Hidden() bool { return false } func (cmd *statusCommand) Register(fs *flag.FlagSet) { + fs.BoolVar(&cmd.examples, "examples", false, "print detailed usage examples") fs.BoolVar(&cmd.json, "json", false, "output in JSON format") fs.StringVar(&cmd.template, "f", "", "output in text/template format") fs.BoolVar(&cmd.dot, "dot", false, "output the dependency graph in GraphViz format") @@ -64,6 +102,7 @@ func (cmd *statusCommand) Register(fs *flag.FlagSet) { } type statusCommand struct { + examples bool json bool template string output string @@ -200,7 +239,15 @@ func (out *templateOutput) BasicHeader() error { return nil } func (out *templateOutput) BasicFooter() error { return nil } func (out *templateOutput) BasicLine(bs *BasicStatus) error { - return out.tmpl.Execute(out.w, bs) + data := rawStatus{ + ProjectRoot: bs.ProjectRoot, + Constraint: bs.getConsolidatedConstraint(), + Version: bs.getConsolidatedVersion(), + Revision: bs.Revision.String(), + Latest: bs.getConsolidatedLatest(shortRev), + PackageCount: bs.PackageCount, + } + return out.tmpl.Execute(out.w, data) } func (out *templateOutput) MissingHeader() error { return nil } @@ -211,6 +258,11 @@ func (out *templateOutput) MissingLine(ms *MissingStatus) error { } func (cmd *statusCommand) Run(ctx *dep.Ctx, args []string) error { + if cmd.examples { + ctx.Err.Println(strings.TrimSpace(statusExamples)) + return nil + } + if err := cmd.validateFlags(); err != nil { return err } diff --git a/cmd/dep/status_test.go b/cmd/dep/status_test.go index b8b3aea9a3..9285b5a547 100644 --- a/cmd/dep/status_test.go +++ b/cmd/dep/status_test.go @@ -13,6 +13,7 @@ import ( "strings" "testing" "text/tabwriter" + "text/template" "github.com/golang/dep" "github.com/golang/dep/gps" @@ -41,21 +42,28 @@ func TestBasicLine(t *testing.T) { project := dep.Project{} aSemverConstraint, _ := gps.NewSemverConstraint("1.2.3") + templateString := "PR:{{.ProjectRoot}}, Const:{{.Constraint}}, Ver:{{.Version}}, Rev:{{.Revision}}, Lat:{{.Latest}}, PkgCt:{{.PackageCount}}" + equalityTestTemplate := `{{if eq .Constraint "1.2.3"}}Constraint is 1.2.3{{end}}|{{if eq .Version "flooboo"}}Version is flooboo{{end}}|{{if eq .Latest "unknown"}}Latest is unknown{{end}}` + tests := []struct { - name string - status BasicStatus - wantDotStatus []string - wantJSONStatus []string - wantTableStatus []string + name string + status BasicStatus + wantDotStatus []string + wantJSONStatus []string + wantTableStatus []string + wantTemplateStatus []string + wantEqTemplateStatus []string }{ { name: "BasicStatus with ProjectRoot only", status: BasicStatus{ ProjectRoot: "github.com/foo/bar", }, - wantDotStatus: []string{`[label="github.com/foo/bar"];`}, - wantJSONStatus: []string{`"Version":""`, `"Revision":""`}, - wantTableStatus: []string{`github.com/foo/bar 0`}, + wantDotStatus: []string{`[label="github.com/foo/bar"];`}, + wantJSONStatus: []string{`"Version":""`, `"Revision":""`}, + wantTableStatus: []string{`github.com/foo/bar 0`}, + wantTemplateStatus: []string{`PR:github.com/foo/bar, Const:, Ver:, Rev:, Lat:, PkgCt:0`}, + wantEqTemplateStatus: []string{`||`}, }, { name: "BasicStatus with Revision", @@ -63,9 +71,11 @@ func TestBasicLine(t *testing.T) { ProjectRoot: "github.com/foo/bar", Revision: gps.Revision("flooboofoobooo"), }, - wantDotStatus: []string{`[label="github.com/foo/bar\nflooboo"];`}, - wantJSONStatus: []string{`"Version":""`, `"Revision":"flooboofoobooo"`, `"Constraint":""`}, - wantTableStatus: []string{`github.com/foo/bar flooboo 0`}, + wantDotStatus: []string{`[label="github.com/foo/bar\nflooboo"];`}, + wantJSONStatus: []string{`"Version":""`, `"Revision":"flooboofoobooo"`, `"Constraint":""`}, + wantTableStatus: []string{`github.com/foo/bar flooboo 0`}, + wantTemplateStatus: []string{`PR:github.com/foo/bar, Const:, Ver:flooboo, Rev:flooboofoobooo, Lat:, PkgCt:0`}, + wantEqTemplateStatus: []string{`|Version is flooboo|`}, }, { name: "BasicStatus with Version and Revision", @@ -74,9 +84,11 @@ func TestBasicLine(t *testing.T) { Version: gps.NewVersion("1.0.0"), Revision: gps.Revision("flooboofoobooo"), }, - wantDotStatus: []string{`[label="github.com/foo/bar\n1.0.0"];`}, - wantJSONStatus: []string{`"Version":"1.0.0"`, `"Revision":"flooboofoobooo"`, `"Constraint":""`}, - wantTableStatus: []string{`github.com/foo/bar 1.0.0 flooboo 0`}, + wantDotStatus: []string{`[label="github.com/foo/bar\n1.0.0"];`}, + wantJSONStatus: []string{`"Version":"1.0.0"`, `"Revision":"flooboofoobooo"`, `"Constraint":""`}, + wantTableStatus: []string{`github.com/foo/bar 1.0.0 flooboo 0`}, + wantTemplateStatus: []string{`PR:github.com/foo/bar, Const:, Ver:1.0.0, Rev:flooboofoobooo, Lat:, PkgCt:0`}, + wantEqTemplateStatus: []string{`||`}, }, { name: "BasicStatus with Constraint, Version and Revision", @@ -86,9 +98,11 @@ func TestBasicLine(t *testing.T) { Version: gps.NewVersion("1.0.0"), Revision: gps.Revision("revxyz"), }, - wantDotStatus: []string{`[label="github.com/foo/bar\n1.0.0"];`}, - wantJSONStatus: []string{`"Revision":"revxyz"`, `"Constraint":"1.2.3"`, `"Version":"1.0.0"`}, - wantTableStatus: []string{`github.com/foo/bar 1.2.3 1.0.0 revxyz 0`}, + wantDotStatus: []string{`[label="github.com/foo/bar\n1.0.0"];`}, + wantJSONStatus: []string{`"Revision":"revxyz"`, `"Constraint":"1.2.3"`, `"Version":"1.0.0"`}, + wantTableStatus: []string{`github.com/foo/bar 1.2.3 1.0.0 revxyz 0`}, + wantTemplateStatus: []string{`PR:github.com/foo/bar, Const:1.2.3, Ver:1.0.0, Rev:revxyz, Lat:, PkgCt:0`}, + wantEqTemplateStatus: []string{`Constraint is 1.2.3||`}, }, { name: "BasicStatus with update error", @@ -96,9 +110,11 @@ func TestBasicLine(t *testing.T) { ProjectRoot: "github.com/foo/bar", hasError: true, }, - wantDotStatus: []string{`[label="github.com/foo/bar"];`}, - wantJSONStatus: []string{`"Version":""`, `"Revision":""`, `"Latest":"unknown"`}, - wantTableStatus: []string{`github.com/foo/bar unknown 0`}, + wantDotStatus: []string{`[label="github.com/foo/bar"];`}, + wantJSONStatus: []string{`"Version":""`, `"Revision":""`, `"Latest":"unknown"`}, + wantTableStatus: []string{`github.com/foo/bar unknown 0`}, + wantTemplateStatus: []string{`PR:github.com/foo/bar, Const:, Ver:, Rev:, Lat:unknown, PkgCt:0`}, + wantEqTemplateStatus: []string{`||Latest is unknown`}, }, } @@ -149,6 +165,33 @@ func TestBasicLine(t *testing.T) { t.Errorf("Did not find expected Table status: \n\t(GOT) %v \n\t(WNT) %v", buf.String(), wantStatus) } } + + buf.Reset() + template, _ := template.New("status").Parse(templateString) + templateout := &templateOutput{w: &buf, tmpl: template} + templateout.BasicHeader() + templateout.BasicLine(&test.status) + templateout.BasicFooter() + + for _, wantStatus := range test.wantTemplateStatus { + if ok := strings.Contains(buf.String(), wantStatus); !ok { + t.Errorf("Did not find expected template status: \n\t(GOT) %v \n\t(WNT) %v", buf.String(), wantStatus) + } + } + + // The following test is to ensure that certain fields usable with string operations such as .eq + buf.Reset() + template, _ = template.New("status").Parse(equalityTestTemplate) + templateout = &templateOutput{w: &buf, tmpl: template} + templateout.BasicHeader() + templateout.BasicLine(&test.status) + templateout.BasicFooter() + + for _, wantStatus := range test.wantEqTemplateStatus { + if ok := strings.Contains(buf.String(), wantStatus); !ok { + t.Errorf("Did not find expected template status: \n\t(GOT) %v \n\t(WNT) %v", buf.String(), wantStatus) + } + } }) } }