-
Notifications
You must be signed in to change notification settings - Fork 77
/
workflow.go
109 lines (84 loc) · 2.5 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
package pgs
import (
"io/ioutil"
"sync"
"google.golang.org/protobuf/proto"
plugin_go "google.golang.org/protobuf/types/pluginpb"
)
type workflow interface {
Init(*Generator) AST
Run(AST) []Artifact
Persist([]Artifact)
}
// standardWorkflow describes a typical protoc-plugin flow, with the only
// exception being the behavior of the persister directly writing custom file
// artifacts to disk (instead of via the plugin's output to protoc).
type standardWorkflow struct {
*Generator
BiDi bool
}
func (wf *standardWorkflow) Init(g *Generator) AST {
wf.Generator = g
wf.Debug("reading input")
data, err := ioutil.ReadAll(g.in)
wf.CheckErr(err, "reading input")
wf.Debug("parsing input proto")
req := new(plugin_go.CodeGeneratorRequest)
err = proto.Unmarshal(data, req)
wf.CheckErr(err, "parsing input proto")
wf.Assert(len(req.FileToGenerate) > 0, "no files to generate")
wf.Debug("parsing command-line params")
wf.params = ParseParameters(req.GetParameter())
for _, pm := range wf.paramMutators {
pm(wf.params)
}
if wf.BiDi {
return ProcessCodeGeneratorRequestBidirectional(g, req)
}
return ProcessCodeGeneratorRequest(g, req)
}
func (wf *standardWorkflow) Run(ast AST) (arts []Artifact) {
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 {
arts = append(arts, m.Execute(ast.Targets(), ast.Packages())...)
}
return
}
func (wf *standardWorkflow) Persist(arts []Artifact) {
resp := wf.persister.Persist(arts...)
data, err := proto.Marshal(resp)
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 exactly
// once. Subsequent calls will ignore their inputs and use the previously
// provided values.
type onceWorkflow struct {
workflow
initOnce sync.Once
ast AST
runOnce sync.Once
arts []Artifact
persistOnce sync.Once
}
func (wf *onceWorkflow) Init(g *Generator) AST {
wf.initOnce.Do(func() { wf.ast = wf.workflow.Init(g) })
return wf.ast
}
func (wf *onceWorkflow) Run(ast AST) []Artifact {
wf.runOnce.Do(func() {
wf.arts = wf.workflow.Run(ast)
})
return wf.arts
}
func (wf *onceWorkflow) Persist(artifacts []Artifact) {
wf.persistOnce.Do(func() { wf.workflow.Persist(artifacts) })
}