Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4de4277

Browse files
committed
Add timeseries CSV generator script
1 parent 270cf62 commit 4de4277

3 files changed

Lines changed: 144 additions & 28 deletions

File tree

misc/scripts/library-coverage/generate-report.py

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import subprocess
21
import csv
32
import sys
43
import os
54
import shutil
65
import settings
6+
import utils
77

88
"""
99
This script runs the CSV coverage report QL query, and transforms it to a more readable format.
@@ -12,30 +12,6 @@
1212
"""
1313

1414

15-
def subprocess_run(cmd):
16-
"""Runs a command through subprocess.run, with a few tweaks. Raises an Exception if exit code != 0."""
17-
return subprocess.run(cmd, capture_output=True, text=True, env=os.environ.copy(), check=True)
18-
19-
20-
def create_empty_database(lang, extension, database):
21-
"""Creates an empty database for the given language."""
22-
subprocess_run(["codeql", "database", "init", "--language=" + lang,
23-
"--source-root=/tmp/empty", "--allow-missing-source-root", database])
24-
subprocess_run(["mkdir", "-p", database + "/src/tmp/empty"])
25-
subprocess_run(["touch", database + "/src/tmp/empty/empty" + extension])
26-
subprocess_run(["codeql", "database", "finalize",
27-
database, "--no-pre-finalize"])
28-
29-
30-
def run_codeql_query(query, database, output):
31-
"""Runs a codeql query on the given database."""
32-
subprocess_run(["codeql", "query", "run", query,
33-
"--database", database, "--output", output + ".bqrs"])
34-
subprocess_run(["codeql", "bqrs", "decode", output + ".bqrs",
35-
"--format=csv", "--no-titles", "--output", output])
36-
os.remove(output + ".bqrs")
37-
38-
3915
def append_csv_number(list, value):
4016
"""Adds a number to the list or None if the value is not greater than 0."""
4117
if value > 0:
@@ -117,7 +93,7 @@ def __init__(self, lang, capitalized_lang, ext, ql_path):
11793

11894

11995
try: # Check for `codeql` on path
120-
subprocess_run(["codeql", "--version"])
96+
utils.subprocess_run(["codeql", "--version"])
12197
except Exception as e:
12298
print("Error: couldn't invoke CodeQL CLI 'codeql'. Is it on the path? Aborting.", file=sys.stderr)
12399
raise e
@@ -165,8 +141,8 @@ def __init__(self, lang, capitalized_lang, ext, ql_path):
165141
lang = config.lang
166142
db = "empty-" + lang
167143
ql_output = output_ql_csv.format(language=lang)
168-
create_empty_database(lang, config.ext, db)
169-
run_codeql_query(config.ql_path, db, ql_output)
144+
utils.create_empty_database(lang, config.ext, db)
145+
utils.run_codeql_query(config.ql_path, db, ql_output)
170146
shutil.rmtree(db)
171147

