Skip to content

Commit 5f88917

Browse files
author
Andrew Carter
committed
Add exclude option
Added --exclude option that mimics ctag's exclude flag. The pattern is expected to be a shell glob pattern (which is what Go's filepath.Match method expects). It can be set multiple times to set several filters. Once the file list is built, the patterns will be applied to each file to filter out any names that match the exclude patterns before processing.
1 parent f9b2760 commit 5f88917

File tree

2 files changed

+169
-12
lines changed

2 files changed

+169
-12
lines changed

files_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package main
2+
3+
import (
4+
"reflect"
5+
"strings"
6+
"testing"
7+
)
8+
9+
var sources = []string{
10+
"LICENSE",
11+
"README.md",
12+
"fields.go",
13+
"fields_test.go",
14+
"files_test.go",
15+
"main.go",
16+
"parser.go",
17+
"parser_test.go",
18+
"tag.go",
19+
"tag_test.go",
20+
"tags",
21+
"tests/const.go-src",
22+
"tests/func.go-src",
23+
"tests/import.go-src",
24+
"tests/interface.go-src",
25+
"tests/range.go-src",
26+
"tests/simple.go-src",
27+
"tests/struct.go-src",
28+
"tests/type.go-src",
29+
"tests/var.go-src",
30+
}
31+
32+
func TestCommandLineFiles(t *testing.T) {
33+
patterns := patternList{}
34+
35+
files, err := getFileNames(sources, false, patterns)
36+
if err != nil {
37+
t.Error(err)
38+
}
39+
40+
if !reflect.DeepEqual(sources, files) {
41+
t.Errorf("%+v != %+v", sources, files)
42+
}
43+
}
44+
45+
func TestSingleExcludePattern(t *testing.T) {
46+
// Single pattern - exclude *_test.go files
47+
patterns := []string{"*_test.go"}
48+
files, err := getFileNames(sources, false, patterns)
49+
if err != nil {
50+
t.Error(err)
51+
}
52+
53+
for _, f := range files {
54+
if strings.HasSuffix(f, "_test.go") {
55+
t.Errorf("%v should not be included", f)
56+
}
57+
}
58+
}
59+
60+
func TestMultipeExcludePatterns(t *testing.T) {
61+
// Multiple patterns - exclude *_test.go and **/*-src
62+
patterns := []string{"*_test.go", "**/*-src"}
63+
files, err := getFileNames(sources, false, patterns)
64+
if err != nil {
65+
t.Error(err)
66+
}
67+
68+
for _, f := range files {
69+
if strings.HasSuffix(f, "_test.go") || strings.HasSuffix(f, "-src") {
70+
t.Errorf("%v should not be included", f)
71+
}
72+
}
73+
}
74+
75+
func TestRecursiveExcludes(t *testing.T) {
76+
input := []string{"/usr/local/go/src"}
77+
patterns := []string{
78+
"*_test.go",
79+
"/usr/local/go/src/*/*/testdata/*",
80+
"/usr/local/go/src/*/*/testdata/*/*",
81+
"/usr/local/go/src/*/*/testdata/*/*/*",
82+
"/usr/local/go/src/*/*/testdata/*/*/*/*",
83+
"/usr/local/go/src/*/*/testdata/*/*/*/*/*",
84+
"/usr/local/go/src/*/*/testdata/*/*/*/*/*/*",
85+
"/usr/local/go/src/*/*/testdata/*/*/*/*/*/*/*",
86+
}
87+
files, err := getFileNames(input, true, patterns)
88+
if err != nil {
89+
t.Error(err)
90+
}
91+
for _, f := range files {
92+
if strings.HasSuffix(f, "_test.go") || strings.Contains(f, "/testdata/") {
93+
t.Errorf("%v should not be included", f)
94+
}
95+
}
96+
t.Log(files)
97+
}

main.go

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,28 @@ const (
2121
AuthorEmail = "[email protected]"
2222
)
2323

