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

Wildcard ignores #1156

Merged
merged 12 commits into from
Oct 12, 2017
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

NEW FEATURES:

* Wildcard ignore support. (#1156)
* Disable SourceManager lock by setting `DEPNOLOCK` environment variable.
(#1206)

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ignored = ["github.com/golang/notexist/samples*"]

[[constraint]]
branch = "master"
name = "github.com/sdboyer/deptest"

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ignored = ["github.com/golang/notexist/samples*"]

[[constraint]]
branch = "master"
name = "github.com/sdboyer/deptest"
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright 2017 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.

package main

import (
_ "github.com/sdboyer/deptest"
)

func main() {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright 2017 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.

package samples

import _ "github.com/sdboyer/deptestdos"
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright 2017 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.

package subsamples

import _ "github.com/sdboyer/dep-test"
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"commands": [
["ensure"]
],
"error-expected": "",
"vendor-final": [
"github.com/sdboyer/deptest"
]
}
6 changes: 6 additions & 0 deletions docs/Gopkg.toml.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ You might also try [virtualgo](https://github.com/GetStream/vg), which installs
ignored = ["github.com/user/project/badpkg"]
```

Use wildcard character (*) to define a package prefix to be ignored. Use this
to ignore any package and their subpackages.
```toml
ignored = ["github.com/user/project/badpkg*"]
```

**Use this for:** preventing a package and any of that package's unique
dependencies from being installed.

Expand Down
16 changes: 16 additions & 0 deletions internal/gps/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"strings"
)

const wcIgnoreSuffix = "*"

// string headers used to demarcate sections in hash input creation
const (
hhConstraints = "-CONSTRAINTS-"
Expand Down Expand Up @@ -81,10 +83,24 @@ func (s *solver) writeHashingInputs(w io.Writer) {
writeString(hhIgnores)
ig := make([]string, 0, len(s.rd.ig))
for pkg := range s.rd.ig {
// Skip wildcard ignore. They are handled separately below.
if strings.HasSuffix(pkg, wcIgnoreSuffix) {
continue
}

if !strings.HasPrefix(pkg, s.rd.rpt.ImportRoot) || !isPathPrefixOrEqual(s.rd.rpt.ImportRoot, pkg) {
ig = append(ig, pkg)
}
}

// Add wildcard ignores to ignore list.
if s.rd.igpfx != nil {
s.rd.igpfx.Walk(func(s string, v interface{}) bool {
ig = append(ig, s+"*")
return false
})
}

sort.Strings(ig)

for _, igp := range ig {
Expand Down
91 changes: 91 additions & 0 deletions internal/gps/hash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -594,3 +594,94 @@ func diffHashingInputs(s Solver, wnt []string) string {
tw.Flush()
return buf.String()
}

func TestHashInputsIneffectualWildcardIgs(t *testing.T) {
fix := basicFixtures["shared dependency with overlapping constraints"]

rm := fix.rootmanifest().(simpleRootManifest).dup()

params := SolveParameters{
RootDir: string(fix.ds[0].n),
RootPackageTree: fix.rootTree(),
Manifest: rm,
ProjectAnalyzer: naiveAnalyzer{},
stdLibFn: func(string) bool { return false },
mkBridgeFn: overrideMkBridge,
}

cases := []struct {
name string
ignoreMap map[string]bool
elems []string
}{
{
name: "no wildcard ignores",
elems: []string{
hhConstraints,
"a",
"sv-1.0.0",
"b",
"sv-1.0.0",
hhImportsReqs,
"a",
"b",
hhIgnores,
hhOverrides,
hhAnalyzer,
"naive-analyzer",
"1",
},
},
{
name: "different wildcard ignores",
ignoreMap: map[string]bool{
"foobar*": true,
"foobarbaz*": true,
"foozapbar*": true,
},
elems: []string{
hhConstraints,
"a",
"sv-1.0.0",
"b",
"sv-1.0.0",
hhImportsReqs,
"a",
"b",
hhIgnores,
"foobar*",
"foozapbar*",
hhOverrides,
hhAnalyzer,
"naive-analyzer",
"1",
},
},
}

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {

rm.ig = c.ignoreMap

params.Manifest = rm

s, err := Prepare(params, newdepspecSM(fix.ds, nil))
if err != nil {
t.Fatalf("Unexpected error while prepping solver: %s", err)
}

dig := s.HashInputs()
h := sha256.New()

for _, v := range c.elems {
h.Write([]byte(v))
}
correct := h.Sum(nil)

if !bytes.Equal(dig, correct) {
t.Errorf("Hashes are not equal. Inputs:\n%s", diffHashingInputs(s, c.elems))
}
})
}
}
55 changes: 55 additions & 0 deletions internal/gps/pkgtree/pkgtree.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@ import (
"strconv"
"strings"
"unicode"

"github.com/armon/go-radix"
)

// wildcard ignore suffix
const wcIgnoreSuffix = "*"

// Package represents a Go package. It contains a subset of the information
// go/build.Package does.
type Package struct {
Expand Down Expand Up @@ -550,6 +555,9 @@ func (t PackageTree) ToReachMap(main, tests, backprop bool, ignore map[string]bo
ignore = make(map[string]bool)
}

// Radix tree for ignore prefixes.
xt := CreateIgnorePrefixTree(ignore)

// world's simplest adjacency list
workmap := make(map[string]wm)

Expand All @@ -572,6 +580,14 @@ func (t PackageTree) ToReachMap(main, tests, backprop bool, ignore map[string]bo
continue
}

if xt != nil {
// Skip ignored packages prefix matches
_, _, ok := xt.LongestPrefix(ip)
if ok {
continue
}
}

// TODO (kris-nova) Disable to get staticcheck passing
//imps = imps[:0]

Expand Down Expand Up @@ -1026,3 +1042,42 @@ func uniq(a []string) []string {
}
return a[:i]
}

// CreateIgnorePrefixTree takes a set of strings to be ignored and returns a
// trie consisting of strings prefixed with wildcard ignore suffix (*).
func CreateIgnorePrefixTree(ig map[string]bool) *radix.Tree {
var xt *radix.Tree
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not initialize a new tree here instead of checking for nil later on?

Copy link
Collaborator Author

@darkowlzz darkowlzz Oct 6, 2017

Choose a reason for hiding this comment

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

We had that earlier but then we decided to allocate memory only when we get a wildcard suffix. Refer #1156 (comment)


// Create a sorted list of all the ignores to have a proper order in
// ignores parsing.
sortedIgnores := make([]string, len(ig))
for k := range ig {
sortedIgnores = append(sortedIgnores, k)
}
sort.Strings(sortedIgnores)

for _, i := range sortedIgnores {
// Skip global ignore.
if i == "*" {
continue
}

// Check if it's a recursive ignore.
if strings.HasSuffix(i, wcIgnoreSuffix) {
// Create trie if it doesn't exists.
if xt == nil {
xt = radix.New()
}
// Check if it is ineffectual.
_, _, ok := xt.LongestPrefix(i)
if ok {
// Skip ineffectual wildcard ignore.
continue
}
// Create the ignore prefix and insert in the radix tree.
xt.Insert(i[:len(i)-len(wcIgnoreSuffix)], true)
}
}

return xt
}
Loading