| 222 | } |
| 223 | |
| 224 | func copyProps(src, dst interface{}, asType string) (err error) { |
| 225 | var ( |
| 226 | srcVal = reflect.ValueOf(src) |
| 227 | dstVal = reflect.ValueOf(dst).Elem() |
| 228 | ) |
| 229 | debug.Assertf(cos.StringInSlice(asType, []string{apc.Daemon, apc.Cluster}), "unexpected config level: %s", asType) |
| 230 | |
| 231 | for i := 0; i < srcVal.NumField(); i++ { |
| 232 | copyTag, ok := srcVal.Type().Field(i).Tag.Lookup("copy") |
| 233 | if ok && copyTag == "skip" { |
| 234 | continue |
| 235 | } |
| 236 | |
| 237 | var ( |
| 238 | srcValField = srcVal.Field(i) |
| 239 | fieldName = srcVal.Type().Field(i).Name |
| 240 | dstValField = dstVal.FieldByName(fieldName) |
| 241 | ) |
| 242 | |
| 243 | if srcValField.IsNil() { |
| 244 | continue |
| 245 | } |
| 246 | |
| 247 | t, ok := dstVal.Type().FieldByName(fieldName) |
| 248 | debug.AssertMsg(ok, fieldName) |
| 249 | // NOTE: the tag is used exclusively to enforce local vs global scope of the config var |
| 250 | allowed := t.Tag.Get("allow") |
| 251 | if allowed != "" && allowed != asType { |
| 252 | return fmt.Errorf("cannot set property %s with config level %q as %q", |
| 253 | fieldName, allowed, asType) |
| 254 | } |
| 255 | |
| 256 | if dstValField.Kind() != reflect.Struct && dstValField.Kind() != reflect.Invalid { |
| 257 | // Set value for the field |
| 258 | if srcValField.Kind() != reflect.Ptr { |
| 259 | dstValField.Set(srcValField) |
| 260 | } else { |
| 261 | dstValField.Set(srcValField.Elem()) |
| 262 | } |
| 263 | } else { |
| 264 | // Recurse into struct |
| 265 | err = copyProps(srcValField.Elem().Interface(), dstValField.Addr().Interface(), asType) |
| 266 | if err != nil { |
| 267 | return |
| 268 | } |
| 269 | } |
| 270 | } |
| 271 | return |
| 272 | } |
| 273 | |
| 274 | func mergeProps(src, dst interface{}) { |
| 275 | var ( |