24+
type patternList []string
25+
26+
func (p *patternList) String() string {
27+
return fmt.Sprint(*p)
28+
}
29+
30+
func (p *patternList) Set(value string) error {
31+
*p = append(*p, value)
32+
return nil
33+
}
34+
2435
var (
25-
printVersion bool
26-
inputFile string
27-
outputFile string
28-
recurse bool
29-
sortOutput bool
30-
silent bool
31-
relative bool
32-
listLangs bool
33-
fields string
36+
printVersion bool
37+
inputFile string
38+
outputFile string
39+
recurse bool
40+
sortOutput bool
41+
silent bool
42+
relative bool
43+
listLangs bool
44+
fields string
45+
excludePatterns patternList
3446
)
3547

3648
// ignore unknown flags
@@ -47,6 +59,7 @@ func init() {
4759
flags.BoolVar(&relative, "tag-relative", false, "file paths should be relative to the directory containing the tag file.")
4860
flags.BoolVar(&listLangs, "list-languages", false, "list supported languages.")
4961
flags.StringVar(&fields, "fields", "", "include selected extension fields (only +l).")
62+
flags.Var(&excludePatterns, "exclude", "exclude files and directories matching 'pattern'. May be called multiple times.")
5063

5164
flags.Usage = func() {
5265
fmt.Fprintf(os.Stderr, "gotags version %s\n\n", Version)
@@ -69,6 +82,43 @@ func walkDir(names []string, dir string) ([]string, error) {
6982
return names, e
7083
}
7184

85+
// includeName will return true supplied list of patterns do not exclude name
86+
func includeName(name string, patterns []string) (bool, error) {
87+
for _, p := range patterns {
88+
// Compare pattern to full path and then to base filename
89+
for _, v := range []string{name, filepath.Base(name)} {
90+
m, err := filepath.Match(p, v)
91+
if err != nil {
92+
// Error - exclude
93+
return false, err
94+
}
95+
if m == true {
96+
// Matches filepath - exclude
97+
return false, nil
98+
}
99+
}
100+
}
101+
102+
// No filters matched - include the file
103+
return true, nil
104+
}
105+
106+
func filterNames(names []string, patterns []string) ([]string, error) {
107+
var ret []string
108+
109+
for _, f := range names {
110+
ok, err := includeName(f, patterns)
111+
if err != nil {
112+
return nil, err
113+
}
114+
if ok {
115+
ret = append(ret, f)
116+
}
117+
}
118+
119+
return ret, nil
120+
}
121+
72122
func recurseNames(names []string) ([]string, error) {
73123
var ret []string
74124
for _, name := range names {
@@ -113,22 +163,32 @@ func readNames(names []string) ([]string, error) {
113163
return names, nil
114164
}
115165

116-
func getFileNames() ([]string, error) {
166+
func getFileNames(files []string, recurse bool, excludes patternList) ([]string, error) {
117167
var names []string
118168

119-
names = append(names, flags.Args()...)
169+
// Start with list of supplied file names
170+
names = append(names, files...)
171+
172+
// Read filenames from input file if provided
120173
names, err := readNames(names)
121174
if err != nil {
122175
return nil, err
123176
}
124177

178+
// Recurse into directories in the file list
125179
if recurse {
126180
names, err = recurseNames(names)
127181
if err != nil {
128182
return nil, err
129183
}
130184
}
131185

186+
// Apply excludes patterns
187+
names, err = filterNames(names, excludes)
188+
if err != nil {
189+
return nil, err
190+
}
191+
132192
return names, nil
133193
}
134194

@@ -145,7 +205,7 @@ func main() {
145205
return
146206
}
147207

148-
files, err := getFileNames()
208+
files, err := getFileNames(flags.Args(), recurse, excludePatterns)
149209
if err != nil {
150210
fmt.Fprintf(os.Stderr, "cannot get specified files\n\n")
151211
flags.Usage()

0 commit comments

Comments
 (0)