Skip to content

Commit 56ad762

Browse files
committed
refactor: clean up codeql_test_run.py
1 parent ca7cece commit 56ad762

1 file changed

Lines changed: 41 additions & 48 deletions

File tree

‎misc/just/codeql_test_run.py‎

Lines changed: 41 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import re
1616
import subprocess
1717
import sys
18+
import shutil
1819
from pathlib import Path
1920

2021
JUST = os.environ.get("JUST_EXECUTABLE", "just")
@@ -23,12 +24,12 @@
2324
CMD_END = os.environ.get("CMD_END", "")
2425
SEMMLE_CODE = os.environ.get("SEMMLE_CODE")
2526

26-
ENV_RE = re.compile(r"^[A-Z_][A-Z_0-9]*=.*$")
27+
ENV_RE = re.compile(r"(^[A-Z_][A-Z_0-9]*)=(.*)$")
2728

2829

2930
def invoke(invocation, *, cwd=None, log_prefix=""):
3031
prefix = f"{log_prefix} " if log_prefix else ""
31-
print(f"{CMD_BEGIN}{prefix}{' '.join(invocation)}{CMD_END}")
32+
print(f"{CMD_BEGIN}{prefix}{' '.join(map(str, invocation))}{CMD_END}")
3233
try:
3334
subprocess.run(invocation, check=True, cwd=cwd)
3435
except subprocess.CalledProcessError as e:
@@ -61,11 +62,11 @@ def build_parser():
6162
parser.add_argument("--codeql", default="build" if SEMMLE_CODE else "host")
6263
parser.add_argument("--extra-check", action="append", dest="extra_checks")
6364
parser.add_argument("--all-checks", "+", action="store_true", dest="all")
64-
parser.set_defaults(extra_checks=[], tests=[], flags=[], env=[])
65+
parser.set_defaults(extra_checks=[], tests=[], flags=[], env={})
6566
return parser
6667

6768

68-
def parse_arguments(argv):
69+
def parse_arguments():
6970
"""Sort a command line into the kinds that are handled differently.
7071
7172
`argparse` owns the options this script acts on itself. Everything else belongs to
@@ -74,33 +75,44 @@ def parse_arguments(argv):
7475
positionals, told apart only by how they look.
7576
"""
7677
# An empty argument can come from a caller interpolating an unset variable.
77-
args, rest = build_parser().parse_known_args([arg for arg in argv if arg])
78+
args, rest = build_parser().parse_known_args()
7879
for arg in rest:
79-
if arg.startswith("-"):
80+
if not arg:
81+
pass
82+
elif arg.startswith("-"):
8083
args.flags.append(arg)
81-
elif ENV_RE.match(arg):
82-
args.env.append(arg)
84+
elif m := ENV_RE.match(arg):
85+
k, v = m.groups()
86+
args.env[k] = v
8387
else:
8488
args.tests.append(arg)
8589
return args
8690

8791

88-
def env_value(args, name, default):
89-
"""Resolve a setting from test arguments, then the environment, then a default."""
90-
for assignment in reversed(args.env):
91-
key, _, value = assignment.partition("=")
92-
if key == name and value:
93-
return value
94-
return os.environ.get(name) or default
95-
92+
def resolve_codeql(args: argparse.Namespace) -> Path:
93+
suffix = ".exe" if sys.platform == "win32" else ""
94+
match args.codeql:
95+
case "built" | "build":
96+
return Path(
97+
SEMMLE_CODE, "target", "intree", f"codeql-{args.language}", "codeql"
98+
).with_suffix(suffix)
99+
case "host":
100+
return Path(shutil.which("codeql" + suffix))
101+
case _:
102+
codeql = Path(args.codeql)
103+
if codeql.is_dir():
104+
codeql /= "codeql"
105+
return codeql.with_suffix(suffix)
106+
96107

97108
def main():
98-
argv = sys.argv[1:]
99-
args = parse_arguments(argv)
109+
args = parse_arguments()
110+
100111
if args.all:
101112
# Apply what the language offered by parsing it alongside everything else, so an
102113
# offered check lands exactly where the same flag typed by hand would.
103-
args = parse_arguments(argv + args.extra_checks)
114+
sys.argv[1:1] = args.extra_checks
115+
args = parse_arguments()
104116

105117
if not SEMMLE_CODE and args.codeql in ("build", "built"):
106118
error(
@@ -112,52 +124,33 @@ def main():
112124
if not args.tests:
113125
args.tests.append(".")
114126

127+
os.environ.update(args.env)
128+
115129
# Resolve these only once all arguments are known, so that a `RAM_PER_THREAD=` test
116130
# argument can lower the default on memory-heavy suites.
117131
default_ram = 3000 if sys.platform == "linux" else 2048
118-
ram_per_thread = int(env_value(args, "RAM_PER_THREAD", default_ram))
119-
cpus = int(env_value(args, "CPUS", os.cpu_count() or 1))
132+
ram_per_thread = int(os.environ.get("RAM_PER_THREAD", default_ram))
133+
cpus = int(os.environ.get("CPUS", os.cpu_count() or 1))
120134
args.flags[:0] = [f"--ram={ram_per_thread * cpus}", f"-j{cpus}"]
121135

122136
if args.codeql == "build":
123-
if invoke([JUST, args.language, "build"], cwd=SEMMLE_CODE) != 0:
124-
return 1
137+
if ret := invoke([JUST, args.language, "build"], cwd=SEMMLE_CODE):
138+
return ret
125139

126140
if args.codeql != "host":
127141
# Disable the default implicit config file, but keep an explicit one.
128142
# Same behavior wrt --codeql as the integration test runner.
129143
os.environ.setdefault("CODEQL_CONFIG_FILE", ".")
130144

131-
for env_var in args.env:
132-
key, _, value = env_var.partition("=")
133-
os.environ[key] = value
134-
135-
# Resolve codeql executable
136-
if args.codeql in ("built", "build"):
137-
codeql = Path(
138-
SEMMLE_CODE, "target", "intree", f"codeql-{args.language}", "codeql"
139-
)
140-
elif args.codeql == "host":
141-
codeql = Path("codeql")
142-
else:
143-
codeql = Path(args.codeql)
144-
145-
if codeql.is_dir():
146-
codeql = codeql / "codeql"
147-
148-
# On Windows, prefer codeql.exe over the Unix shell wrapper
149-
if sys.platform == "win32" and codeql.suffix != ".exe":
150-
exe = codeql.with_suffix(".exe")
151-
if exe.exists():
152-
codeql = exe
145+
codeql = resolve_codeql(args)
153146

154-
if args.codeql != "host" and not codeql.exists():
147+
if not codeql.exists():
155148
error(f"CodeQL executable not found: {codeql}")
156149
return 1
157150

158151
return invoke(
159-
[str(codeql), "test", "run", *args.flags, "--", *args.tests],
160-
log_prefix=" ".join(args.env),
152+
[codeql, "test", "run", *args.flags, "--", *args.tests],
153+
log_prefix=" ".join(f"{k}={v}" for k, v in args.env.items()),
161154
)
162155

163156

0 commit comments

Comments
 (0)