Skip to content

Commit 1af7692

Browse files
committed
Compile allow and deny list as globs to allow wildcards
* as the glob special characters are not valid package names this should not cause compile errors for any matches of existing modules
1 parent 47afd98 commit 1af7692

File tree

7 files changed

+95
-102
lines changed

7 files changed

+95
-102
lines changed

cmd/depguard/main_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ var expectedConfigStruct = &depguard.LinterSettings{
1616
Files: []string{"$all", "!$test"},
1717
Allow: []string{"$gostd", "github.com/"},
1818
Deny: map[string]string{
19+
"github.com/**/test": "No test packages allowed",
1920
"reflect": "Who needs reflection",
2021
"github.com/OpenPeeDeeP": "Use Something Else",
2122
},

cmd/depguard/testfiles/.depguard.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
],
1111
"deny": {
1212
"reflect": "Who needs reflection",
13-
"github.com/OpenPeeDeeP": "Use Something Else"
13+
"github.com/OpenPeeDeeP": "Use Something Else",
14+
"github.com/**/test": "No test packages allowed"
1415
}
1516
},
1617
"tests": {

cmd/depguard/testfiles/.depguard.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ allow = [
1010
[main.deny]
1111
reflect = "Who needs reflection"
1212
"github.com/OpenPeeDeeP" = "Use Something Else"
13+
"github.com/**/test" = "No test packages allowed"
1314

1415
[tests]
1516
files = [

cmd/depguard/testfiles/.depguard.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ main:
88
deny:
99
reflect: Who needs reflection
1010
github.com/OpenPeeDeeP: Use Something Else
11+
github.com/**/test: No test packages allowed
1112
tests:
1213
files:
1314
- "$test"

internal/utils/variables_test.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package utils
22

33
import (
44
"errors"
5+
"slices"
56
"strings"
67
"testing"
78

@@ -61,7 +62,7 @@ func TestGoStdExpander(t *testing.T) {
6162
t.Fatal("expected more than 1 expansion")
6263
}
6364
// Just make sure a few are in there
64-
if !contains(pre, "os") && !contains(pre, "strings") {
65+
if !slices.Contains(pre, "os") && !slices.Contains(pre, "strings") {
6566
t.Error("could not find some of the expected packages")
6667
}
6768
}
@@ -197,12 +198,3 @@ func TestExpandMap(t *testing.T) {
197198
}
198199
})
199200
}
200-
201-
func contains(sl []string, str string) bool {
202-
for _, s := range sl {
203-
if s == str {
204-
return true
205-
}
206-
}
207-
return false
208-
}

settings.go

Lines changed: 53 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ type list struct {
2020
name string
2121
files []glob.Glob
2222
negFiles []glob.Glob
23-
allow []string
24-
deny []string
23+
allow []glob.Glob
24+
deny []glob.Glob
2525
suggestions []string
2626
}
2727

@@ -65,11 +65,18 @@ func (l *List) compile() (*list, error) {
6565
if err != nil {
6666
errs = append(errs, err)
6767
}
68+
sort.Strings(l.Allow)
6869

6970
// Sort Allow
70-
li.allow = make([]string, len(l.Allow))
71-
copy(li.allow, l.Allow)
72-
sort.Strings(li.allow)
71+
li.allow = make([]glob.Glob, 0, len(l.Allow))
72+
for _, pkg := range l.Allow {
73+
glob, err := inputPatternToGlob(pkg)
74+
if err != nil {
75+
errs = append(errs, err)
76+
continue
77+
}
78+
li.allow = append(li.allow, glob)
79+
}
7380
}
7481

7582
if l.Deny != nil {
@@ -80,18 +87,24 @@ func (l *List) compile() (*list, error) {
8087
}
8188

8289
// Split Deny Into Package Slice
83-
li.deny = make([]string, 0, len(l.Deny))
84-
for pkg := range l.Deny {
85-
li.deny = append(li.deny, pkg)
86-
}
8790

88-
// Sort Deny
89-
sort.Strings(li.deny)
91+
// sort before compiling as globs are opaque
92+
pkgs := make([]string, 0, len(l.Deny))
93+
for k := range l.Deny {
94+
pkgs = append(pkgs, k)
95+
}
96+
sort.Strings(pkgs)
9097

91-
// Populate Suggestions to match the Deny order
92-
li.suggestions = make([]string, 0, len(li.deny))
93-
for _, dp := range li.deny {
94-
li.suggestions = append(li.suggestions, strings.TrimSpace(l.Deny[dp]))
98+
li.deny = make([]glob.Glob, 0, len(pkgs))
99+
li.suggestions = make([]string, 0, len(pkgs))
100+
for _, pkg := range pkgs {
101+
glob, err := inputPatternToGlob(pkg)
102+
if err != nil {
103+
errs = append(errs, err)
104+
continue
105+
}
106+
li.deny = append(li.deny, glob)
107+
li.suggestions = append(li.suggestions, strings.TrimSpace(l.Deny[pkg]))
95108
}
96109
}
97110

@@ -107,17 +120,24 @@ func (l *List) compile() (*list, error) {
107120
}
108121

109122
func (l *list) fileMatch(fileName string) bool {
110-
inAllowed := len(l.files) == 0 || strInGlobList(fileName, l.files)
111-
inDenied := strInGlobList(fileName, l.negFiles)
112-
return inAllowed && !inDenied
123+
inDenied, _ := strInGlobList(fileName, l.negFiles)
124+
if inDenied {
125+
return false
126+
}
127+
if len(l.files) == 0 {
128+
// No allow list matches all
129+
return true
130+
}
131+
inAllowed, _ := strInGlobList(fileName, l.files)
132+
return inAllowed
113133
}
114134

115135
func (l *list) importAllowed(imp string) (bool, string) {
116136
inAllowed := len(l.allow) == 0
117137
if !inAllowed {
118-
inAllowed, _ = strInPrefixList(imp, l.allow)
138+
inAllowed, _ = strInGlobList(imp, l.allow)
119139
}
120-
inDenied, suggIdx := strInPrefixList(imp, l.deny)
140+
inDenied, suggIdx := strInGlobList(imp, l.deny)
121141
sugg := ""
122142
if inDenied && suggIdx != -1 {
123143
sugg = l.suggestions[suggIdx]
@@ -179,29 +199,22 @@ func (ls linterSettings) whichLists(fileName string) []*list {
179199
return matches
180200
}
181201

182-
func strInGlobList(str string, globList []glob.Glob) bool {
183-
for _, g := range globList {
202+
func strInGlobList(str string, globList []glob.Glob) (bool, int) {
203+
for idx, g := range globList {
184204
if g.Match(str) {
185-
return true
205+
return true, idx
186206
}
187207
}
188-
return false
208+
return false, 0
189209
}
190210

191-
func strInPrefixList(str string, prefixList []string) (bool, int) {
192-
// Idx represents where in the prefix slice the passed in string would go
193-
// when sorted. -1 Just means that it would be at the very front of the slice.
194-
idx := sort.Search(len(prefixList), func(i int) bool {
195-
return strings.TrimRight(prefixList[i], "$") > str
196-
}) - 1
197-
// This means that the string passed in has no way to be prefixed by anything
198-
// in the prefix list as it is already smaller then everything
199-
if idx == -1 {
200-
return false, idx
201-
}
202-
ioc := prefixList[idx]
203-
if ioc[len(ioc)-1] == '$' {
204-
return str == ioc[:len(ioc)-1], idx
205-
}
206-
return strings.HasPrefix(str, prefixList[idx]), idx
211+
func inputPatternToGlob(pattern string) (glob.Glob, error) {
212+
lastIdx := len(pattern) - 1
213+
if pattern[lastIdx] == '$' {
214+
pattern = pattern[:lastIdx]
215+
} else {
216+
pattern += "**"
217+
}
218+
return glob.Compile(pattern, '/')
219+
207220
}

0 commit comments

Comments
 (0)