OLD | NEW |
1 // Copyright 2016 The LUCI Authors. All rights reserved. | 1 // Copyright 2016 The LUCI Authors. All rights reserved. |
2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
4 | 4 |
5 package flagpb | 5 package flagpb |
6 | 6 |
7 import ( | 7 import ( |
8 "bytes" | 8 "bytes" |
9 "encoding/hex" | 9 "encoding/hex" |
10 "encoding/json" | 10 "encoding/json" |
11 "fmt" | 11 "fmt" |
12 "strconv" | 12 "strconv" |
13 "strings" | 13 "strings" |
14 | 14 |
| 15 "github.com/luci/luci-go/common/proto/google/descutil" |
| 16 |
15 "github.com/golang/protobuf/jsonpb" | 17 "github.com/golang/protobuf/jsonpb" |
16 "github.com/golang/protobuf/proto" | 18 "github.com/golang/protobuf/proto" |
17 » "github.com/luci/luci-go/common/proto/google/descriptor" | 19 » "google.golang.org/genproto/protobuf" |
18 ) | 20 ) |
19 | 21 |
20 // UnmarshalMessage unmarshals the proto message from flags. | 22 // UnmarshalMessage unmarshals the proto message from flags. |
21 // | 23 // |
22 // The descriptor set should be obtained from the `cproto` compiled packages' | 24 // The descriptor set should be obtained from the `cproto` compiled packages' |
23 // FileDescriptorSet() method. | 25 // FileDescriptorSet() method. |
24 func UnmarshalMessage(flags []string, resolver Resolver, msg proto.Message) erro
r { | 26 func UnmarshalMessage(flags []string, resolver Resolver, msg proto.Message) erro
r { |
25 // TODO(iannucci): avoid round-trip through parser and jsonpb and popula
te the | 27 // TODO(iannucci): avoid round-trip through parser and jsonpb and popula
te the |
26 // message directly. This would involve writing some additional reflecti
on | 28 // message directly. This would involve writing some additional reflecti
on |
27 // code that may depend on implementation details of proto's generated G
o | 29 // code that may depend on implementation details of proto's generated G
o |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 target := &root | 125 target := &root |
124 if len(pathMsgs) > 0 { | 126 if len(pathMsgs) > 0 { |
125 lastMsg := pathMsgs[len(pathMsgs)-1] | 127 lastMsg := pathMsgs[len(pathMsgs)-1] |
126 target = &lastMsg.message | 128 target = &lastMsg.message |
127 } | 129 } |
128 name := fieldPath[len(fieldPath)-1] | 130 name := fieldPath[len(fieldPath)-1] |
129 | 131 |
130 // Resolve target field. | 132 // Resolve target field. |
131 var fieldIndex int | 133 var fieldIndex int |
132 if target.desc.GetOptions().GetMapEntry() { | 134 if target.desc.GetOptions().GetMapEntry() { |
133 » » if fieldIndex = target.desc.FindField("value"); fieldIndex == -1
{ | 135 » » if fieldIndex = descutil.FindField(target.desc, "value"); fieldI
ndex == -1 { |
134 return nil, fmt.Errorf("map entry type %s does not have
value field", target.desc.GetName()) | 136 return nil, fmt.Errorf("map entry type %s does not have
value field", target.desc.GetName()) |
135 } | 137 } |
136 } else { | 138 } else { |
137 » » if fieldIndex = target.desc.FindField(name); fieldIndex == -1 { | 139 » » if fieldIndex = descutil.FindField(target.desc, name); fieldInde
x == -1 { |
138 return nil, fmt.Errorf("field %s not found in message %s
", name, target.desc.GetName()) | 140 return nil, fmt.Errorf("field %s not found in message %s
", name, target.desc.GetName()) |
139 } | 141 } |
140 } | 142 } |
141 field := target.desc.Field[fieldIndex] | 143 field := target.desc.Field[fieldIndex] |
142 | 144 |
143 var value interface{} | 145 var value interface{} |
144 hasValue := false | 146 hasValue := false |
145 | 147 |
146 if !hasValueStr { | 148 if !hasValueStr { |
147 switch { | 149 switch { |
148 // Boolean and repeated message fields may have no value and ign
ore | 150 // Boolean and repeated message fields may have no value and ign
ore |
149 // next argument. | 151 // next argument. |
150 case field.GetType() == descriptor.FieldDescriptorProto_TYPE_BOO
L: | 152 case field.GetType() == descriptor.FieldDescriptorProto_TYPE_BOO
L: |
151 value = true | 153 value = true |
152 hasValue = true | 154 hasValue = true |
153 » » case field.GetType() == descriptor.FieldDescriptorProto_TYPE_MES
SAGE && field.Repeated(): | 155 » » case field.GetType() == descriptor.FieldDescriptorProto_TYPE_MES
SAGE && descutil.Repeated(field): |
154 value = map[string]interface{}{} | 156 value = map[string]interface{}{} |
155 hasValue = true | 157 hasValue = true |
156 | 158 |
157 default: | 159 default: |
158 // Read next argument as a value. | 160 // Read next argument as a value. |
159 if len(flags) == 0 { | 161 if len(flags) == 0 { |
160 return nil, fmt.Errorf("value was expected") | 162 return nil, fmt.Errorf("value was expected") |
161 } | 163 } |
162 valueStr, flags = flags[0], flags[1:] | 164 valueStr, flags = flags[0], flags[1:] |
163 } | 165 } |
164 } | 166 } |
165 | 167 |
166 // Check if the value is already set. | 168 // Check if the value is already set. |
167 » if target.data[name] != nil && !field.Repeated() { | 169 » if target.data[name] != nil && !descutil.Repeated(field) { |
168 repeatedFields := make([]string, 0, len(pathMsgs)) | 170 repeatedFields := make([]string, 0, len(pathMsgs)) |
169 for _, m := range pathMsgs { | 171 for _, m := range pathMsgs { |
170 if m.repeated { | 172 if m.repeated { |
171 repeatedFields = append(repeatedFields, "-"+stri
ngs.Join(m.path, ".")) | 173 repeatedFields = append(repeatedFields, "-"+stri
ngs.Join(m.path, ".")) |
172 } | 174 } |
173 } | 175 } |
174 if len(repeatedFields) == 0 { | 176 if len(repeatedFields) == 0 { |
175 return nil, fmt.Errorf("value is already set to %v", tar
get.data[name]) | 177 return nil, fmt.Errorf("value is already set to %v", tar
get.data[name]) |
176 } | 178 } |
177 return nil, fmt.Errorf( | 179 return nil, fmt.Errorf( |
178 "value is already set to %v. Did you forgot to insert %s
in between to declare a new repeated message?", | 180 "value is already set to %v. Did you forgot to insert %s
in between to declare a new repeated message?", |
179 target.data[name], strings.Join(repeatedFields, " or ")) | 181 target.data[name], strings.Join(repeatedFields, " or ")) |
180 } | 182 } |
181 | 183 |
182 if !hasValue { | 184 if !hasValue { |
183 value, err = p.parseFieldValue(valueStr, target.desc.GetName(),
field) | 185 value, err = p.parseFieldValue(valueStr, target.desc.GetName(),
field) |
184 if err != nil { | 186 if err != nil { |
185 return nil, err | 187 return nil, err |
186 } | 188 } |
187 } | 189 } |
188 | 190 |
189 » if !field.Repeated() { | 191 » if !descutil.Repeated(field) { |
190 target.data[name] = value | 192 target.data[name] = value |
191 } else { | 193 } else { |
192 target.data[name] = append(asSlice(target.data[name]), value) | 194 target.data[name] = append(asSlice(target.data[name]), value) |
193 } | 195 } |
194 | 196 |
195 return flags, nil | 197 return flags, nil |
196 } | 198 } |
197 | 199 |
198 type subMsg struct { | 200 type subMsg struct { |
199 message | 201 message |
(...skipping 10 matching lines...) Expand all Loading... |
210 // If a field is not a message field, returns an error. | 212 // If a field is not a message field, returns an error. |
211 func (p *parser) subMessages(root message, path []string) ([]subMsg, error) { | 213 func (p *parser) subMessages(root message, path []string) ([]subMsg, error) { |
212 result := make([]subMsg, 0, len(path)) | 214 result := make([]subMsg, 0, len(path)) |
213 | 215 |
214 parent := &root | 216 parent := &root |
215 for i, name := range path { | 217 for i, name := range path { |
216 curPath := path[:i+1] | 218 curPath := path[:i+1] |
217 | 219 |
218 var fieldIndex int | 220 var fieldIndex int |
219 if parent.desc.GetOptions().GetMapEntry() { | 221 if parent.desc.GetOptions().GetMapEntry() { |
220 » » » if fieldIndex = parent.desc.FindField("value"); fieldInd
ex == -1 { | 222 » » » if fieldIndex = descutil.FindField(parent.desc, "value")
; fieldIndex == -1 { |
221 return nil, fmt.Errorf("map entry type %s does n
ot have value field", parent.desc.GetName()) | 223 return nil, fmt.Errorf("map entry type %s does n
ot have value field", parent.desc.GetName()) |
222 } | 224 } |
223 } else { | 225 } else { |
224 » » » if fieldIndex = parent.desc.FindField(name); fieldIndex
== -1 { | 226 » » » if fieldIndex = descutil.FindField(parent.desc, name); f
ieldIndex == -1 { |
225 return nil, fmt.Errorf("field %q not found in me
ssage %s", name, parent.desc.GetName()) | 227 return nil, fmt.Errorf("field %q not found in me
ssage %s", name, parent.desc.GetName()) |
226 } | 228 } |
227 } | 229 } |
228 | 230 |
229 f := parent.desc.Field[fieldIndex] | 231 f := parent.desc.Field[fieldIndex] |
230 if f.GetType() != descriptor.FieldDescriptorProto_TYPE_MESSAGE { | 232 if f.GetType() != descriptor.FieldDescriptorProto_TYPE_MESSAGE { |
231 return nil, fmt.Errorf("field %s is not a message", stri
ngs.Join(curPath, ".")) | 233 return nil, fmt.Errorf("field %s is not a message", stri
ngs.Join(curPath, ".")) |
232 } | 234 } |
233 | 235 |
234 subDescInterface, err := p.resolve(f.GetTypeName()) | 236 subDescInterface, err := p.resolve(f.GetTypeName()) |
235 if err != nil { | 237 if err != nil { |
236 return nil, err | 238 return nil, err |
237 } | 239 } |
238 subDesc, ok := subDescInterface.(*descriptor.DescriptorProto) | 240 subDesc, ok := subDescInterface.(*descriptor.DescriptorProto) |
239 if !ok { | 241 if !ok { |
240 return nil, fmt.Errorf("%s is not a message", f.GetTypeN
ame()) | 242 return nil, fmt.Errorf("%s is not a message", f.GetTypeN
ame()) |
241 } | 243 } |
242 | 244 |
243 sub := subMsg{ | 245 sub := subMsg{ |
244 message: message{desc: subDesc}, | 246 message: message{desc: subDesc}, |
245 » » » repeated: f.Repeated() && !subDesc.GetOptions().GetMapEn
try(), | 247 » » » repeated: descutil.Repeated(f) && !subDesc.GetOptions().
GetMapEntry(), |
246 path: curPath, | 248 path: curPath, |
247 } | 249 } |
248 if value, ok := parent.data[name]; !ok { | 250 if value, ok := parent.data[name]; !ok { |
249 sub.data = map[string]interface{}{} | 251 sub.data = map[string]interface{}{} |
250 if sub.repeated { | 252 if sub.repeated { |
251 parent.data[name] = []interface{}{sub.data} | 253 parent.data[name] = []interface{}{sub.data} |
252 } else { | 254 } else { |
253 parent.data[name] = sub.data | 255 parent.data[name] = sub.data |
254 } | 256 } |
255 } else { | 257 } else { |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
354 case 2: | 356 case 2: |
355 key = parts[0] | 357 key = parts[0] |
356 value = parts[1] | 358 value = parts[1] |
357 hasValue = true | 359 hasValue = true |
358 } | 360 } |
359 return | 361 return |
360 } | 362 } |
361 | 363 |
362 // parseEnum returns the number of an enum member, which can be name or number. | 364 // parseEnum returns the number of an enum member, which can be name or number. |
363 func parseEnum(enum *descriptor.EnumDescriptorProto, member string) (int32, erro
r) { | 365 func parseEnum(enum *descriptor.EnumDescriptorProto, member string) (int32, erro
r) { |
364 » i := enum.FindValue(member) | 366 » i := descutil.FindEnumValue(enum, member) |
365 if i < 0 { | 367 if i < 0 { |
366 // Is member the number? | 368 // Is member the number? |
367 if number, err := strconv.ParseInt(member, 10, 32); err == nil { | 369 if number, err := strconv.ParseInt(member, 10, 32); err == nil { |
368 » » » i = enum.FindValueByNumber(int32(number)) | 370 » » » i = descutil.FindValueByNumber(enum, int32(number)) |
369 } | 371 } |
370 } | 372 } |
371 if i < 0 { | 373 if i < 0 { |
372 return 0, fmt.Errorf("invalid value %q for enum %s", member, enu
m.GetName()) | 374 return 0, fmt.Errorf("invalid value %q for enum %s", member, enu
m.GetName()) |
373 } | 375 } |
374 return enum.Value[i].GetNumber(), nil | 376 return enum.Value[i].GetNumber(), nil |
375 } | 377 } |
376 | 378 |
377 func asSlice(x interface{}) []interface{} { | 379 func asSlice(x interface{}) []interface{} { |
378 if x == nil { | 380 if x == nil { |
379 return nil | 381 return nil |
380 } | 382 } |
381 return x.([]interface{}) | 383 return x.([]interface{}) |
382 } | 384 } |
OLD | NEW |