Skip to content

Commit 22cada3

Browse files
authored
Merge pull request #4245 from bruntib/query_checkers_script
[script] Script for querying all reports
2 parents f7e9d53 + 591495c commit 22cada3

File tree

2 files changed

+183
-0
lines changed

2 files changed

+183
-0
lines changed
+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# -------------------------------------------------------------------------
2+
#
3+
# Part of the CodeChecker project, under the Apache License v2.0 with
4+
# LLVM Exceptions. See LICENSE for license information.
5+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
#
7+
# -------------------------------------------------------------------------
8+
9+
import argparse
10+
import json
11+
import sys
12+
13+
def __sorted_results(result_file):
14+
return json.load(result_file).sort(
15+
key=lambda report: report['bugHash'] + str(report['reportId']))
16+
17+
def __print_missing(needles, haystack, haystack_name):
18+
for needle in needles:
19+
if needle not in haystack:
20+
print(f"Report not found in {haystack_name}:")
21+
print(json.dumps(needle, indent=4))
22+
return True
23+
return False
24+
25+
def main():
26+
parser = argparse.ArgumentParser(
27+
description="Compares two CodeChecker results. The results should be "
28+
"generated by 'CodeChecker cmd results' command.")
29+
30+
parser.add_argument(
31+
"result1",
32+
type=argparse.FileType("r"),
33+
help="Path of the first result.")
34+
35+
parser.add_argument(
36+
"result2",
37+
type=argparse.FileType("r"),
38+
help="Path of the second result.")
39+
40+
args = parser.parse_args()
41+
42+
result1 = __sorted_results(args.result1)
43+
result2 = __sorted_results(args.result2)
44+
45+
found_missing = False
46+
found_missing |= __print_missing(result1, result2, "result2")
47+
found_missing |= __print_missing(result2, result1, "result1")
48+
49+
args.result1.close()
50+
args.result2.close()
51+
52+
return 1 if found_missing else 0
53+
54+
if __name__ == '__main__':
55+
sys.exit(main())
+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# -------------------------------------------------------------------------
2+
#
3+
# Part of the CodeChecker project, under the Apache License v2.0 with
4+
# LLVM Exceptions. See LICENSE for license information.
5+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
#
7+
# -------------------------------------------------------------------------
8+
import argparse
9+
import functools
10+
import json
11+
import os
12+
import subprocess
13+
import sys
14+
from multiprocess import Pool
15+
from pathlib import Path
16+
from typing import List, Tuple
17+
18+
19+
def parse_args():
20+
"""
21+
Initialize global variables based on command line arguments. These
22+
variables are global because get_results() uses them. That function is used
23+
as a callback which doesn't get this info as parameters.
24+
"""
25+
parser = argparse.ArgumentParser(
26+
description="Fetch all reports of products")
27+
28+
parser.add_argument(
29+
'--url',
30+
default='localhost:8001',
31+
help='URL of a CodeChecker server.')
32+
33+
parser.add_argument(
34+
'--output',
35+
required=True,
36+
help='Output folder for generated JSON files.')
37+
38+
parser.add_argument(
39+
'-j', '--jobs',
40+
default=1,
41+
type=int,
42+
help='Get reports in this many parallel jobs.')
43+
44+
parser.add_argument(
45+
'--products',
46+
nargs='+',
47+
help='List of products to fetch reports for. By default, all products '
48+
'are fetched.')
49+
50+
return parser.parse_args()
51+
52+
53+
def __get_keys_from_list(out) -> List[str]:
54+
"""
55+
Get all keys from a JSON list.
56+
"""
57+
return map(lambda prod: next(iter(prod.keys())), json.loads(out))
58+
59+
60+
def result_getter(args: argparse.Namespace):
61+
def get_results(product_run: Tuple[str, str]):
62+
product, run = product_run
63+
print(product, run)
64+
65+
out, _ = subprocess.Popen([
66+
'CodeChecker', 'cmd', 'results', run,
67+
'-o', 'json',
68+
'--url', f'{args.url}/{product}'],
69+
stdout=subprocess.PIPE,
70+
stderr=subprocess.PIPE).communicate()
71+
72+
reports = sorted(
73+
json.loads(out), key=lambda report: report['reportId'])
74+
75+
run = run.replace('/', '_')
76+
with open(Path(args.output) / f'{product}_{run}.json', 'w',
77+
encoding='utf-8') as f:
78+
json.dump(reports, f)
79+
80+
return get_results
81+
82+
83+
def get_all_products(url: str) -> List[str]:
84+
"""
85+
Get all products from a CodeChecker server.
86+
87+
:param url: URL of a CodeChecker server.
88+
:return: List of product names.
89+
"""
90+
out, _ = subprocess.Popen(
91+
['CodeChecker', 'cmd', 'products', 'list', '-o', 'json', '--url', url],
92+
stdout=subprocess.PIPE,
93+
stderr=subprocess.DEVNULL).communicate()
94+
95+
return __get_keys_from_list(out)
96+
97+
98+
def dump_products(args: argparse.Namespace):
99+
for product in args.products:
100+
f = functools.partial(lambda p, r: (p, r), product)
101+
with subprocess.Popen([
102+
'CodeChecker', 'cmd', 'runs',
103+
'--url', f'{args.url}/{product}',
104+
'-o', 'json'],
105+
stdout=subprocess.PIPE,
106+
stderr=subprocess.PIPE
107+
) as proc:
108+
runs = list(__get_keys_from_list(proc.stdout.read()))
109+
110+
with Pool(args.jobs) as p:
111+
p.map(result_getter(args), map(f, runs))
112+
113+
114+
def main():
115+
args = parse_args()
116+
117+
os.makedirs(args.output, exist_ok=True)
118+
119+
if not args.products:
120+
args.products = get_all_products(args.url)
121+
122+
dump_products(args)
123+
124+
return 0
125+
126+
127+
if __name__ == '__main__':
128+
sys.exit(main())

0 commit comments

Comments
 (0)