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

Commit

Permalink
status: return slice of error from collectConstraints()
Browse files Browse the repository at this point in the history
Errors from collectConstraints() should not result in failure of status.
These errors are logged to stderr and the error count is added to
`errCount` of `runStatusAll()`. This results in letting the user know
about incomplete status result, keeping the status output clean. Running
status in verbose mode would show all those errors.
  • Loading branch information
darkowlzz committed Dec 6, 2017
1 parent 73ca5d9 commit e8a2617
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 55 deletions.
30 changes: 20 additions & 10 deletions cmd/dep/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,12 @@ func runStatusAll(ctx *dep.Ctx, out outputter, p *dep.Project, sm gps.SourceMana
return false, 0, errors.Wrapf(err, "could not set up solver for input hashing")
}

cm := collectConstraints(ctx, p, sm)
// Errors while collecting constraints should not fail the whole status run.
// It should count the error and tell the user about incomplete results.
cm, ccerrs := collectConstraints(ctx, p, sm)
if len(ccerrs) > 0 {
errCount += len(ccerrs)
}

// Get the project list and sort it so that the printed output users see is
// deterministically ordered. (This may be superfluous if the lock is always
Expand Down Expand Up @@ -566,7 +571,7 @@ func runStatusAll(ctx *dep.Ctx, out outputter, p *dep.Project, sm gps.SourceMana

// Count ListVersions error because we get partial results when
// this happens.
errCount = len(errListVerCh)
errCount += len(errListVerCh)
if ctx.Verbose {
for err := range errListVerCh {
ctx.Err.Println(err.Error())
Expand Down Expand Up @@ -684,28 +689,31 @@ type projectConstraint struct {
type constraintsCollection map[string][]projectConstraint

// collectConstraints collects constraints declared by all the dependencies.
func collectConstraints(ctx *dep.Ctx, p *dep.Project, sm gps.SourceManager) constraintsCollection {
// It returns constraintsCollection and a slice of errors encountered while
// collecting the constraints, if any.
func collectConstraints(ctx *dep.Ctx, p *dep.Project, sm gps.SourceManager) (constraintsCollection, []error) {
logger := ctx.Err
if !ctx.Verbose {
logger = log.New(ioutil.Discard, "", 0)
}

logger.Println("Collecting project constraints:")

var mutex sync.Mutex
constraintCollection := make(constraintsCollection)

// Get direct deps of the root project.
_, directDeps, err := getDirectDependencies(sm, p)
if err != nil {
logger.Println("Error getting direct deps:", err)
// Return empty collection, not nil, if we fail here.
return constraintCollection, []error{errors.Wrap(err, "failed to get direct dependencies")}
}

// Create a root analyzer.
rootAnalyzer := newRootAnalyzer(true, ctx, directDeps, sm)

lp := p.Lock.Projects()

var mutex sync.Mutex
constraintCollection := make(constraintsCollection)

// Channel for receiving all the errors.
errCh := make(chan error, len(lp))

Expand Down Expand Up @@ -750,13 +758,15 @@ func collectConstraints(ctx *dep.Ctx, p *dep.Project, sm gps.SourceManager) cons
wg.Wait()
close(errCh)

var errs []error
if len(errCh) > 0 {
for err := range errCh {
logger.Println(err.Error())
for e := range errCh {
errs = append(errs, e)
logger.Println(e.Error())
}
}

return constraintCollection
return constraintCollection, errs
}

type byProject []projectConstraint
Expand Down
98 changes: 53 additions & 45 deletions cmd/dep/status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"bytes"
"io/ioutil"
"log"
"path/filepath"
"reflect"
"testing"
"text/tabwriter"
Expand Down Expand Up @@ -299,45 +300,42 @@ func TestCollectConstraints(t *testing.T) {

cases := []struct {
name string
project dep.Project
lock dep.Lock
wantConstraints constraintsCollection
wantErr bool
}{
{
name: "without any constraints",
project: dep.Project{
Lock: &dep.Lock{
P: []gps.LockedProject{
gps.NewLockedProject(
gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/sdboyer/deptest")},
gps.NewVersion("v1.0.0"),
[]string{"."},
),
},
lock: dep.Lock{
P: []gps.LockedProject{
gps.NewLockedProject(
gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/sdboyer/deptest")},
gps.NewVersion("v1.0.0"),
[]string{"."},
),
},
},
wantConstraints: constraintsCollection{},
},
{
name: "with multiple constraints",
project: dep.Project{
Lock: &dep.Lock{
P: []gps.LockedProject{
gps.NewLockedProject(
gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/sdboyer/deptest")},
gps.NewVersion("v1.0.0"),
[]string{"."},
),
gps.NewLockedProject(
gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-1")},
gps.NewVersion("v0.1.0"),
[]string{"."},
),
gps.NewLockedProject(
gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-2")},
gps.NewBranch("master").Pair(gps.Revision("824a8d56a4c6b2f4718824a98cd6d70d3dbd4c3e")),
[]string{"."},
),
},
lock: dep.Lock{
P: []gps.LockedProject{
gps.NewLockedProject(
gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/sdboyer/deptest")},
gps.NewVersion("v1.0.0"),
[]string{"."},
),
gps.NewLockedProject(
gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-1")},
gps.NewVersion("v0.1.0"),
[]string{"."},
),
gps.NewLockedProject(
gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-2")},
gps.NewBranch("master").Pair(gps.Revision("824a8d56a4c6b2f4718824a98cd6d70d3dbd4c3e")),
[]string{"."},
),
},
},
wantConstraints: constraintsCollection{
Expand All @@ -355,27 +353,26 @@ func TestCollectConstraints(t *testing.T) {
},
{
name: "skip projects with invalid versions",
project: dep.Project{
Lock: &dep.Lock{
P: []gps.LockedProject{
gps.NewLockedProject(
gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-1")},
gps.NewVersion("v0.1.0"),
[]string{"."},
),
gps.NewLockedProject(
gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-2")},
gps.NewVersion("v1.0.0"),
[]string{"."},
),
},
lock: dep.Lock{
P: []gps.LockedProject{
gps.NewLockedProject(
gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-1")},
gps.NewVersion("v0.1.0"),
[]string{"."},
),
gps.NewLockedProject(
gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot("github.com/darkowlzz/deptest-project-2")},
gps.NewVersion("v1.0.0"),
[]string{"."},
),
},
},
wantConstraints: constraintsCollection{
"github.com/sdboyer/deptest": []projectConstraint{
{"github.com/darkowlzz/deptest-project-1", ver1},
},
},
wantErr: true,
},
}

Expand All @@ -396,12 +393,23 @@ func TestCollectConstraints(t *testing.T) {
h.Must(err)
defer sm.Release()

// Create new project and set root. Setting root is required for PackageList
// to run properly.
p := new(dep.Project)
p.SetRoot(filepath.Join(pwd, "src"))

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
gotConstraints := collectConstraints(ctx, &c.project, sm)
p.Lock = &c.lock
gotConstraints, err := collectConstraints(ctx, p, sm)
if len(err) > 0 && !c.wantErr {
t.Fatalf("unexpected errors while collecting constraints: %v", err)
} else if len(err) == 0 && c.wantErr {
t.Fatalf("expected errors while collecting constraints, but got none")
}

if !reflect.DeepEqual(gotConstraints, c.wantConstraints) {
t.Fatalf("Unexpected collected constraints: \n\t(GOT): %v\n\t(WNT): %v", gotConstraints, c.wantConstraints)
t.Fatalf("unexpected collected constraints: \n\t(GOT): %v\n\t(WNT): %v", gotConstraints, c.wantConstraints)
}
})
}
Expand Down

0 comments on commit e8a2617

Please sign in to comment.