blob: 79898c8e48b5b9fd62d156345ac8c03c54eb8e5c [file] [log] [blame]
#!/usr/bin/env python3
# SPDX-License-Identifier: BSD-3-Clause
#
# Copyright (c) 2022-2023, Arm Limited. All rights reserved.
"""Merge json files and print the result to STDOUT.
Source files are specified with a list of file names. Any name in the list can
be a glob pattern. Glob patterns act if the returned list of file names were
passed instead. The list returned by glob is not sorted. All files are
processed in the order being found in the argument list.
Note: do not forget to quote globing patterns when running the tool from a
shell.
"""
import argparse
import errno
import glob
import json
import logging
import os.path
import sys
# initialize logger
logging.getLogger('merge_json')
logging.basicConfig(level=logging.ERROR)
def parse_arguments(args):
parser = argparse.ArgumentParser(
prog=os.path.basename(args[0]),
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument(
"-e", "--exclude",
default=None,
metavar="<exclude pattern>",
help="Exclude files matching this pattern.")
parser.add_argument(
"-o", "--output_file",
default=None,
metavar="<path to output file>",
help="Write result to this file instead of STDOUT")
parser.add_argument(
"-v",
action='append_const', const='v',
metavar="<verbosity level>",
help="Set the amount of information printed to STDERR." +
" Passing more times gives more info.")
parser.add_argument(
"-i", "--ignore-missing",
dest="ignore_missing",
action='store_const', const=True, default=False,
help="Ignore missing source files or source globs returning" +
" empty result.")
parser.add_argument(
'source_list',
nargs="+",
metavar="<source file>",
help="List of source files (file name can be glob pattern).")
parsed_args = parser.parse_args(args[1:])
# Count -v arguments to logging level
if parsed_args.v:
llv = len(parsed_args.v)
if llv > 3:
llv = 3
else:
llv = 0
parsed_args.log_level = [logging.ERROR, logging.WARNING, logging.INFO,
logging.DEBUG][llv]
return (parsed_args)
def merge_files(parsed_args):
logger = logging.getLogger('merge_json')
logger.info(
"Merging " + str(parsed_args.source_list) + " to " +
(parsed_args.output_file if parsed_args.output_file else "STDOUT"))
result = {}
exclude_list = None
if parsed_args.exclude:
exclude_list = glob.glob(parsed_args.exclude, recursive=True)
if exclude_list:
logger.debug("Excluding files: %s" % exclude_list)
else:
logger.warning("Exclude pattern matches no files.")
for pattern in parsed_args.source_list:
file_list = glob.glob(pattern, recursive=True)
logger.debug("Globing " + pattern + " = " + str(file_list))
if not file_list:
logger.error("Pattern \"%s\" does not match any file" % pattern)
if not parsed_args.ignore_missing:
raise (FileNotFoundError(
errno.ENOENT,
"Pattern does not match any file",
pattern))
for file in list(file_list):
if exclude_list and file in list(exclude_list):
logger.debug("excluding file " + file)
continue
logger.debug("Reding source file " + file)
with open(file, "rt", encoding="utf8", errors="strict") as f:
result.update(json.load(f))
if parsed_args.output_file is not None:
path = os.path.dirname(parsed_args.output_file)
if path:
os.makedirs(path, exist_ok=True)
with open(parsed_args.output_file, "w", encoding="utf8") as f:
json.dump(result, f, indent=4)
else:
print(json.dumps(result, indent=4))
if __name__ == "__main__":
parsed_args = parse_arguments(sys.argv)
logger = logging.getLogger('merge_json')
logger.setLevel(parsed_args.log_level)
merge_files(parsed_args)