Enable merge_json.py to handle multiple input files

Rewrite merge_json.py to enable merging multiple input files into a
single JSON file. Also adding a mechanism for update the relative paths
in the JSON file, so their base directory will be the parent directory
of the merged JSON file.

Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: Ia9452d1e1a0a7916c48e61ff4cbe0986fa370730
diff --git a/tools/python/merge_json.py b/tools/python/merge_json.py
index 68ad10b..1479d8c 100644
--- a/tools/python/merge_json.py
+++ b/tools/python/merge_json.py
@@ -4,24 +4,52 @@
 # Copyright (c) 2022, Arm Limited. All rights reserved.
 
 """
-Merge two json files, the second is merged into the first. If the first file
-doesn't exists yet, it will be created, along with its parent directories.
+Merge multiple json files in the order of the command line arguments.
 """
 
+import argparse
 import json
-import os.path
-import sys
+import os
 
-if os.path.isfile(sys.argv[1]):
-    with open(sys.argv[1], "rt", encoding="ascii") as f:
-        combined = json.load(f)
-else:
-    os.makedirs(os.path.dirname(sys.argv[1]), exist_ok=True)
-    combined = {}
+def update_relative_path(path, original_json_path, merged_json_path):
+    """
+    Update relative path according to its original and new base directory.
+    """
+    original_base_dir = os.path.dirname(original_json_path)
+    merged_base_dir = os.path.dirname(merged_json_path)
 
-with open(sys.argv[2], "rt", encoding="ascii") as f:
-    current = json.load(f)
-    combined = {**combined, **current}
+    return os.path.relpath(original_base_dir + "/" + path, merged_base_dir)
 
-with open(sys.argv[1], "wt", encoding="ascii") as f:
-    json.dump(combined, f, indent=4)
+parser = argparse.ArgumentParser(
+    prog="merge_json",
+    description="Merge multiple JSON files into a single file.",
+    epilog="The merge happens in the order of command line arguments.")
+parser.add_argument("output", help="Output JSON file")
+parser.add_argument("inputs", nargs="+", help="Input JSON files")
+
+args = parser.parse_args()
+
+json_combined = {}
+
+for input_json_path in args.inputs:
+    print(f"Adding {input_json_path}")
+    with open(input_json_path, "rt", encoding="ascii") as f:
+        json_fragment = json.load(f)
+
+        # Align relative paths to merged JSON file's path
+        # The original JSON fragment and the merged JSON file might be placed
+        # in a different directory. This requires updating the relative paths
+        # in the JSON, so the merged file can have paths relative to itself.
+        keys = list(json_fragment.keys())
+        assert keys
+        sp = keys[0]
+
+        json_fragment[sp]["image"] = update_relative_path(
+            json_fragment[sp]["image"], input_json_path, args.output)
+        json_fragment[sp]["pm"] = update_relative_path(
+            json_fragment[sp]["pm"], input_json_path, args.output)
+
+        json_combined = {**json_combined, **json_fragment}
+
+with open(args.output, "wt", encoding="ascii") as f:
+    json.dump(json_combined, f, indent=4)