]> rtime.felk.cvut.cz Git - coffee/buildroot.git/blob - utils/check-package
libkcapi: depends on BR2_TOOLCHAIN_HAS_SYNC_4
[coffee/buildroot.git] / utils / check-package
1 #!/usr/bin/env python
2 # See utils/checkpackagelib/readme.txt before editing this file.
3
4 from __future__ import print_function
5 import argparse
6 import inspect
7 import os
8 import re
9 import sys
10
11 import checkpackagelib.lib_config
12 import checkpackagelib.lib_hash
13 import checkpackagelib.lib_mk
14 import checkpackagelib.lib_patch
15
16 VERBOSE_LEVEL_TO_SHOW_IGNORED_FILES = 3
17 flags = None  # Command line arguments.
18
19
20 def parse_args():
21     parser = argparse.ArgumentParser()
22
23     # Do not use argparse.FileType("r") here because only files with known
24     # format will be open based on the filename.
25     parser.add_argument("files", metavar="F", type=str, nargs="*",
26                         help="list of files")
27
28     parser.add_argument("--br2-external", "-b", dest='intree_only', action="store_false",
29                         help="do not apply the pathname filters used for intree files")
30
31     parser.add_argument("--manual-url", action="store",
32                         default="http://nightly.buildroot.org/",
33                         help="default: %(default)s")
34     parser.add_argument("--verbose", "-v", action="count", default=0)
35
36     # Now the debug options in the order they are processed.
37     parser.add_argument("--include-only", dest="include_list", action="append",
38                         help="run only the specified functions (debug)")
39     parser.add_argument("--exclude", dest="exclude_list", action="append",
40                         help="do not run the specified functions (debug)")
41     parser.add_argument("--dry-run", action="store_true", help="print the "
42                         "functions that would be called for each file (debug)")
43
44     return parser.parse_args()
45
46
47 CONFIG_IN_FILENAME = re.compile("Config\.\S*$")
48 DO_CHECK_INTREE = re.compile("|".join([
49     "Config.in",
50     "arch/",
51     "boot/",
52     "fs/",
53     "linux/",
54     "package/",
55     "system/",
56     "toolchain/",
57     ]))
58 DO_NOT_CHECK_INTREE = re.compile("|".join([
59     "boot/barebox/barebox\.mk$",
60     "fs/common\.mk$",
61     "package/doc-asciidoc\.mk$",
62     "package/pkg-\S*\.mk$",
63     "toolchain/helpers\.mk$",
64     "toolchain/toolchain-external/pkg-toolchain-external\.mk$",
65     ]))
66
67
68 def get_lib_from_filename(fname):
69     if flags.intree_only:
70         if DO_CHECK_INTREE.match(fname) is None:
71             return None
72         if DO_NOT_CHECK_INTREE.match(fname):
73             return None
74     if CONFIG_IN_FILENAME.search(fname):
75         return checkpackagelib.lib_config
76     if fname.endswith(".hash"):
77         return checkpackagelib.lib_hash
78     if fname.endswith(".mk"):
79         return checkpackagelib.lib_mk
80     if fname.endswith(".patch"):
81         return checkpackagelib.lib_patch
82     return None
83
84
85 def is_a_check_function(m):
86     if not inspect.isclass(m):
87         return False
88     # do not call the base class
89     if m.__name__.startswith("_"):
90         return False
91     if flags.include_list and m.__name__ not in flags.include_list:
92         return False
93     if flags.exclude_list and m.__name__ in flags.exclude_list:
94         return False
95     return True
96
97
98 def print_warnings(warnings):
99     # Avoid the need to use 'return []' at the end of every check function.
100     if warnings is None:
101         return 0  # No warning generated.
102
103     for level, message in enumerate(warnings):
104         if flags.verbose >= level:
105             print(message.replace("\t", "< tab  >").rstrip())
106     return 1  # One more warning to count.
107
108
109 def check_file_using_lib(fname):
110     # Count number of warnings generated and lines processed.
111     nwarnings = 0
112     nlines = 0
113
114     lib = get_lib_from_filename(fname)
115     if not lib:
116         if flags.verbose >= VERBOSE_LEVEL_TO_SHOW_IGNORED_FILES:
117             print("{}: ignored".format(fname))
118         return nwarnings, nlines
119     classes = inspect.getmembers(lib, is_a_check_function)
120
121     if flags.dry_run:
122         functions_to_run = [c[0] for c in classes]
123         print("{}: would run: {}".format(fname, functions_to_run))
124         return nwarnings, nlines
125
126     objects = [c[1](fname, flags.manual_url) for c in classes]
127
128     for cf in objects:
129         nwarnings += print_warnings(cf.before())
130     for lineno, text in enumerate(open(fname, "r").readlines()):
131         nlines += 1
132         for cf in objects:
133             nwarnings += print_warnings(cf.check_line(lineno + 1, text))
134     for cf in objects:
135         nwarnings += print_warnings(cf.after())
136
137     return nwarnings, nlines
138
139
140 def __main__():
141     global flags
142     flags = parse_args()
143
144     if flags.intree_only:
145         # change all paths received to be relative to the base dir
146         base_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
147         files_to_check = [os.path.relpath(os.path.abspath(f), base_dir) for f in flags.files]
148         # move current dir so the script find the files
149         os.chdir(base_dir)
150     else:
151         files_to_check = flags.files
152
153     if len(files_to_check) == 0:
154         print("No files to check style")
155         sys.exit(1)
156
157     # Accumulate number of warnings generated and lines processed.
158     total_warnings = 0
159     total_lines = 0
160
161     for fname in files_to_check:
162         nwarnings, nlines = check_file_using_lib(fname)
163         total_warnings += nwarnings
164         total_lines += nlines
165
166     # The warning messages are printed to stdout and can be post-processed
167     # (e.g. counted by 'wc'), so for stats use stderr. Wait all warnings are
168     # printed, for the case there are many of them, before printing stats.
169     sys.stdout.flush()
170     print("{} lines processed".format(total_lines), file=sys.stderr)
171     print("{} warnings generated".format(total_warnings), file=sys.stderr)
172
173     if total_warnings > 0:
174         sys.exit(1)
175
176
177 __main__()