2 # See utils/checkpackagelib/readme.txt before editing this file.
4 from __future__ import print_function
11 import checkpackagelib.lib_config
12 import checkpackagelib.lib_hash
13 import checkpackagelib.lib_mk
14 import checkpackagelib.lib_patch
16 VERBOSE_LEVEL_TO_SHOW_IGNORED_FILES = 3
17 flags = None # Command line arguments.
21 parser = argparse.ArgumentParser()
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="*",
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")
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)
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)")
44 return parser.parse_args()
47 CONFIG_IN_FILENAME = re.compile("Config\.\S*$")
48 DO_CHECK_INTREE = re.compile("|".join([
58 DO_NOT_CHECK_INTREE = re.compile("|".join([
59 "boot/barebox/barebox\.mk$",
61 "package/doc-asciidoc\.mk$",
62 "package/pkg-\S*\.mk$",
63 "toolchain/helpers\.mk$",
64 "toolchain/toolchain-external/pkg-toolchain-external\.mk$",
68 def get_lib_from_filename(fname):
70 if DO_CHECK_INTREE.match(fname) is None:
72 if DO_NOT_CHECK_INTREE.match(fname):
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
85 def is_a_check_function(m):
86 if not inspect.isclass(m):
88 # do not call the base class
89 if m.__name__.startswith("_"):
91 if flags.include_list and m.__name__ not in flags.include_list:
93 if flags.exclude_list and m.__name__ in flags.exclude_list:
98 def print_warnings(warnings):
99 # Avoid the need to use 'return []' at the end of every check function.
101 return 0 # No warning generated.
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.
109 def check_file_using_lib(fname):
110 # Count number of warnings generated and lines processed.
114 lib = get_lib_from_filename(fname)
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)
122 functions_to_run = [c[0] for c in classes]
123 print("{}: would run: {}".format(fname, functions_to_run))
124 return nwarnings, nlines
126 objects = [c[1](fname, flags.manual_url) for c in classes]
129 nwarnings += print_warnings(cf.before())
130 for lineno, text in enumerate(open(fname, "r").readlines()):
133 nwarnings += print_warnings(cf.check_line(lineno + 1, text))
135 nwarnings += print_warnings(cf.after())
137 return nwarnings, nlines
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
151 files_to_check = flags.files
153 if len(files_to_check) == 0:
154 print("No files to check style")
157 # Accumulate number of warnings generated and lines processed.
161 for fname in files_to_check:
162 nwarnings, nlines = check_file_using_lib(fname)
163 total_warnings += nwarnings
164 total_lines += nlines
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.
170 print("{} lines processed".format(total_lines), file=sys.stderr)
171 print("{} warnings generated".format(total_warnings), file=sys.stderr)
173 if total_warnings > 0: