| 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 |