Skip to content
This repository was archived by the owner on Sep 9, 2020. It is now read-only.

Implement missing flag for dep status #1870

Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Implement missing flag for dep status
Comply with command spec by making dep status -missing
list the dependencies that are missing from the lock file
but are used in the project. Issue #1382.
tinnefeld committed Jul 8, 2018
commit 391e768af268da865414c724ed7a764b09259c9a
80 changes: 66 additions & 14 deletions cmd/dep/status.go
Original file line number Diff line number Diff line change
@@ -119,6 +119,9 @@ type outputter interface {
MissingHeader() error
MissingLine(*MissingStatus) error
MissingFooter() error
StatusMissingHeader() error
StatusMissingLine(gps.ProjectRoot) error
StatusMissingFooter() error
}

// Only a subset of the outputters should be able to output old statuses.
@@ -170,6 +173,20 @@ func (out *tableOutput) MissingFooter() error {
return out.w.Flush()
}

func (out *tableOutput) StatusMissingHeader() error {
_, err := fmt.Fprintln(out.w, "Missing dependencies (not present in lock):")
return err
}

func (out *tableOutput) StatusMissingLine(missingDep gps.ProjectRoot) error {
_, err := fmt.Fprintf(out.w, " %v\n", missingDep)
return err
}

func (out *tableOutput) StatusMissingFooter() error {
return out.w.Flush()
}

