github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/config/merge.go (about) 1 // Copyright 2021 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package config 5 6 import ( 7 "encoding/json" 8 ) 9 10 // Unfortunately, if we want to apply a JSON patch to some configuration, we cannot just unmarshal 11 // it twice - in that case json.RawMessage objects will be completely replaced, but not merged. 12 func MergeJSONs(left, right []byte) ([]byte, error) { 13 vLeft, err := parseFragment(left) 14 if err != nil { 15 return nil, err 16 } 17 vRight, err := parseFragment(right) 18 if err != nil { 19 return nil, err 20 } 21 return json.Marshal(mergeRecursive(vLeft, vRight)) 22 } 23 24 // Recursively apply a patch to a raw JSON data. 25 // Patch is supposed to be a map, which possibly nests other map objects. 26 func PatchJSON(left []byte, patch map[string]interface{}) ([]byte, error) { 27 vLeft, err := parseFragment(left) 28 if err != nil { 29 return nil, err 30 } 31 return json.Marshal(mergeRecursive(vLeft, patch)) 32 } 33 34 func parseFragment(input []byte) (parsed interface{}, err error) { 35 if len(input) == 0 { 36 // For convenience, we allow empty strings to be passed to the function that merges JSONs. 37 return 38 } 39 err = json.Unmarshal(json.RawMessage(input), &parsed) 40 return 41 } 42 43 // If one of the elements is not a map, use the new one. 44 // Otherwise, recursively merge map elements. 45 func mergeRecursive(left, right interface{}) interface{} { 46 if left == nil { 47 return right 48 } 49 if right == nil { 50 return left 51 } 52 mLeft, okLeft := left.(map[string]interface{}) 53 mRight, okRight := right.(map[string]interface{}) 54 if !okLeft || !okRight { 55 return right 56 } 57 for key, val := range mRight { 58 valLeft, ok := mLeft[key] 59 if ok { 60 mLeft[key] = mergeRecursive(valLeft, val) 61 } else { 62 mLeft[key] = val 63 } 64 } 65 return mLeft 66 }