aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/config/merge.go
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2021-11-17 12:36:48 +0000
committerAleksandr Nogikh <wp32pw@gmail.com>2021-11-19 19:06:55 +0100
commit780b27623e2c0284dfb0c8e0392463d1eef00e92 (patch)
treec8dcefe94021fc3e0a5693e082a9c3751c64997f /pkg/config/merge.go
parent3a9d0024ba818c5b37058d9ac6fdfc0ddfa78be6 (diff)
tools/syz-testbed: support per-checkout syz-manager configs
Let the user of the tool specify individual syz-manager configs for checkouts. A base config is specified as previously and then individual parts of jsons are applied to that base config, e.g. <...> "checkouts": [ { "name": "first", "repo": "https://github.com/google/syzkaller.git", }, { "name": "second", "repo": "https://github.com/google/syzkaller.git", "manager_config": { "kernel_obj": "/tmp/linux-stable2" } } ], "manager_config": { "target": "linux/amd64", "kernel_obj": "/tmp/linux-stable", <...> } <...>
Diffstat (limited to 'pkg/config/merge.go')
-rw-r--r--pkg/config/merge.go57
1 files changed, 57 insertions, 0 deletions
diff --git a/pkg/config/merge.go b/pkg/config/merge.go
new file mode 100644
index 000000000..49a7254de
--- /dev/null
+++ b/pkg/config/merge.go
@@ -0,0 +1,57 @@
+// Copyright 2021 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package config
+
+import (
+ "encoding/json"
+)
+
+// Unfortunately, if we want to apply a JSON patch to some configuration, we cannot just unmarshal
+// it twice - in that case json.RawMessage objects will be completely replaced, but not merged.
+func MergeJSONData(left, right []byte) ([]byte, error) {
+ vLeft, err := parseFragment(left)
+ if err != nil {
+ return nil, err
+ }
+ vRight, err := parseFragment(right)
+ if err != nil {
+ return nil, err
+ }
+ merged := mergeRecursive(vLeft, vRight)
+ return json.Marshal(merged)
+}
+
+func parseFragment(input []byte) (parsed interface{}, err error) {
+ if len(input) == 0 {
+ // For convenience, we allow empty strings to be passed to the function that merges JSONs.
+ return
+ }
+ err = json.Unmarshal(json.RawMessage(input), &parsed)
+ return
+}
+
+// If one of the elements is not a map, use the new one.
+// Otherwise, recursively merge map elements.
+func mergeRecursive(left, right interface{}) interface{} {
+ if left == nil {
+ return right
+ }
+ if right == nil {
+ return left
+ }
+ mLeft, okLeft := left.(map[string]interface{})
+ mRight, okRight := right.(map[string]interface{})
+ if !okLeft || !okRight {
+ return right
+ }
+ for key, val := range mRight {
+ valLeft, ok := mLeft[key]
+ if ok {
+ mLeft[key] = mergeRecursive(valLeft, val)
+ } else {
+ mLeft[key] = val
+ }
+ }
+ return mLeft
+}