blob: 79898c8e48b5b9fd62d156345ac8c03c54eb8e5c [file] [log] [blame]
Balint Dobszay9e2573d2022-08-10 15:15:21 +02001#!/usr/bin/env python3
2# SPDX-License-Identifier: BSD-3-Clause
3#
Gyorgy Szingcacf18d2023-01-18 19:08:58 +00004# Copyright (c) 2022-2023, Arm Limited. All rights reserved.
Balint Dobszay9e2573d2022-08-10 15:15:21 +02005
Gyorgy Szingcacf18d2023-01-18 19:08:58 +00006"""Merge json files and print the result to STDOUT.
7
8Source files are specified with a list of file names. Any name in the list can
9be a glob pattern. Glob patterns act if the returned list of file names were
10passed instead. The list returned by glob is not sorted. All files are
11processed in the order being found in the argument list.
12
13Note: do not forget to quote globing patterns when running the tool from a
14 shell.
Balint Dobszay9e2573d2022-08-10 15:15:21 +020015"""
16
Gyorgy Szingcacf18d2023-01-18 19:08:58 +000017import argparse
18import errno
19import glob
Balint Dobszay9e2573d2022-08-10 15:15:21 +020020import json
Gyorgy Szingcacf18d2023-01-18 19:08:58 +000021import logging
Balint Dobszay9e2573d2022-08-10 15:15:21 +020022import os.path
23import sys
24
Gyorgy Szingcacf18d2023-01-18 19:08:58 +000025# initialize logger
26logging.getLogger('merge_json')
27logging.basicConfig(level=logging.ERROR)
Balint Dobszay9e2573d2022-08-10 15:15:21 +020028
Balint Dobszay9e2573d2022-08-10 15:15:21 +020029
Gyorgy Szingcacf18d2023-01-18 19:08:58 +000030def parse_arguments(args):
31 parser = argparse.ArgumentParser(
32 prog=os.path.basename(args[0]),
33 description=__doc__,
34 formatter_class=argparse.RawDescriptionHelpFormatter)
35 parser.add_argument(
36 "-e", "--exclude",
37 default=None,
38 metavar="<exclude pattern>",
39 help="Exclude files matching this pattern.")
40 parser.add_argument(
41 "-o", "--output_file",
42 default=None,
43 metavar="<path to output file>",
44 help="Write result to this file instead of STDOUT")
45 parser.add_argument(
46 "-v",
47 action='append_const', const='v',
48 metavar="<verbosity level>",
49 help="Set the amount of information printed to STDERR." +
50 " Passing more times gives more info.")
51 parser.add_argument(
52 "-i", "--ignore-missing",
53 dest="ignore_missing",
54 action='store_const', const=True, default=False,
55 help="Ignore missing source files or source globs returning" +
56 " empty result.")
57 parser.add_argument(
58 'source_list',
59 nargs="+",
60 metavar="<source file>",
61 help="List of source files (file name can be glob pattern).")
62 parsed_args = parser.parse_args(args[1:])
63 # Count -v arguments to logging level
64 if parsed_args.v:
65 llv = len(parsed_args.v)
66 if llv > 3:
67 llv = 3
68 else:
69 llv = 0
70 parsed_args.log_level = [logging.ERROR, logging.WARNING, logging.INFO,
71 logging.DEBUG][llv]
72 return (parsed_args)
73
74
75def merge_files(parsed_args):
76 logger = logging.getLogger('merge_json')
77
78 logger.info(
79 "Merging " + str(parsed_args.source_list) + " to " +
80 (parsed_args.output_file if parsed_args.output_file else "STDOUT"))
81
82 result = {}
83 exclude_list = None
84
85 if parsed_args.exclude:
86 exclude_list = glob.glob(parsed_args.exclude, recursive=True)
87 if exclude_list:
88 logger.debug("Excluding files: %s" % exclude_list)
89 else:
90 logger.warning("Exclude pattern matches no files.")
91
92 for pattern in parsed_args.source_list:
93 file_list = glob.glob(pattern, recursive=True)
94 logger.debug("Globing " + pattern + " = " + str(file_list))
95 if not file_list:
96 logger.error("Pattern \"%s\" does not match any file" % pattern)
97 if not parsed_args.ignore_missing:
98 raise (FileNotFoundError(
99 errno.ENOENT,
100 "Pattern does not match any file",
101 pattern))
102
103 for file in list(file_list):
104 if exclude_list and file in list(exclude_list):
105 logger.debug("excluding file " + file)
106 continue
107 logger.debug("Reding source file " + file)
108 with open(file, "rt", encoding="utf8", errors="strict") as f:
109 result.update(json.load(f))
110
111 if parsed_args.output_file is not None:
112 path = os.path.dirname(parsed_args.output_file)
113 if path:
114 os.makedirs(path, exist_ok=True)
115 with open(parsed_args.output_file, "w", encoding="utf8") as f:
116 json.dump(result, f, indent=4)
117 else:
118 print(json.dumps(result, indent=4))
119
120
121if __name__ == "__main__":
122 parsed_args = parse_arguments(sys.argv)
123 logger = logging.getLogger('merge_json')
124 logger.setLevel(parsed_args.log_level)
125 merge_files(parsed_args)