@@ -45,6 +45,21 @@ func RegisterOptionsMarkers(into *markers.Registry) error {
45
45
return nil
46
46
}
47
47
48
+ // RegistryFromOptions produces just the marker registry that would be used by FromOptions, without
49
+ // attempting to produce a full Runtime. This can be useful if you want to display help without
50
+ // trying to load roots.
51
+ func RegistryFromOptions (optionsRegistry * markers.Registry , options []string ) (* markers.Registry , error ) {
52
+ protoRt , err := protoFromOptions (optionsRegistry , options )
53
+ if err != nil {
54
+ return nil , err
55
+ }
56
+ reg := & markers.Registry {}
57
+ if err := protoRt .Generators .RegisterMarkers (reg ); err != nil {
58
+ return nil , err
59
+ }
60
+ return reg , nil
61
+ }
62
+
48
63
// FromOptions parses the options from markers stored in the given registry out into a runtime.
49
64
// The markers in the registry must be either
50
65
//
@@ -57,6 +72,40 @@ func RegisterOptionsMarkers(into *markers.Registry) error {
57
72
// further modified. Not default generators are used if none are specified -- you can check
58
73
// the output and rerun for that.
59
74
func FromOptions (optionsRegistry * markers.Registry , options []string ) (* Runtime , error ) {
75
+
76
+ protoRt , err := protoFromOptions (optionsRegistry , options )
77
+ if err != nil {
78
+ return nil , err
79
+ }
80
+
81
+ // make the runtime
82
+ genRuntime , err := protoRt .Generators .ForRoots (protoRt .Paths ... )
83
+ if err != nil {
84
+ return nil , err
85
+ }
86
+
87
+ // attempt to figure out what the user wants without a lot of verbose specificity:
88
+ // if the user specifies a default rule, assume that they probably want to fall back
89
+ // to that. Otherwise, assume that they just wanted to customize one option from the
90
+ // set, and leave the rest in the standard configuration.
91
+ if protoRt .OutputRules .Default != nil {
92
+ genRuntime .OutputRules = protoRt .OutputRules
93
+ return genRuntime , nil
94
+ }
95
+
96
+ outRules := DirectoryPerGenerator ("config" , protoRt .GeneratorsByName )
97
+ for gen , rule := range protoRt .OutputRules .ByGenerator {
98
+ outRules .ByGenerator [gen ] = rule
99
+ }
100
+
101
+ genRuntime .OutputRules = outRules
102
+ return genRuntime , nil
103
+ }
104
+
105
+ // protoFromOptions returns a proto-Runtime from the given options registry and
106
+ // options set. This can then be used to construct an actual Runtime. See the
107
+ // FromOptions function for more details about how the options work.
108
+ func protoFromOptions (optionsRegistry * markers.Registry , options []string ) (protoRuntime , error ) {
60
109
var gens Generators
61
110
rules := OutputRules {
62
111
ByGenerator : make (map [Generator ]OutputRule ),
@@ -74,12 +123,12 @@ func FromOptions(optionsRegistry *markers.Registry, options []string) (*Runtime,
74
123
}
75
124
defn := optionsRegistry .Lookup (rawOpt , markers .DescribesPackage )
76
125
if defn == nil {
77
- return nil , fmt .Errorf ("unknown option %q" , rawOpt [1 :])
126
+ return protoRuntime {} , fmt .Errorf ("unknown option %q" , rawOpt [1 :])
78
127
}
79
128
80
129
val , err := defn .Parse (rawOpt )
81
130
if err != nil {
82
- return nil , fmt .Errorf ("unable to parse option %q: %v" , rawOpt [1 :], err )
131
+ return protoRuntime {} , fmt .Errorf ("unable to parse option %q: %v" , rawOpt [1 :], err )
83
132
}
84
133
85
134
switch val := val .(type ) {
@@ -99,42 +148,35 @@ func FromOptions(optionsRegistry *markers.Registry, options []string) (*Runtime,
99
148
case InputPaths :
100
149
paths = append (paths , val ... )
101
150
default :
102
- return nil , fmt .Errorf ("unknown option marker %q" , defn .Name )
151
+ return protoRuntime {} , fmt .Errorf ("unknown option marker %q" , defn .Name )
103
152
}
104
153
}
105
154
106
155
// actually associate the rules now that we know the generators
107
156
for genName , outputRule := range outputByGen {
108
157
gen , knownGen := gensByName [genName ]
109
158
if ! knownGen {
110
- return nil , fmt .Errorf ("non-invoked generator %q" , genName )
159
+ return protoRuntime {} , fmt .Errorf ("non-invoked generator %q" , genName )
111
160
}
112
161
113
162
rules .ByGenerator [gen ] = outputRule
114
163
}
115
164
116
- // make the runtime
117
- genRuntime , err := Generators (gens ).ForRoots (paths ... )
118
- if err != nil {
119
- return nil , err
120
- }
121
-
122
- // attempt to figure out what the user wants without a lot of verbose specificity:
123
- // if the user specifies a default rule, assume that they probably want to fall back
124
- // to that. Otherwise, assume that they just wanted to customize one option from the
125
- // set, and leave the rest in the standard configuration.
126
- if rules .Default != nil {
127
- genRuntime .OutputRules = rules
128
- return genRuntime , nil
129
- }
130
-
131
- outRules := DirectoryPerGenerator ("config" , gensByName )
132
- for gen , rule := range rules .ByGenerator {
133
- outRules .ByGenerator [gen ] = rule
134
- }
165
+ return protoRuntime {
166
+ Paths : paths ,
167
+ Generators : Generators (gens ),
168
+ OutputRules : rules ,
169
+ GeneratorsByName : gensByName ,
170
+ }, nil
171
+ }
135
172
136
- genRuntime .OutputRules = outRules
137
- return genRuntime , nil
173
+ // protoRuntime represents the raw pieces needed to compose a runtime, as
174
+ // parsed from some options.
175
+ type protoRuntime struct {
176
+ Paths []string
177
+ Generators Generators
178
+ OutputRules OutputRules
179
+ GeneratorsByName map [string ]Generator
138
180
}
139
181
140
182
// splitOutputRuleOption splits a marker name of "output:rule:gen" or "output:rule"
0 commit comments