forked from lyft/protoc-gen-star
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathworkflow.go
156 lines (126 loc) · 3.88 KB
/
workflow.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
package pgs
import (
"io/ioutil"
"sync"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/protoc-gen-go/plugin"
)
type workflow interface {
Init(g *Generator)
Go()
Star()
Persist()
}
// standardWorkflow uses a close-to-official execution pattern for PGGo. PG*
// modules are executed once the PGGo execution has completed and files are
// persisted the Generator's Persister instance (typically sending back to
// protoc and creating files on disk).
type standardWorkflow struct {
*Generator
arts []Artifact
}
func (wf *standardWorkflow) Init(g *Generator) {
*wf = standardWorkflow{}
wf.Generator = g
wf.Debug("reading input")
data, err := ioutil.ReadAll(wf.in)
wf.CheckErr(err, "reading input")
wf.Debug("parsing input proto")
err = proto.Unmarshal(data, wf.pgg.request())
wf.CheckErr(err, "parsing input proto")
wf.Assert(len(wf.pgg.request().FileToGenerate) > 0, "no files to generate")
wf.Debug("parsing command-line params")
wf.params = ParseParameters(wf.pgg.request().GetParameter())
for _, pm := range wf.paramMutators {
pm(wf.params)
}
}
func (wf *standardWorkflow) Go() {
wf.RegisterPlugin(wf.gatherer)
wf.params.AddPlugin(wf.gatherer.Name())
wf.Debug("initializing plugins")
for _, p := range wf.plugins {
p.InitContext(Context(
wf.Debugger.Push(p.Name()),
wf.params,
".",
))
}
wf.Debug("preparing official generator")
wf.pgg.prepare(wf.params)
wf.Debug("generating official PGG PBs and gathering PG* AST")
wf.pgg.generate()
}
func (wf *standardWorkflow) Star() {
ctx := Context(wf.Debugger, wf.params, wf.params.OutputPath())
wf.Debug("initializing modules")
for _, m := range wf.mods {
m.InitContext(ctx.Push(m.Name()))
}
wf.Debug("executing modules")
for _, m := range wf.mods {
if mm, ok := m.(MultiModule); ok {
wf.arts = append(wf.arts, mm.MultiExecute(wf.gatherer.targets, wf.gatherer.pkgs)...)
} else {
for _, pkg := range wf.gatherer.targets {
wf.arts = append(wf.arts, m.Execute(pkg, wf.gatherer.pkgs)...)
}
}
}
}
func (wf *standardWorkflow) Persist() {
wf.persister.Persist(wf.arts...)
data, err := proto.Marshal(wf.pgg.response())
wf.CheckErr(err, "marshaling output proto")
n, err := wf.out.Write(data)
wf.CheckErr(err, "writing output proto")
wf.Assert(len(data) == n, "failed to write all output")
wf.Debug("rendering successful")
}
// onceWorkflow wraps an existing workflow, executing its methods only once.
// This is required to keep the Generator AST & Render methods idempotent.
type onceWorkflow struct {
workflow
initOnce sync.Once
goOnce sync.Once
starOnce sync.Once
persistOnce sync.Once
}
func (wf *onceWorkflow) Init(g *Generator) { wf.initOnce.Do(func() { wf.workflow.Init(g) }) }
func (wf *onceWorkflow) Go() { wf.goOnce.Do(wf.workflow.Go) }
func (wf *onceWorkflow) Star() { wf.starOnce.Do(wf.workflow.Star) }
func (wf *onceWorkflow) Persist() { wf.persistOnce.Do(wf.workflow.Persist) }
// excludeGoWorkflow wraps an existing workflow, stripping any PGGo generated
// files from the response. This workflow is used when the IncludeGo InitOption
// is not applied to the Generator.
type excludeGoWorkflow struct {
*Generator
workflow
}
func (wf *excludeGoWorkflow) Init(g *Generator) {
wf.Generator = g
wf.workflow.Init(g)
}
func (wf *excludeGoWorkflow) Go() {
wf.workflow.Go()
scrubbed := make(
[]*plugin_go.CodeGeneratorResponse_File,
0, len(wf.pgg.response().File))
toScrub := make(map[string]struct{}, len(wf.pgg.response().File))
el := struct{}{}
for _, pkg := range wf.gatherer.targets {
for _, f := range pkg.Files() {
if f.BuildTarget() {
toScrub[f.OutputPath().String()] = el
}
}
}
for _, f := range wf.pgg.response().File {
if _, scrub := toScrub[f.GetName()]; !scrub {
scrubbed = append(scrubbed, f)
} else {
wf.Debug("excluding official Go PB:", f.GetName())
}
}
wf.pgg.response().File = scrubbed
}