-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
159 lines (133 loc) · 3.49 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package main
import (
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"sort"
"sync"
)
// TODO: atom editor plugin for linter (should work with our JSON mode)
func processFile(filename string, report chan *Warning, maxWarnings int) int {
fm, err := NewFileMap(filename)
check(err)
// We launch a goroutine per list of TextChecks and write any warnings to
// our gather channel. Then we pump from the gather channel to our caller.
// There are many things we COULD do as we gather the warnings, but
// currently this is only used to handle the max warnings per file feature.
wg := sync.WaitGroup{}
gather := make(chan *Warning, 64)
launch := func(checks []TextCheck) {
wg.Add(1)
go func(fm *FileMap, checks []TextCheck) {
defer wg.Done()
count := 0
for _, c := range checks {
for _, warn := range c.Match(fm) {
gather <- warn
count++
if maxWarnings > 0 && count >= maxWarnings {
// optimization: see below for actual maxWarnings work
return
}
}
}
}(fm, checks)
}
launch(ShouldNotExist())
launch(ShouldNotCliche())
launch(ShouldNotRedundant())
launch(ShouldNotProfane())
launch(ShouldNotBias())
launch(ShouldNotPassive())
go func() {
wg.Wait()
close(gather)
}()
// Actually funnel warnings back to caller
finalCount := 0
for warn := range gather {
report <- warn
finalCount++
if maxWarnings > 0 && finalCount >= maxWarnings {
break
}
}
return finalCount
}
func main() {
flags := flag.NewFlagSet("tint", flag.ExitOnError)
verbosePtr := flags.Bool("v", false, "Verbose output (written to stderr")
sortPtr := flags.Bool("s", false, "Sort output (by file name, line number, column number")
jsonPtr := flags.Bool("j", false, "Use JSON output instead of default")
maxAllPtr := flags.Int("max", 0, "Maximum warnings to output")
maxFilePtr := flags.Int("filemax", 0, "Maximum warnings per file")
check(flags.Parse(os.Args[1:]))
args := flags.Args()
// If it should always be printed, we use log. If it should only be printed when
// verbose=true, then we use verb
var verb *log.Logger
if *verbosePtr {
verb = log.New(os.Stderr, "", 0)
} else {
verb = log.New(ioutil.Discard, "", 0)
}
verb.Printf("Verbose: %v\n", *verbosePtr)
verb.Printf("Sort: %v\n", *sortPtr)
wg := sync.WaitGroup{}
report := make(chan *Warning, 64)
for _, filename := range args {
verb.Printf("FILE: %s\n", filename)
wg.Add(1)
go func(fn string) {
defer wg.Done()
processFile(fn, report, *maxFilePtr)
}(filename)
}
go func() {
wg.Wait()
close(report)
}()
// Final output channel might be filtered by sort or count options
output := report
// Sort filter
if *sortPtr {
sortInput := output
output = make(chan *Warning, 64)
go func(out chan *Warning) {
defer close(out)
warnings := make([]*Warning, 0, 128)
for warn := range sortInput {
warnings = append(warnings, warn)
}
verb.Printf("Sorting %d warnings\n", len(warnings))
sort.Sort(WarningDefSort(warnings))
for _, warn := range warnings {
out <- warn
}
}(output)
}
// Output all warnings
var outputter func(w *Warning)
if *jsonPtr {
outputter = func(w *Warning) {
fmt.Printf("%s\n", w.CreateJSON())
}
} else {
outputter = func(w *Warning) {
fmt.Printf("%s:%d:%d:warning: %s\n",
w.Filename, w.Row+1, w.Col+1, msgEscape(w.Msg),
)
}
}
written := 0
for warn := range output {
outputter(warn)
written++
if *maxAllPtr > 0 && written >= *maxAllPtr {
verb.Printf("Maximum warnings reached (%d)\n", written)
break
}
}
}