blob: 85b1bc076a44963ff011704caeb31bae0cffa468 [file] [log] [blame]
Flavio Ceolin85525422021-03-23 15:06:01 -07001#!/usr/bin/env python3
2# SPDX-License-Identifier: Apache-2.0
3# Copyright (c) 2021 Intel Corporation
4
5import os
6import sh
7import argparse
8import re
9from unidiff import PatchSet
10
11if "ZEPHYR_BASE" not in os.environ:
12 exit("$ZEPHYR_BASE environment variable undefined.")
13
14repository_path = os.environ['ZEPHYR_BASE']
15
16sh_special_args = {
17 '_tty_out': False,
18 '_cwd': repository_path
19}
20
21coccinelle_scripts = ["/scripts/coccinelle/reserved_names.cocci",
22 "/scripts/coccinelle/same_identifier.cocci",
Anas Nashif01c1bcf2021-05-06 14:17:29 -040023 #"/scripts/coccinelle/identifier_length.cocci",
Flavio Ceolin85525422021-03-23 15:06:01 -070024 ]
25
26
27def parse_coccinelle(contents: str, violations: dict):
Anas Nashifb669f0c2021-04-30 23:01:03 -040028 reg = re.compile("([a-zA-Z0-9_/]*\\.[ch]:[0-9]*)(:[0-9\\-]*: )(.*)")
Flavio Ceolin85525422021-03-23 15:06:01 -070029 for line in contents.split("\n"):
30 r = reg.match(line)
31 if r:
32 f = r.group(1)
33 if f in violations:
34 violations[f].append(r.group(3))
35 else:
36 violations[r.group(1)] = [r.group(3)]
37
38
39def parse_args():
40 parser = argparse.ArgumentParser(
41 description="Check if change requires full twister")
42 parser.add_argument('-c', '--commits', default=None,
43 help="Commit range in the form: a..b")
Flavio Ceolin58fdc012021-03-24 15:54:16 -070044 parser.add_argument("-o", "--output", required=False,
45 help="Print violation into a file")
Flavio Ceolin85525422021-03-23 15:06:01 -070046 return parser.parse_args()
47
48
49def main():
50 args = parse_args()
51 if not args.commits:
52 exit("missing commit range")
53
Flavio Ceolin0bbe5e42021-03-24 16:18:43 -070054 # pylint does not like the 'sh' library
55 # pylint: disable=too-many-function-args,unexpected-keyword-arg
Flavio Ceolin85525422021-03-23 15:06:01 -070056 commit = sh.git("diff", args.commits, **sh_special_args)
57 patch_set = PatchSet(commit)
58 zephyr_base = os.getenv("ZEPHYR_BASE")
59 violations = {}
60 numViolations = 0
61
62 for f in patch_set:
63 if not f.path.endswith(".c") and not f.path.endswith(".h") or not os.path.exists(zephyr_base + "/" + f.path):
64 continue
65
66 for script in coccinelle_scripts:
67 script_path = os.getenv("ZEPHYR_BASE") + "/" + script
Anas Nashif8ebc67e2021-05-03 10:40:42 -040068 print(f"Running {script} on {f.path}")
69 try:
70 cocci = sh.coccicheck(
71 "--mode=report",
72 "--cocci=" +
73 script_path,
74 f.path,
75 _timeout=10,
76 **sh_special_args)
77 parse_coccinelle(cocci, violations)
78 except sh.TimeoutException:
79 print("we timed out waiting, skipping...")
Flavio Ceolin85525422021-03-23 15:06:01 -070080
81 for hunk in f:
82 for line in hunk:
83 if line.is_added:
84 violation = "{}:{}".format(f.path, line.target_line_no)
85 if violation in violations:
86 numViolations += 1
Flavio Ceolin58fdc012021-03-24 15:54:16 -070087 if args.output:
88 with open(args.output, "a+") as fp:
89 fp.write("{}:{}\n".format(
90 violation, "\t\n".join(
91 violations[violation])))
92 else:
93 print(
94 "{}:{}".format(
95 violation, "\t\n".join(
96 violations[violation])))
Flavio Ceolin85525422021-03-23 15:06:01 -070097
98 return numViolations
99
100
101if __name__ == "__main__":
102 ret = main()
103 exit(ret)