func (out *tableOutput) OldHeader() error {
_, err := fmt.Fprintf(out.w, "PROJECT\tCONSTRAINT\tREVISION\tLATEST\n")
return err
@@ -191,10 +208,11 @@ func (out *tableOutput) OldFooter() error {
}

type jsonOutput struct {
w io.Writer
basic []*rawStatus
missing []*MissingStatus
old []*rawOldStatus
w io.Writer
basic []*rawStatus
missing []*MissingStatus
statusMissing []struct{ ProjectRoot gps.ProjectRoot }
old []*rawOldStatus
}

func (out *jsonOutput) BasicHeader() error {
@@ -225,6 +243,21 @@ func (out *jsonOutput) MissingFooter() error {
return json.NewEncoder(out.w).Encode(out.missing)
}

func (out *jsonOutput) StatusMissingHeader() error {
out.statusMissing = []struct{ ProjectRoot gps.ProjectRoot }{}
return nil
}

func (out *jsonOutput) StatusMissingLine(missingDep gps.ProjectRoot) error {
out.statusMissing = append(out.statusMissing,
struct{ ProjectRoot gps.ProjectRoot }{missingDep})
return nil
}

func (out *jsonOutput) StatusMissingFooter() error {
return json.NewEncoder(out.w).Encode(out.statusMissing)
}

func (out *jsonOutput) OldHeader() error {
out.old = []*rawOldStatus{}
return nil
@@ -269,9 +302,12 @@ func (out *dotOutput) BasicLine(bs *BasicStatus) error {
return nil
}

func (out *dotOutput) MissingHeader() error { return nil }
func (out *dotOutput) MissingLine(ms *MissingStatus) error { return nil }
func (out *dotOutput) MissingFooter() error { return nil }
func (out *dotOutput) MissingHeader() error { return nil }
func (out *dotOutput) MissingLine(ms *MissingStatus) error { return nil }
func (out *dotOutput) MissingFooter() error { return nil }
func (out *dotOutput) StatusMissingHeader() error { return nil }
func (out *dotOutput) StatusMissingLine(missingDep gps.ProjectRoot) error { return nil }
func (out *dotOutput) StatusMissingFooter() error { return nil }

type templateOutput struct {
w io.Writer
@@ -303,6 +339,12 @@ func (out *templateOutput) MissingFooter() error { return nil }
func (out *templateOutput) MissingLine(ms *MissingStatus) error {
return out.tmpl.Execute(out.w, ms)
}
func (out *templateOutput) StatusMissingHeader() error { return nil }
func (out *templateOutput) StatusMissingLine(missingDep gps.ProjectRoot) error {
t := struct{ ProjectRoot gps.ProjectRoot }{missingDep}
return out.tmpl.Execute(out.w, t)
}
func (out *templateOutput) StatusMissingFooter() error { return nil }

func (cmd *statusCommand) Run(ctx *dep.Ctx, args []string) error {
if cmd.examples {
@@ -373,7 +415,10 @@ func (cmd *statusCommand) Run(ctx *dep.Ctx, args []string) error {
}

if cmd.missing {
err := cmd.runStatusMissing(ctx, p)
err := cmd.runStatusMissing(ctx, out, p)
if len(buf.String()) > 0 {
ctx.Out.Print(buf.String())
}
return err
}

@@ -491,7 +536,7 @@ func (os OldStatus) marshalJSON() *rawOldStatus {
}

// runStatusMissing analyses the project for missing dependencies in lock file.
func (cmd *statusCommand) runStatusMissing(ctx *dep.Ctx, p *dep.Project) error {
func (cmd *statusCommand) runStatusMissing(ctx *dep.Ctx, out outputter, p *dep.Project) error {

ptree, err := p.ParseRootPackageTree()
if err != nil {
@@ -500,7 +545,7 @@ func (cmd *statusCommand) runStatusMissing(ctx *dep.Ctx, p *dep.Project) error {
rm, _ := ptree.ToReachMap(true, true, false, p.Manifest.IgnoredPackages())
external := rm.FlattenFn(paths.IsStandardImportPath)

var missingDeps []string
var missingDeps []gps.ProjectRoot

missingOuter:
for _, d := range external {
@@ -510,16 +555,23 @@ missingOuter:
}
}

missingDeps = append(missingDeps, d)
missingDeps = append(missingDeps, gps.ProjectRoot(d))
}

if missingDeps != nil {
ctx.Err.Printf("Missing dependencies (not present in lock):\n")
if err = out.StatusMissingHeader(); err != nil {
return err
}
for _, d := range missingDeps {
ctx.Err.Printf(" %v\n", d)
if err = out.StatusMissingLine(d); err != nil {
return err
}
}
if err = out.StatusMissingFooter(); err != nil {
return err
}
} else {
ctx.Err.Println("No missing dependencies found.")
ctx.Err.Printf("No missing dependencies found.")
}

return nil
88 changes: 64 additions & 24 deletions cmd/dep/status_test.go
Original file line number Diff line number Diff line change
@@ -560,10 +560,13 @@ func TestValidateFlags(t *testing.T) {
func TestStatusMissing(t *testing.T) {

cases := []struct {
name string
lock dep.Lock
wantStatus string
wantErr bool
name string
lock dep.Lock
cmds []statusCommand
wantTableStatus string
wantJSONStatus string
wantTemplateStatus string
wantErr bool
}{
{
name: "no missing dependencies",
@@ -586,7 +589,10 @@ func TestStatusMissing(t *testing.T) {
),
},
},
wantStatus: "No missing dependencies found.\n",
cmds: []statusCommand{
statusCommand{missing: true}, //default for table output
},
wantTableStatus: "No missing dependencies found.\n",
},
{
name: "two missing dependencies",
@@ -599,9 +605,16 @@ func TestStatusMissing(t *testing.T) {
),
},
},
wantStatus: "Missing dependencies (not present in lock):\n" +
cmds: []statusCommand{
statusCommand{missing: true}, //default for table output
statusCommand{missing: true, json: true},
statusCommand{missing: true, template: "Missing:{{.ProjectRoot}} "},
},
wantTableStatus: "Missing dependencies (not present in lock):\n" +
" github.com/boltdb/bolt\n" +
" github.com/sdboyer/dep-test\n",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use back tick (`) as well if you would like to avoid appending with + and \n.

wantJSONStatus: `[{"ProjectRoot":"github.com/boltdb/bolt"},{"ProjectRoot":"github.com/sdboyer/dep-test"}]` + "\n",
wantTemplateStatus: "Missing:github.com/boltdb/bolt Missing:github.com/sdboyer/dep-test \n",
},
}

@@ -613,14 +626,13 @@ func TestStatusMissing(t *testing.T) {
h.TempCopy(filepath.Join(testdir, "main.go"), filepath.Join("status", "missing", "main.go"))
testProjPath := h.Path(testdir)

var buf bytes.Buffer
bufferWriter := bufio.NewWriter(&buf)
var bufW bytes.Buffer
bufferWriter := bufio.NewWriter(&bufW)
bufferLogger := log.New(bufferWriter, "", 0)
discardLogger := log.New(ioutil.Discard, "", 0)

ctx := &dep.Ctx{
GOPATH: testProjPath,
Out: discardLogger,
Out: bufferLogger,
Err: bufferLogger,
}

@@ -631,25 +643,53 @@ func TestStatusMissing(t *testing.T) {
p := new(dep.Project)
p.SetRoot(testProjPath)

cmd := statusCommand{
missing: true,
}
var bufO bytes.Buffer
var out outputter

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
buf.Reset()
p.Manifest = &dep.Manifest{} // needed for empty Ignored packages string
p.Lock = &c.lock

err = cmd.runStatusMissing(ctx, p)
bufferWriter.Flush()
actualStatus := buf.String()
for _, statusCmd := range c.cmds {
bufO.Reset()
bufW.Reset()

var wantStatus string
switch {
case statusCmd.json:
out = &jsonOutput{
w: &bufO,
}
wantStatus = c.wantJSONStatus
case statusCmd.template != "":
tmpl, _ := template.New("status").Parse(statusCmd.template)
out = &templateOutput{
w: &bufO,
tmpl: tmpl,
}
wantStatus = c.wantTemplateStatus
default:
out = &tableOutput{
w: tabwriter.NewWriter(&bufO, 0, 4, 2, ' ', 0),
}
wantStatus = c.wantTableStatus
}

if err != nil && !c.wantErr {
t.Fatalf("unexpected errors while collecting constraints: %v", err)
}
if actualStatus != c.wantStatus {
t.Fatalf("unexpected missign status: \n\t(GOT): %v\n\t(WNT): %v", actualStatus, c.wantStatus)
p.Manifest = &dep.Manifest{} // needed for empty Ignored packages string
p.Lock = &c.lock

err = statusCmd.runStatusMissing(ctx, out, p)
if len(bufO.String()) > 0 {
ctx.Out.Print(bufO.String())
}
bufferWriter.Flush()
actualStatus := bufW.String()

if err != nil && !c.wantErr {
t.Fatalf("unexpected errors while collecting constraints: %v", err)
}
if actualStatus != wantStatus {
t.Fatalf("unexpected missing status: \n\t(GOT): %v\n\t(WNT): %v", actualStatus, wantStatus)
}
}
})
}
3 changes: 2 additions & 1 deletion cmd/dep/testdata/status/missing/main.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

@@ -10,4 +10,5 @@ import (
_ "github.com/sdboyer/deptestdos"
)

// FooBar is a dummy type
type FooBar int