forked from rhysd/actionlint
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pass.go
149 lines (122 loc) · 3.42 KB
/
pass.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
package actionlint
import (
"fmt"
"io"
"time"
)
// Pass is an interface to traverse a workflow syntax tree
type Pass interface {
// VisitStep is callback when visiting Step node. It returns internal error when it cannot continue the process
VisitStep(node *Step) error
// VisitJobPre is callback when visiting Job node before visiting its children. It returns internal error when it cannot continue the process
VisitJobPre(node *Job) error
// VisitJobPost is callback when visiting Job node after visiting its children. It returns internal error when it cannot continue the process
VisitJobPost(node *Job) error
// VisitWorkflowPre is callback when visiting Workflow node before visiting its children. It returns internal error when it cannot continue the process
VisitWorkflowPre(node *Workflow) error
// VisitWorkflowPost is callback when visiting Workflow node after visiting its children. It returns internal error when it cannot continue the process
VisitWorkflowPost(node *Workflow) error
}
// Visitor visits syntax tree from root in depth-first order
type Visitor struct {
passes []Pass
dbg io.Writer
}
// NewVisitor creates Visitor instance
func NewVisitor() *Visitor {
return &Visitor{}
}
// AddPass adds new pass which is called on traversing a syntax tree
func (v *Visitor) AddPass(p Pass) {
v.passes = append(v.passes, p)
}
// EnableDebug enables debug output when non-nil io.Writer value is given. All debug outputs from
// visitor will be written to the writer.
func (v *Visitor) EnableDebug(w io.Writer) {
v.dbg = w
}
func (v *Visitor) reportElapsedTime(what string, start time.Time) {
fmt.Fprintf(v.dbg, "[Visitor] %s took %vms\n", what, time.Since(start).Milliseconds())
}
// Visit visits given syntax tree in depth-first order
func (v *Visitor) Visit(n *Workflow) error {
var t time.Time
if v.dbg != nil {
t = time.Now()
}
for _, p := range v.passes {
if err := p.VisitWorkflowPre(n); err != nil {
return err
}
}
if v.dbg != nil {
v.reportElapsedTime("VisitWorkflowPre", t)
t = time.Now()
}
for _, j := range n.Jobs {
if err := v.visitJob(j); err != nil {
return err
}
}
if v.dbg != nil {
v.reportElapsedTime(fmt.Sprintf("Visiting %d jobs", len(n.Jobs)), t)
t = time.Now()
}
for _, p := range v.passes {
if err := p.VisitWorkflowPost(n); err != nil {
return err
}
}
if v.dbg != nil {
v.reportElapsedTime("VisitWorkflowPost", t)
}
return nil
}
func (v *Visitor) visitJob(n *Job) error {
var t time.Time
if v.dbg != nil {
t = time.Now()
}
for _, p := range v.passes {
if err := p.VisitJobPre(n); err != nil {
return err
}
}
if v.dbg != nil {
v.reportElapsedTime(fmt.Sprintf("VisitWorkflowJobPre at job %q", n.ID.Value), t)
t = time.Now()
}
for _, s := range n.Steps {
if err := v.visitStep(s); err != nil {
return err
}
}
if v.dbg != nil {
v.reportElapsedTime(fmt.Sprintf("Visiting %d steps at job %q", len(n.Steps), n.ID.Value), t)
t = time.Now()
}
for _, p := range v.passes {
if err := p.VisitJobPost(n); err != nil {
return err
}
}
if v.dbg != nil {
v.reportElapsedTime(fmt.Sprintf("VisitWorkflowJobPost at job %q", n.ID.Value), t)
}
return nil
}
func (v *Visitor) visitStep(n *Step) error {
var t time.Time
if v.dbg != nil {
t = time.Now()
}
for _, p := range v.passes {
if err := p.VisitStep(n); err != nil {
return err
}
}
if v.dbg != nil {
v.reportElapsedTime(fmt.Sprintf("VisitStep at %s", n.Pos), t)
}
return nil
}