xref: /aosp_15_r20/build/soong/scripts/merge_json.py (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1#!/usr/bin/env python
2#
3# Copyright 2024 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17"""A tool for merging two or more JSON files."""
18
19import argparse
20import logging
21import json
22import sys
23
24def parse_args():
25  """Parse commandline arguments."""
26
27  parser = argparse.ArgumentParser()
28  parser.add_argument("output", help="output JSON file", type=argparse.FileType("w"))
29  parser.add_argument("input", help="input JSON files", nargs="+", type=argparse.FileType("r"))
30  return parser.parse_args()
31
32def main():
33  """Program entry point."""
34  args = parse_args()
35  merged_dict = {}
36  has_error = False
37  logger = logging.getLogger(__name__)
38
39  for json_file in args.input:
40    try:
41      data = json.load(json_file)
42    except json.JSONDecodeError as e:
43      logger.error(f"Error parsing JSON in file: {json_file.name}. Reason: {e}")
44      has_error = True
45      continue
46
47    for key, value in data.items():
48      if key not in merged_dict:
49        merged_dict[key] = value
50      elif merged_dict[key] == value:
51        logger.warning(f"Duplicate key '{key}' with identical values found.")
52      else:
53        logger.error(f"Conflicting values for key '{key}': {merged_dict[key]} != {value}")
54        has_error = True
55
56  if has_error:
57    sys.exit(1)
58
59  json.dump(merged_dict, args.output)
60
61if __name__ == "__main__":
62  main()
63