Skip to content

Commit c44eadc

Browse files
committed
Use arguments instead of environment variables
1 parent 21bd649 commit c44eadc

2 files changed

Lines changed: 96 additions & 74 deletions

File tree

src/codechecker.bzl

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -96,25 +96,24 @@ def _codechecker_impl(ctx):
9696
config_file, codechecker_env = get_config_file(ctx)
9797

9898
codechecker_files = ctx.actions.declare_directory(ctx.label.name + "/codechecker-files")
99-
100-
# Use environment variables instead of expand_template
101-
environment_variables = {
102-
"RULES_CODECHECKER_MODE": "Run",
103-
"RULES_CODECHECKER_VERBOSITY": "DEBUG",
104-
"RULES_CODECHECKER_CODECHECKER_BIN": CODECHECKER_BIN_PATH,
105-
"RULES_CODECHECKER_COMPILE_COMMANDS": ctx.outputs.codechecker_commands.path,
106-
"RULES_CODECHECKER_CODECHECKER_SKIPFILE": ctx.outputs.codechecker_skipfile.path,
107-
"RULES_CODECHECKER_CODECHECKER_CONFIG": config_file.path,
108-
"RULES_CODECHECKER_CODECHECKER_ANALYZE": " ".join(ctx.attr.analyze),
109-
"RULES_CODECHECKER_CODECHECKER_FILES": codechecker_files.path,
110-
"RULES_CODECHECKER_CODECHECKER_LOG": ctx.outputs.codechecker_log.path,
111-
"RULES_CODECHECKER_CODECHECKER_ENV": codechecker_env,
112-
}
99+
113100
codechecker_script = ctx.actions.declare_file(ctx.label.name + "/codechecker_script")
114101
ctx.actions.symlink(
115102
output = codechecker_script,
116103
target_file = ctx.executable._codechecker_script,
117104
)
105+
cmd_args = ctx.actions.args()
106+
cmd_args.add("--mode", "Run")
107+
cmd_args.add("--verbosity", "DEBUG")
108+
cmd_args.add("--codechecker_path", CODECHECKER_BIN_PATH)
109+
cmd_args.add("--commands", ctx.outputs.codechecker_commands.path)
110+
cmd_args.add("--skip", ctx.outputs.codechecker_skipfile.path)
111+
cmd_args.add("--config", config_file.path)
112+
if len(ctx.attr.analyze) != 0:
113+
cmd_args.add("--analyze", "'" + " ".join(ctx.attr.analyze) + "'")
114+
cmd_args.add("--files", codechecker_files.path)
115+
cmd_args.add("--log", ctx.outputs.codechecker_log.path)
116+
cmd_args.add("--env", codechecker_env)
118117
ctx.actions.run(
119118
inputs = depset(
120119
[
@@ -130,8 +129,7 @@ def _codechecker_impl(ctx):
130129
],
131130
executable = codechecker_script,
132131
tools = [ctx.attr._codechecker_script[DefaultInfo].files_to_run],
133-
arguments = [],
134-
env = environment_variables,
132+
arguments = [cmd_args],
135133
mnemonic = "CodeChecker",
136134
progress_message = "CodeChecker %s" % str(ctx.label),
137135
# use_default_shell_env = True,
@@ -242,16 +240,32 @@ def _codechecker_test_impl(ctx):
242240
target_file = ctx.executable._codechecker_script,
243241
)
244242

243+
launcher = ctx.actions.declare_file(ctx.label.name + "_launcher.sh")
244+
ctx.actions.write(
245+
output = launcher,
246+
content = """#!/bin/bash
247+
exec {tool} --mode=Test --verbosity=INFO \
248+
--codechecker_path '{codechecker_path}' \
249+
--files '{codechecker_files}' --severities '{severities}'
250+
""".format(
251+
tool = ctx.outputs.codechecker_test_script.short_path,
252+
codechecker_path = CODECHECKER_BIN_PATH,
253+
codechecker_files = codechecker_files.short_path,
254+
severities = " ".join(ctx.attr.severities)
255+
),
256+
is_executable = True,
257+
)
258+
245259
# Return test script and all required files
246-
run_files = default_runfiles + [ctx.outputs.codechecker_test_script]
260+
run_files = default_runfiles + [ctx.outputs.codechecker_test_script, launcher]
247261
all_runfiles = ctx.runfiles(files = run_files)
248262
# Add runfiles from the py_binary target:
249263
all_runfiles = all_runfiles.merge(ctx.attr._codechecker_script[DefaultInfo].default_runfiles)
250264
return [
251265
DefaultInfo(
252266
files = depset(all_files),
253267
runfiles = all_runfiles,
254-
executable = ctx.outputs.codechecker_test_script,
268+
executable = launcher,
255269
),
256270
RunEnvironmentInfo(
257271
environment = environment_variables,

src/codechecker_script.py

Lines changed: 64 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -24,37 +24,39 @@
2424
import shlex
2525
import subprocess
2626
import sys
27+
import argparse
2728

29+
parser = argparse.ArgumentParser(description="CodeChecker Bazel Wrapper")
2830

29-
EXECUTION_MODE = os.environ.get("RULES_CODECHECKER_MODE", "{Mode}")
30-
VERBOSITY = os.environ.get("RULES_CODECHECKER_VERBOSITY", "{Verbosity}")
31-
CODECHECKER_PATH = os.environ.get(
32-
"RULES_CODECHECKER_CODECHECKER_BIN", "{codechecker_bin}"
31+
parser.add_argument("--mode", required=True, help="Execution mode")
32+
parser.add_argument("--verbosity", default="INFO", help="Log level")
33+
parser.add_argument(
34+
"--codechecker_path", required=True, help="CodeChecker path"
3335
)
34-
CODECHECKER_SKIPFILE = os.environ.get(
35-
"RULES_CODECHECKER_CODECHECKER_SKIPFILE", "{codechecker_skipfile}"
36-
)
37-
CODECHECKER_CONFIG = os.environ.get(
38-
"RULES_CODECHECKER_CODECHECKER_CONFIG", "{codechecker_config}"
39-
)
40-
CODECHECKER_ANALYZE = os.environ.get(
41-
"RULES_CODECHECKER_CODECHECKER_ANALYZE", "{codechecker_analyze}"
42-
)
43-
CODECHECKER_FILES = os.environ.get(
44-
"RULES_CODECHECKER_CODECHECKER_FILES", "{codechecker_files}"
45-
)
46-
CODECHECKER_LOG = os.environ.get(
47-
"RULES_CODECHECKER_CODECHECKER_LOG", "{codechecker_log}"
48-
)
49-
CODECHECKER_SEVERITIES = os.environ.get(
50-
"RULES_CODECHECKER_SEVERITIES", "{Severities}"
51-
)
52-
CODECHECKER_ENV = os.environ.get(
53-
"RULES_CODECHECKER_CODECHECKER_ENV", "{codechecker_env}"
54-
)
55-
COMPILE_COMMANDS = os.environ.get(
56-
"RULES_CODECHECKER_COMPILE_COMMANDS", "{compile_commands}"
36+
parser.add_argument("--commands", help="Compile commands json")
37+
parser.add_argument("--skip", help="Skipfile path")
38+
parser.add_argument("--config", help="Config file path")
39+
parser.add_argument("--analyze", default="", help="Analysis options")
40+
parser.add_argument(
41+
"--files", help="Folder where CodeChecker will store its results"
5742
)
43+
parser.add_argument("--log", help="Log file path")
44+
parser.add_argument("--env", help="Environment for CodeChecker")
45+
parser.add_argument("--severities", help="List of severities to fail on")
46+
47+
args = parser.parse_args()
48+
49+
EXECUTION_MODE = args.mode
50+
VERBOSITY = args.verbosity
51+
CODECHECKER_PATH = args.codechecker_path
52+
COMPILE_COMMANDS = args.commands
53+
CODECHECKER_SKIPFILE = args.skip
54+
CODECHECKER_CONFIG = args.config
55+
CODECHECKER_ANALYZE = args.analyze
56+
CODECHECKER_FILES = args.files
57+
CODECHECKER_LOG = args.log
58+
CODECHECKER_ENV = args.env
59+
CODECHECKER_SEVERITIES = args.severities
5860

5961
START_PATH = r"\/(?:(?!\.\s+)\S)+"
6062
BAZEL_PATHS = {
@@ -65,7 +67,7 @@
6567

6668

6769
def fail(message, exit_code=1):
68-
""" Print error message and return exit code """
70+
"""Print error message and return exit code"""
6971
logging.error(message)
7072
print()
7173
print("*" * 50)
@@ -86,27 +88,27 @@ def fail(message, exit_code=1):
8688

8789

8890
def read_file(filename):
89-
""" Read text file and return its contents """
91+
"""Read text file and return its contents"""
9092
if not os.path.isfile(filename):
9193
fail(f"File not found: {filename}")
9294
with open(filename, encoding="utf-8") as handle:
9395
return handle.read()
9496

9597

9698
def separator(method="info"):
97-
""" Print log separator line to logging.info() or other logging methods """
99+
"""Print log separator line to logging.info() or other logging methods"""
98100
getattr(logging, method)("#" * 23)
99101

100102

101103
def stage(title, method="info"):
102-
""" Print stage title into log """
104+
"""Print stage title into log"""
103105
separator(method)
104106
getattr(logging, method)("### " + title)
105107
separator(method)
106108

107109

108110
def valid_parameter(parameter):
109-
""" Check if external parameter is defined and valid """
111+
"""Check if external parameter is defined and valid"""
110112
if parameter is None:
111113
return False
112114
if parameter and parameter[0] == "{":
@@ -115,14 +117,14 @@ def valid_parameter(parameter):
115117

116118

117119
def log_file_name():
118-
""" Check and return log file name """
120+
"""Check and return log file name"""
119121
if valid_parameter(CODECHECKER_LOG):
120122
return CODECHECKER_LOG
121123
return None
122124

123125

124126
def setup():
125-
""" Setup logging parameters for execution session """
127+
"""Setup logging parameters for execution session"""
126128
if VERBOSITY == "INFO":
127129
log_level = logging.INFO
128130
elif VERBOSITY == "WARN":
@@ -140,7 +142,7 @@ def setup():
140142

141143

142144
def input_data():
143-
""" Print out input (external) parameters """
145+
"""Print out input (external) parameters"""
144146
stage("CodeChecker input data:", "debug")
145147
logging.debug("EXECUTION_MODE : %s", str(EXECUTION_MODE))
146148
logging.debug("VERBOSITY : %s", str(VERBOSITY))
@@ -156,7 +158,7 @@ def input_data():
156158

157159

158160
def execute(cmd, env=None, codes=None):
159-
""" Execute CodeChecker commands """
161+
"""Execute CodeChecker commands"""
160162
if codes is None:
161163
codes = [0]
162164
with subprocess.Popen(
@@ -178,20 +180,20 @@ def execute(cmd, env=None, codes=None):
178180

179181

180182
def create_folder(path):
181-
""" Create folder structure for CodeChecker data files and reports """
183+
"""Create folder structure for CodeChecker data files and reports"""
182184
if not os.path.exists(path):
183185
os.makedirs(path)
184186

185187

186188
def prepare():
187-
""" Prepare CodeChecker execution environment """
189+
"""Prepare CodeChecker execution environment"""
188190
stage("CodeChecker files:")
189191
logging.info("Creating folder: %s", CODECHECKER_FILES)
190192
create_folder(CODECHECKER_FILES)
191193

192194

193195
def analyze():
194-
""" Run CodeChecker analyze command """
196+
"""Run CodeChecker analyze command"""
195197
stage("CodeChecker analyze:")
196198

197199
env = os.environ
@@ -207,9 +209,11 @@ def analyze():
207209
output = execute(f"{CODECHECKER_PATH} analyzers --details", env=env)
208210
logging.debug("Analyzers:\n\n%s", output)
209211

210-
command = f"{CODECHECKER_PATH} analyze --skip={CODECHECKER_SKIPFILE} " \
211-
f"{COMPILE_COMMANDS} --output={CODECHECKER_FILES}/data " \
212-
f"--config {CODECHECKER_CONFIG} {CODECHECKER_ANALYZE}"
212+
command = (
213+
f"{CODECHECKER_PATH} analyze --skip={CODECHECKER_SKIPFILE} "
214+
f"{COMPILE_COMMANDS} --output={CODECHECKER_FILES}/data "
215+
f"--config {CODECHECKER_CONFIG} {CODECHECKER_ANALYZE}"
216+
)
213217
# FIXME: Workaround "CodeChecker simply remove compiler-rt include path".
214218
# This can be removed once codechecker 6.16.0 is used.
215219
# command += " --keep-gcc-intrin"
@@ -222,7 +226,7 @@ def analyze():
222226

223227

224228
def fix_bazel_paths():
225-
""" Remove Bazel leading paths in all files """
229+
"""Remove Bazel leading paths in all files"""
226230
stage("Fix CodeChecker output:")
227231
folder = CODECHECKER_FILES
228232
logging.info("Fixing Bazel paths in %s", folder)
@@ -241,7 +245,7 @@ def fix_bazel_paths():
241245

242246

243247
def realpath(filename):
244-
""" Return real full absolute path for given filename """
248+
"""Return real full absolute path for given filename"""
245249
if os.path.exists(filename):
246250
real_file_name = os.path.abspath(os.path.realpath(filename))
247251
logging.debug("Updating %s -> %s", filename, real_file_name)
@@ -250,7 +254,7 @@ def realpath(filename):
250254

251255

252256
def resolve_plist_symlinks(filepath):
253-
""" Resolve the symbolic links in plist files to real file paths """
257+
"""Resolve the symbolic links in plist files to real file paths"""
254258
# plistlib replaced readPlist/writePlist with load/dump in Python 3.9.
255259
# Since Pylint analyzes every line,
256260
# it flags the methods missing in the current environment.
@@ -274,7 +278,7 @@ def resolve_plist_symlinks(filepath):
274278

275279

276280
def resolve_yaml_symlinks(filepath):
277-
""" Resolve the symbolic links in YAML files to real file paths """
281+
"""Resolve the symbolic links in YAML files to real file paths"""
278282
logging.info("Processing YAML file: %s", filepath)
279283
fields = [
280284
r"MainSourceFile:\s*",
@@ -305,7 +309,7 @@ def resolve_yaml_symlinks(filepath):
305309

306310

307311
def resolve_symlinks():
308-
""" Change ".../execroot/apps" paths to absolute paths in data/* files """
312+
"""Change ".../execroot/apps" paths to absolute paths in data/* files"""
309313
stage("Resolve file paths in CodeChecker analyze output:")
310314
analyze_outdir = CODECHECKER_FILES + "/data"
311315
logging.info(
@@ -335,14 +339,18 @@ def update_file_paths():
335339

336340

337341
def parse():
338-
""" Run CodeChecker parse commands """
342+
"""Run CodeChecker parse commands"""
339343
stage("CodeChecker parse:")
340344
logging.info("CodeChecker parse -e json")
341-
codechecker_parse = f"{CODECHECKER_PATH} parse --config " \
342-
f"{CODECHECKER_CONFIG} {CODECHECKER_FILES}/data"
345+
codechecker_parse = (
346+
f"{CODECHECKER_PATH} parse --config "
347+
f"{CODECHECKER_CONFIG} {CODECHECKER_FILES}/data"
348+
)
343349
# Save results to JSON file
344-
command = f"{codechecker_parse} --export=json > " \
345-
f"{CODECHECKER_FILES}/result.json"
350+
command = (
351+
f"{codechecker_parse} --export=json > "
352+
f"{CODECHECKER_FILES}/result.json"
353+
)
346354
execute(command, codes=[0, 2])
347355
# logging.debug(
348356
# "JSON:\n\n%s\n", read_file(CODECHECKER_FILES + "/result.json")
@@ -366,15 +374,15 @@ def parse():
366374

367375

368376
def run():
369-
""" Perform all steps for "bazel build" phase """
377+
"""Perform all steps for "bazel build" phase"""
370378
prepare()
371379
analyze()
372380
parse()
373381
update_file_paths()
374382

375383

376384
def check_results():
377-
""" Check/verify CodeChecker results """
385+
"""Check/verify CodeChecker results"""
378386
stage("Checking result:")
379387
# Get results file and read it
380388
result_file = CODECHECKER_FILES + "/result.txt"
@@ -421,12 +429,12 @@ def check_results():
421429

422430

423431
def test():
424-
""" Perform all steps for "bazel test" phase """
432+
"""Perform all steps for "bazel test" phase"""
425433
check_results()
426434

427435

428436
def main():
429-
""" Main function """
437+
"""Main function"""
430438
setup()
431439
input_data()
432440
try:

0 commit comments

Comments
 (0)