172148
packages = {}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import subprocess
2+
import csv
3+
import sys
4+
import os
5+
import shutil
6+
from datetime import date
7+
import datetime
8+
import utils
9+
10+
"""
11+
Gets the sink/source/summary statistics for different days.
12+
"""
13+
14+
# the distance between commits to include in the output
15+
day_distance = 1
16+
17+
# the directory where codeql is. This is the directory where we change the SHAs
18+
working_dir = sys.argv[1]
19+
20+
lang = "java"
21+
db = "empty-java"
22+
ql_output = "output-java.csv"
23+
csv_output = "timeseries-java.csv"
24+
25+
26+
def get_str_output(arr):
27+
r = subprocess.check_output(arr)
28+
return r.decode("utf-8").strip("\n'")
29+
30+
31+
def get_date(sha):
32+
d = get_str_output(
33+
["git", "show", "--no-patch", "--no-notes", "--pretty='%cd'", "--date=short", sha])
34+
return date.fromisoformat(d)
35+
36+
37+
def get_parent(sha, date):
38+
parent_sha = get_str_output(
39+
["git", "rev-parse", sha + "^"])
40+
parent_date = get_date(parent_sha)
41+
return (parent_sha, parent_date)
42+
43+
44+
def get_previous_sha(sha, date):
45+
parent_sha, parent_date = get_parent(sha, date)
46+
while parent_date > date + datetime.timedelta(days=-1 * day_distance):
47+
parent_sha, parent_date = get_parent(parent_sha, parent_date)
48+
49+
return (parent_sha, parent_date)
50+
51+
52+
def get_stats():
53+
if os.path.isdir(db):
54+
shutil.rmtree(db)
55+
utils.create_empty_database(lang, ".java", db)
56+
utils.run_codeql_query(
57+
"java/ql/src/meta/frameworks/Coverage.ql", db, ql_output)
58+
shutil.rmtree(db)
59+
60+
sources = 0
61+
sinks = 0
62+
summaries = 0
63+
64+
with open(ql_output) as csvfile:
65+
reader = csv.reader(csvfile)
66+
for row in reader:
67+
# row: "android.util",1,"remote","source",16
68+
if row[3] == "source":
69+
sources += int(row[4])
70+
if row[3] == "sink":
71+
sinks += int(row[4])
72+
if row[3] == "summary":
73+
summaries += int(row[4])
74+
75+
os.remove(ql_output)
76+
77+
return (sources, sinks, summaries)
78+
79+
80+
with open(csv_output, 'w', newline='') as csvfile:
81+
csvwriter = csv.writer(csvfile)
82+
csvwriter.writerow(["SHA", "Date", "Sources", "Sinks", "Summaries"])
83+
84+
os.chdir(working_dir)
85+
86+
utils.subprocess_run(["git", "checkout", "main"])
87+
88+
current_sha = get_str_output(["git", "rev-parse", "HEAD"])
89+
current_date = get_date(current_sha)
90+
91+
while True:
92+
print("Getting stats for " + current_sha)
93+
utils.subprocess_run(["git", "checkout", current_sha])
94+
95+
try:
96+
stats = get_stats()
97+
98+
csvwriter.writerow(
99+
[current_sha, current_date, stats[0], stats[1], stats[2]])
100+
101+
print("Collected stats for " + current_sha +
102+
" at " + current_date.isoformat())
103+
except:
104+
print("Unexpected error:", sys.exc_info()[0])
105+
106+
if os.path.isdir(db):
107+
shutil.rmtree(db)
108+
print("Error getting stats for " +
109+
current_sha + ". Stopping iteration.")
110+
break
111+
112+
current_sha, current_date = get_previous_sha(current_sha, current_date)
113+
114+
utils.subprocess_run(["git", "checkout", "main"])
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import subprocess
2+
import os
3+
4+
5+
def subprocess_run(cmd):
6+
"""Runs a command through subprocess.run, with a few tweaks. Raises an Exception if exit code != 0."""
7+
return subprocess.run(cmd, capture_output=True, text=True, env=os.environ.copy(), check=True)
8+
9+
10+
def create_empty_database(lang, extension, database):
11+
"""Creates an empty database for the given language."""
12+
subprocess_run(["codeql", "database", "init", "--language=" + lang,
13+
"--source-root=/tmp/empty", "--allow-missing-source-root", database])
14+
subprocess_run(["mkdir", "-p", database + "/src/tmp/empty"])
15+
subprocess_run(["touch", database + "/src/tmp/empty/empty" + extension])
16+
subprocess_run(["codeql", "database", "finalize",
17+
database, "--no-pre-finalize"])
18+
19+
20+
def run_codeql_query(query, database, output):
21+
"""Runs a codeql query on the given database."""
22+
subprocess_run(["codeql", "query", "run", query,
23+
"--database", database, "--output", output + ".bqrs"])
24+
subprocess_run(["codeql", "bqrs", "decode", output + ".bqrs",
25+
"--format=csv", "--no-titles", "--output", output])
26+
os.remove(output + ".bqrs")

0 commit comments

Comments
 (0)