forked from KurokuLabs/margo
/
lint.go
129 lines (108 loc) · 2.29 KB
/
lint.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
package mg
import (
"margo.sh/mgutil"
"os"
"os/exec"
)
type Linter struct {
ReducerType
Langs []Lang
Actions []Action
Name string
Args []string
IssueKey func(*Ctx) IssueKey
Tag IssueTag
Label string
TempDir []string
q *mgutil.ChanQ
}
func (lt *Linter) RCond(mx *Ctx) bool {
return mx.LangIs(lt.Langs...) &&
(mx.ActionIs(lt.userActs()...) || mx.ActionIs(lt.auxActs()...))
}
func (lt *Linter) userActs() []Action {
if acts := lt.Actions; len(acts) != 0 {
return acts
}
return []Action{ViewSaved{}}
}
func (lt *Linter) auxActs() []Action {
return []Action{QueryUserCmds{}}
}
func (lt *Linter) Reduce(mx *Ctx) *State {
// keep non-default actions in sync with auxActs()
switch mx.Action.(type) {
case QueryUserCmds:
return lt.userCmds(mx)
default:
lt.q.Put(mx)
return mx.State
}
}
func (lt *Linter) RMount(mx *Ctx) {
lt.q = mgutil.NewChanQ(1)
go lt.loop()
}
func (lt *Linter) RUnmount(mx *Ctx) {
lt.q.Close()
}
func (lt *Linter) userCmds(mx *Ctx) *State {
lbl := lt.Label
if lbl == "" {
lbl = lt.Name
}
return mx.AddUserCmds(UserCmd{
Name: lt.Name,
Args: lt.Args,
Title: "Linter: " + lbl,
})
}
func (lt *Linter) loop() {
for v := range lt.q.C() {
lt.lint(v.(*Ctx))
}
}
func (lt *Linter) key(mx *Ctx) IssueKey {
if ik := lt.IssueKey; ik != nil {
return ik(mx)
}
return IssueKey{Key: lt}
}
func (lt *Linter) lint(mx *Ctx) {
res := StoreIssues{}
res.Key = lt.key(mx)
// make sure to clear any old issues, even if we return early
defer func() { mx.Store.Dispatch(res) }()
cmdStr := mgutil.QuoteCmd(lt.Name, lt.Args...)
if len(lt.TempDir) != 0 {
tmpDir, err := MkTempDir(lt.Label)
if err != nil {
mx.Log.Printf("cannot create tempDir for linter `%s`: %s\n", cmdStr, err)
return
}
defer os.RemoveAll(tmpDir)
m := mx.Env
for _, k := range lt.TempDir {
m = m.Add(k, tmpDir)
}
mx = mx.SetState(mx.State.SetEnv(m))
}
dir := mx.View.Dir()
iw := &IssueOut{
Dir: dir,
Patterns: mx.CommonPatterns(),
Base: Issue{Label: lt.Label, Tag: lt.Tag},
}
cmd := exec.Command(lt.Name, lt.Args...)
cmd.Stdout = iw
cmd.Stderr = iw
cmd.Env = mx.Env.Environ()
cmd.Dir = dir
if err := cmd.Start(); err != nil {
mx.Log.Printf("cannot start linter `%s`: %s", cmdStr, err)
return
}
cmd.Wait()
iw.Close()
res.Issues = iw.Issues()
}