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

Commit 3b8fbe4

Browse files
authored
Merge pull request #1534 from sdboyer/ineffectuals
Warn on ineffectual constraints
2 parents 30ea015 + b89aa7e commit 3b8fbe4

File tree

9 files changed

+206
-123
lines changed

9 files changed

+206
-123
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ IMPROVEMENTS:
2929
* Add constraint for locked projects in `dep status`. ([#962](https://github.com/golang/dep/pull/962)
3030
* Make external config importers error tolerant. ([#1315](https://github.com/golang/dep/pull/1315))
3131
* Show LATEST and VERSION as the same type in status. ([#1515](https://github.com/golang/dep/pull/1515)
32+
* Warn when [[constraint]] rules that will have no effect. ([#1534](https://github.com/golang/dep/pull/1534))
3233

3334
# v0.3.2
3435

cmd/dep/ensure.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,20 @@ func (cmd *ensureCommand) Run(ctx *dep.Ctx, args []string) error {
197197
ctx.Out.Println(err)
198198
}
199199
}
200+
if ineffs := p.FindIneffectualConstraints(sm); len(ineffs) > 0 {
201+
ctx.Err.Printf("Warning: the following project(s) have [[constraint]] stanzas in %s:\n\n", dep.ManifestName)
202+
for _, ineff := range ineffs {
203+
ctx.Err.Println(" ✗ ", ineff)
204+
}
205+
// TODO(sdboyer) lazy wording, it does not mention ignores at all
206+
ctx.Err.Printf("\nHowever, these projects are not direct dependencies of the current project:\n")
207+
ctx.Err.Printf("they are not imported in any .go files, nor are they in the 'required' list in\n")
208+
ctx.Err.Printf("%s. Dep only applies [[constraint]] rules to direct dependencies, so\n", dep.ManifestName)
209+
ctx.Err.Printf("these rules will have no effect.\n\n")
210+
ctx.Err.Printf("Either import/require packages from these projects so that they become direct\n")
211+
ctx.Err.Printf("dependencies, or convert each [[constraint]] to an [[override]] to enforce rules\n")
212+
ctx.Err.Printf("on these projects, if they happen to be transitive dependencies,\n\n")
213+
}
200214

201215
if cmd.add {
202216
return cmd.runAdd(ctx, args, p, sm, params)
@@ -515,7 +529,7 @@ func (cmd *ensureCommand) runAdd(ctx *dep.Ctx, args []string, p *dep.Project, sm
515529
}
516530

517531
inManifest := p.Manifest.HasConstraintsOn(pc.Ident.ProjectRoot)
518-
inImports := exrmap[pc.Ident.ProjectRoot]
532+
inImports := exmap[string(pc.Ident.ProjectRoot)]
519533
if inManifest && inImports {
520534
errCh <- errors.Errorf("nothing to -add, %s is already in %s and the project's direct imports or required list", pc.Ident.ProjectRoot, dep.ManifestName)
521535
return

cmd/dep/failures.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2018 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import (
8+
"context"
9+
10+
"github.com/golang/dep/gps"
11+
"github.com/pkg/errors"
12+
)
13+
14+
// TODO solve failures can be really creative - we need to be similarly creative
15+
// in handling them and informing the user appropriately
16+
func handleAllTheFailuresOfTheWorld(err error) error {
17+
switch errors.Cause(err) {
18+
case context.Canceled, context.DeadlineExceeded, gps.ErrSourceManagerIsReleased:
19+
return nil
20+
}
21+
22+
return errors.Wrap(err, "Solving failure")
23+
}

cmd/dep/gopath_scanner.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ import (
2424
// It uses its results to fill-in any missing details left by the rootAnalyzer.
2525
type gopathScanner struct {
2626
ctx *dep.Ctx
27-
directDeps map[string]bool
27+
directDeps map[gps.ProjectRoot]bool
2828
sm gps.SourceManager
2929

3030
pd projectData
3131
origM *dep.Manifest
3232
origL *dep.Lock
3333
}
3434

35-
func newGopathScanner(ctx *dep.Ctx, directDeps map[string]bool, sm gps.SourceManager) *gopathScanner {
35+
func newGopathScanner(ctx *dep.Ctx, directDeps map[gps.ProjectRoot]bool, sm gps.SourceManager) *gopathScanner {
3636
return &gopathScanner{
3737
ctx: ctx,
3838
directDeps: directDeps,
@@ -113,7 +113,7 @@ func (g *gopathScanner) overlay(rootM *dep.Manifest, rootL *dep.Lock) {
113113
rootL.P = append(rootL.P, lp)
114114
lockedProjects[pkg] = true
115115

116-
if _, isDirect := g.directDeps[string(pkg)]; !isDirect {
116+
if _, isDirect := g.directDeps[pkg]; !isDirect {
117117
f := fb.NewLockedProjectFeedback(lp, fb.DepTypeTransitive)
118118
f.LogFeedback(g.ctx.Err)
119119
}
@@ -220,7 +220,10 @@ func (g *gopathScanner) scanGopathForDependencies() (projectData, error) {
220220
return projectData{}, nil
221221
}
222222

223-
for ip := range g.directDeps {
223+
for ippr := range g.directDeps {
224+
// TODO(sdboyer) these are not import paths by this point, they've
225+
// already been worked down to project roots.
226+
ip := string(ippr)
224227
pr, err := g.sm.DeduceProjectRoot(ip)
225228
if err != nil {
226229
return projectData{}, errors.Wrap(err, "sm.DeduceProjectRoot")

cmd/dep/init.go

Lines changed: 46 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,11 @@ import (
1515

1616
"github.com/golang/dep"
1717
"github.com/golang/dep/gps"
18-
"github.com/golang/dep/gps/paths"
19-
"github.com/golang/dep/gps/pkgtree"
2018
"github.com/golang/dep/internal/fs"
2119
"github.com/pkg/errors"
2220
)
2321

24-
const initShortHelp = `Initialize a new project with manifest and lock files`
22+
const initShortHelp = `Set up a new Go project, or migrate an existing one`
2523
const initLongHelp = `
2624
Initialize the project at filepath root by parsing its dependencies, writing
2725
manifest and lock files, and vendoring the dependencies. If root isn't
@@ -89,43 +87,10 @@ func (cmd *initCommand) Run(ctx *dep.Ctx, args []string) error {
8987
}
9088
}
9189

92-
var err error
93-
p := new(dep.Project)
94-
if err = p.SetRoot(root); err != nil {
95-
return errors.Wrapf(err, "init failed: unable to set the root project to %s", root)
96-
}
97-
98-
ctx.GOPATH, err = ctx.DetectProjectGOPATH(p)
99-
if err != nil {
100-
return errors.Wrapf(err, "init failed: unable to detect the containing GOPATH")
101-
}
102-
103-
mf := filepath.Join(root, dep.ManifestName)
104-
lf := filepath.Join(root, dep.LockName)
105-
vpath := filepath.Join(root, "vendor")
106-
107-
mok, err := fs.IsRegular(mf)
90+
p, err := cmd.establishProjectAt(root, ctx)
10891
if err != nil {
109-
return errors.Wrapf(err, "init failed: unable to check for an existing manifest at %s", mf)
92+
return err
11093
}
111-
if mok {
112-
return errors.Errorf("init aborted: manifest already exists at %s", mf)
113-
}
114-
// Manifest file does not exist.
115-
116-
lok, err := fs.IsRegular(lf)
117-
if err != nil {
118-
return errors.Wrapf(err, "init failed: unable to check for an existing lock at %s", lf)
119-
}
120-
if lok {
121-
return errors.Errorf("invalid aborted: lock already exists at %s", lf)
122-
}
123-
124-
ip, err := ctx.ImportForAbs(root)
125-
if err != nil {
126-
return errors.Wrapf(err, "init failed: unable to determine the import path for the root project %s", root)
127-
}
128-
p.ImportRoot = gps.ProjectRoot(ip)
12994

13095
sm, err := ctx.SourceManager()
13196
if err != nil {
@@ -137,12 +102,13 @@ func (cmd *initCommand) Run(ctx *dep.Ctx, args []string) error {
137102
if ctx.Verbose {
138103
ctx.Out.Println("Getting direct dependencies...")
139104
}
140-
pkgT, directDeps, err := getDirectDependencies(sm, p)
105+
106+
ptree, directDeps, err := p.GetDirectDependencyNames(sm)
141107
if err != nil {
142108
return errors.Wrap(err, "init failed: unable to determine direct dependencies")
143109
}
144110
if ctx.Verbose {
145-
ctx.Out.Printf("Checked %d directories for packages.\nFound %d direct dependencies.\n", len(pkgT.Packages), len(directDeps))
111+
ctx.Out.Printf("Checked %d directories for packages.\nFound %d direct dependencies.\n", len(ptree.Packages), len(directDeps))
146112
}
147113

148114
// Initialize with imported data, then fill in the gaps using the GOPATH
@@ -165,7 +131,7 @@ func (cmd *initCommand) Run(ctx *dep.Ctx, args []string) error {
165131

166132
params := gps.SolveParameters{
167133
RootDir: root,
168-
RootPackageTree: pkgT,
134+
RootPackageTree: ptree,
169135
Manifest: p.Manifest,
170136
Lock: p.Lock,
171137
ProjectAnalyzer: rootAnalyzer,
@@ -203,7 +169,7 @@ func (cmd *initCommand) Run(ctx *dep.Ctx, args []string) error {
203169
p.Lock.SolveMeta.InputsDigest = s.HashInputs()
204170

205171
// Pass timestamp (yyyyMMddHHmmss format) as suffix to backup name.
206-
vendorbak, err := dep.BackupVendor(vpath, time.Now().Format("20060102150405"))
172+
vendorbak, err := dep.BackupVendor(filepath.Join(root, "vendor"), time.Now().Format("20060102150405"))
207173
if err != nil {
208174
return errors.Wrap(err, "init failed: first backup vendor/, delete it, and then retry the previous command: failed to backup existing vendor directory")
209175
}
@@ -227,32 +193,50 @@ func (cmd *initCommand) Run(ctx *dep.Ctx, args []string) error {
227193
return nil
228194
}
229195

230-
func getDirectDependencies(sm gps.SourceManager, p *dep.Project) (pkgtree.PackageTree, map[string]bool, error) {
231-
pkgT, err := p.ParseRootPackageTree()
196+
// establishProjectAt attempts to set up the provided path as the root for the
197+
// project to be created.
198+
//
199+
// It checks for being within a GOPATH, that there is no pre-existing manifest
200+
// and lock, and that we can successfully infer the root import path from
201+
// GOPATH.
202+
//
203+
// If successful, it returns a dep.Project, ready for further use.
204+
func (cmd *initCommand) establishProjectAt(root string, ctx *dep.Ctx) (*dep.Project, error) {
205+
var err error
206+
p := new(dep.Project)
207+
if err = p.SetRoot(root); err != nil {
208+
return nil, errors.Wrapf(err, "init failed: unable to set the root project to %s", root)
209+
}
210+
211+
ctx.GOPATH, err = ctx.DetectProjectGOPATH(p)
232212
if err != nil {
233-
return pkgtree.PackageTree{}, nil, err
213+
return nil, errors.Wrapf(err, "init failed: unable to detect the containing GOPATH")
234214
}
235215

236-
directDeps := map[string]bool{}
237-
rm, _ := pkgT.ToReachMap(true, true, false, nil)
238-
for _, ip := range rm.FlattenFn(paths.IsStandardImportPath) {
239-
pr, err := sm.DeduceProjectRoot(ip)
240-
if err != nil {
241-
return pkgtree.PackageTree{}, nil, err
242-
}
243-
directDeps[string(pr)] = true
216+
mf := filepath.Join(root, dep.ManifestName)
217+
lf := filepath.Join(root, dep.LockName)
218+
219+
mok, err := fs.IsRegular(mf)
220+
if err != nil {
221+
return nil, errors.Wrapf(err, "init failed: unable to check for an existing manifest at %s", mf)
222+
}
223+
if mok {
224+
return nil, errors.Errorf("init aborted: manifest already exists at %s", mf)
244225
}
245226

246-
return pkgT, directDeps, nil
247-
}
227+
lok, err := fs.IsRegular(lf)
228+
if err != nil {
229+
return nil, errors.Wrapf(err, "init failed: unable to check for an existing lock at %s", lf)
230+
}
231+
if lok {
232+
return nil, errors.Errorf("invalid aborted: lock already exists at %s", lf)
233+
}
248234

249-
// TODO solve failures can be really creative - we need to be similarly creative
250-
// in handling them and informing the user appropriately
251-
func handleAllTheFailuresOfTheWorld(err error) error {
252-
switch errors.Cause(err) {
253-
case context.Canceled, context.DeadlineExceeded, gps.ErrSourceManagerIsReleased:
254-
return nil
235+
ip, err := ctx.ImportForAbs(root)
236+
if err != nil {
237+
return nil, errors.Wrapf(err, "init failed: unable to determine the import path for the root project %s", root)
255238
}
239+
p.ImportRoot = gps.ProjectRoot(ip)
256240

257-
return errors.Wrap(err, "Solving failure")
241+
return p, nil
258242
}

cmd/dep/init_test.go

Lines changed: 0 additions & 40 deletions
This file was deleted.

cmd/dep/root_analyzer.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ type rootAnalyzer struct {
2626
skipTools bool
2727
ctx *dep.Ctx
2828
sm gps.SourceManager
29-
directDeps map[string]bool
29+
directDeps map[gps.ProjectRoot]bool
3030
}
3131

32-
func newRootAnalyzer(skipTools bool, ctx *dep.Ctx, directDeps map[string]bool, sm gps.SourceManager) *rootAnalyzer {
32+
func newRootAnalyzer(skipTools bool, ctx *dep.Ctx, directDeps map[gps.ProjectRoot]bool, sm gps.SourceManager) *rootAnalyzer {
3333
return &rootAnalyzer{
3434
skipTools: skipTools,
3535
ctx: ctx,
@@ -73,7 +73,7 @@ func (a *rootAnalyzer) cacheDeps(pr gps.ProjectRoot) error {
7373
return nil
7474
}
7575

76-
deps := make(chan string)
76+
deps := make(chan gps.ProjectRoot)
7777

7878
for i := 0; i < concurrency; i++ {
7979
g.Go(func() error {
@@ -132,7 +132,7 @@ func (a *rootAnalyzer) importManifestAndLock(dir string, pr gps.ProjectRoot, sup
132132

133133
func (a *rootAnalyzer) removeTransitiveDependencies(m *dep.Manifest) {
134134
for pr := range m.Constraints {
135-
if _, isDirect := a.directDeps[string(pr)]; !isDirect {
135+
if _, isDirect := a.directDeps[pr]; !isDirect {
136136
delete(m.Constraints, pr)
137137
}
138138
}
@@ -172,7 +172,7 @@ func (a *rootAnalyzer) FinalizeRootManifestAndLock(m *dep.Manifest, l *dep.Lock,
172172
var f *fb.ConstraintFeedback
173173
pr := y.Ident().ProjectRoot
174174
// New constraints: in new lock and dir dep but not in manifest
175-
if _, ok := a.directDeps[string(pr)]; ok {
175+
if _, ok := a.directDeps[pr]; ok {
176176
if _, ok := m.Constraints[pr]; !ok {
177177
pp := getProjectPropertiesFromVersion(y.Version())
178178
if pp.Constraint != nil {

cmd/dep/status.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -764,8 +764,9 @@ func collectConstraints(ctx *dep.Ctx, p *dep.Project, sm gps.SourceManager) (con
764764
var mutex sync.Mutex
765765
constraintCollection := make(constraintsCollection)
766766

767-
// Get direct deps of the root project.
768-
_, directDeps, err := getDirectDependencies(sm, p)
767+
// Collect the complete set of direct project dependencies, incorporating
768+
// requireds and ignores appropriately.
769+
_, directDeps, err := p.GetDirectDependencyNames(sm)
769770
if err != nil {
770771
// Return empty collection, not nil, if we fail here.
771772
return constraintCollection, []error{errors.Wrap(err, "failed to get direct dependencies")}
@@ -805,7 +806,7 @@ func collectConstraints(ctx *dep.Ctx, p *dep.Project, sm gps.SourceManager) (con
805806
// project and constraint values.
806807
for pr, pp := range pc {
807808
// Check if the project constraint is imported in the root project
808-
if _, ok := directDeps[string(pr)]; !ok {
809+
if _, ok := directDeps[pr]; !ok {
809810
continue
810811
}
811812

0 commit comments

Comments
 (0)