Skip to content

Commit 762d79f

Browse files
committed
Initial implementation of metadata merger
1 parent 3fdd735 commit 762d79f

File tree

3 files changed

+112
-0
lines changed

3 files changed

+112
-0
lines changed

src/BUILD

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ py_binary(
55
visibility = ["//visibility:public"],
66
)
77

8+
py_binary(
9+
name = "metadata_merge",
10+
srcs = ["metadata_merge.py"],
11+
visibility = ["//visibility:public"],
12+
)
13+
814
# Build & Test script template
915
exports_files(
1016
["codechecker_script.py"],

src/code_checker.bzl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,18 @@ def _code_checker_impl(ctx):
322322
sources_and_headers,
323323
)
324324
all_files += outputs
325+
# merge metadata
326+
metadata = [file for file in all_files if file.path.endswith("metadata.json")]
327+
metadata_json = ctx.actions.declare_file(ctx.attr.name + "/data/metadata.json")
328+
ctx.actions.run(
329+
inputs = metadata,
330+
outputs = [metadata_json],
331+
executable = ctx.executable._metadata_merge_script,
332+
arguments = [metadata_json.path] + [file.path for file in metadata],
333+
mnemonic = "Metadata",
334+
progress_message = "Merging metadata.json"
335+
)
336+
all_files.append(metadata_json)
325337
ctx.actions.write(
326338
output = ctx.outputs.test_script,
327339
is_executable = True,
@@ -360,6 +372,14 @@ code_checker_test = rule(
360372
],
361373
doc = "List of default CodeChecker analyze options",
362374
),
375+
"_metadata_merge_script": attr.label(
376+
default = ":metadata_merge",
377+
executable = True,
378+
cfg = 'exec',
379+
),
380+
"_python_runtime": attr.label(
381+
default = "@default_python_tools//:py3_runtime",
382+
),
363383
"targets": attr.label_list(
364384
aspects = [
365385
compile_info_aspect,

src/metadata_merge.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import json
2+
import os
3+
import sys
4+
from typing import List, Dict, Any
5+
6+
7+
def merge_two_json(json1, json2):
8+
if json1 == {}:
9+
return json2
10+
if json2 == {}:
11+
return json1
12+
json1_root = json1["tools"][0]
13+
json2_root = json2["tools"][0]
14+
# We append info from json2 to json1 from here on out
15+
json1_root["result_source_files"].update(json2_root["result_source_files"])
16+
json1_root["skipped"] = json1_root["skipped"] + json2_root["skipped"]
17+
# Merge time
18+
json1_root["timestamps"]["begin"] = min(
19+
float(json1_root["timestamps"]["begin"]),
20+
float(json2_root["timestamps"]["begin"]),
21+
)
22+
json1_root["timestamps"]["end"] = max(
23+
float(json1_root["timestamps"]["end"]),
24+
float(json2_root["timestamps"]["end"]),
25+
)
26+
# Merge analyzers
27+
for key, value in json2_root["analyzers"].items():
28+
json1_stat = json1_root["analyzers"][key]["analyzer_statistics"]
29+
json2_stat = json2_root["analyzers"][key]["analyzer_statistics"]
30+
json1_stat["failed"] = json1_stat["failed"] + json2_stat["failed"]
31+
json1_stat["failed_sources"].extend(json2_stat["failed_sources"])
32+
json1_stat["successful"] = (
33+
json1_stat["successful"] + json2_stat["successful"]
34+
)
35+
json1_stat["successful_sources"].extend(
36+
json2_stat["successful_sources"]
37+
)
38+
return json1
39+
40+
41+
def merge_json_files(file_paths: List[str]) -> Dict[str, Any]:
42+
merged_data = {}
43+
for file_path in file_paths:
44+
if not os.path.exists(file_path):
45+
print(
46+
f"Error: File not found at '{file_path}'. Skipping.",
47+
file=sys.stderr,
48+
)
49+
continue
50+
51+
try:
52+
with open(file_path, "r", encoding="utf-8") as f:
53+
data = json.load(f)
54+
merged_data = merge_two_json(merged_data, data)
55+
except json.JSONDecodeError:
56+
print(
57+
f"Error: Could not decode JSON from '{file_path}'. Skipping.",
58+
file=sys.stderr,
59+
)
60+
except Exception as e:
61+
print(
62+
f"An unexpected error occurred while processing '{file_path}': {e}",
63+
file=sys.stderr,
64+
)
65+
66+
return merged_data
67+
68+
69+
def save_json_file(data: Dict[str, Any], output_path: str) -> None:
70+
try:
71+
with open(output_path, "w", encoding="utf-8") as f:
72+
json.dump(data, f, indent=4)
73+
print(f"\nSuccessfully saved merged data to '{output_path}'")
74+
except Exception as e:
75+
print(f"An error occurred while saving the file: {e}", file=sys.stderr)
76+
77+
78+
if __name__ == "__main__":
79+
output_file = sys.argv[1]
80+
input_files = sys.argv[2:]
81+
82+
merged_data = merge_json_files(input_files)
83+
if merged_data:
84+
save_json_file(merged_data, output_file)
85+
else:
86+
print("\nNo data was merged. Output file will not be created.")

0 commit comments

Comments
 (0)