You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
126 lines
4.0 KiB
126 lines
4.0 KiB
#!/usr/bin/env python3 |
|
# SPDX-License-Identifier: Apache-2.0 |
|
# Copyright (c) 2021 Intel Corporation |
|
|
|
import os |
|
import sh |
|
import argparse |
|
import re |
|
from unidiff import PatchSet |
|
|
|
if "ZEPHYR_BASE" not in os.environ: |
|
exit("$ZEPHYR_BASE environment variable undefined.") |
|
|
|
RESERVED_NAMES_SCRIPT = "/scripts/coccinelle/reserved_names.cocci" |
|
|
|
coccinelle_scripts = [RESERVED_NAMES_SCRIPT, |
|
"/scripts/coccinelle/same_identifier.cocci", |
|
#"/scripts/coccinelle/identifier_length.cocci", |
|
] |
|
|
|
coccinelle_reserved_names_exclude_regex = [ |
|
r"lib/libc/.*", |
|
r"lib/posix/.*", |
|
r"include/zephyr/posix/.*", |
|
] |
|
|
|
def parse_coccinelle(contents: str, violations: dict): |
|
reg = re.compile("([a-zA-Z0-9_/]*\\.[ch]:[0-9]*)(:[0-9\\-]*: )(.*)") |
|
for line in contents.split("\n"): |
|
r = reg.match(line) |
|
if r: |
|
f = r.group(1) |
|
if f in violations: |
|
violations[f].append(r.group(3)) |
|
else: |
|
violations[r.group(1)] = [r.group(3)] |
|
|
|
|
|
def parse_args(): |
|
parser = argparse.ArgumentParser( |
|
description="Check commits against Cocccinelle rules", allow_abbrev=False) |
|
parser.add_argument('-r', "--repository", required=False, |
|
help="Path to repository") |
|
parser.add_argument('-c', '--commits', default=None, |
|
help="Commit range in the form: a..b") |
|
parser.add_argument("-o", "--output", required=False, |
|
help="Print violation into a file") |
|
return parser.parse_args() |
|
|
|
|
|
def main(): |
|
args = parse_args() |
|
if not args.commits: |
|
exit("missing commit range") |
|
|
|
if args.repository is None: |
|
repository_path = os.environ['ZEPHYR_BASE'] |
|
else: |
|
repository_path = args.repository |
|
|
|
sh_special_args = { |
|
'_tty_out': False, |
|
'_cwd': repository_path |
|
} |
|
|
|
# pylint does not like the 'sh' library |
|
# pylint: disable=too-many-function-args,unexpected-keyword-arg |
|
commit = sh.git("diff", args.commits, **sh_special_args) |
|
patch_set = PatchSet(commit) |
|
zephyr_base = os.getenv("ZEPHYR_BASE") |
|
violations = {} |
|
numViolations = 0 |
|
|
|
for f in patch_set: |
|
if not f.path.endswith(".c") and not f.path.endswith(".h") or not os.path.exists(zephyr_base + "/" + f.path): |
|
continue |
|
|
|
for script in coccinelle_scripts: |
|
|
|
skip_reserved_names = False |
|
if script == RESERVED_NAMES_SCRIPT: |
|
for path in coccinelle_reserved_names_exclude_regex: |
|
if re.match(path, f.path): |
|
skip_reserved_names = True |
|
break |
|
|
|
if skip_reserved_names: |
|
continue |
|
|
|
script_path =zephyr_base + "/" + script |
|
print(f"Running {script} on {f.path}") |
|
try: |
|
cocci = sh.coccicheck( |
|
"--mode=report", |
|
"--cocci=" + |
|
script_path, |
|
f.path, |
|
_timeout=10, |
|
**sh_special_args) |
|
parse_coccinelle(cocci, violations) |
|
except sh.TimeoutException: |
|
print("we timed out waiting, skipping...") |
|
|
|
for hunk in f: |
|
for line in hunk: |
|
if line.is_added: |
|
violation = "{}:{}".format(f.path, line.target_line_no) |
|
if violation in violations: |
|
numViolations += 1 |
|
if args.output: |
|
with open(args.output, "a+") as fp: |
|
fp.write("{}:{}\n".format( |
|
violation, "\t\n".join( |
|
violations[violation]))) |
|
else: |
|
print( |
|
"{}:{}".format( |
|
violation, "\t\n".join( |
|
violations[violation]))) |
|
|
|
return numViolations |
|
|
|
|
|
if __name__ == "__main__": |
|
ret = main() |
|
exit(ret)
|
|
|