mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-09-29 08:00:26 +09:00
patman: Fix up checkpatch parsing to deal with 'CHECK' lines
checkpatch has a new type of warning, a 'CHECK'. At present patman fails with these, which makes it less than useful. Add support for checks, making it backwards compatible with the old checkpatch. At the same time, clean up formatting of the CheckPatches() output, fix erroneous "internal error" if multiple patches have warnings and be more robust to new types of problems. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Doug Anderson <dianders@chromium.org>
This commit is contained in:
parent
fe2f8d9e2f
commit
d29fe6e2d2
@ -19,6 +19,7 @@
|
|||||||
# MA 02111-1307 USA
|
# MA 02111-1307 USA
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import collections
|
||||||
import command
|
import command
|
||||||
import gitutil
|
import gitutil
|
||||||
import os
|
import os
|
||||||
@ -57,63 +58,86 @@ def CheckPatch(fname, verbose=False):
|
|||||||
"""Run checkpatch.pl on a file.
|
"""Run checkpatch.pl on a file.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
4-tuple containing:
|
namedtuple containing:
|
||||||
result: False=failure, True=ok
|
ok: False=failure, True=ok
|
||||||
problems: List of problems, each a dict:
|
problems: List of problems, each a dict:
|
||||||
'type'; error or warning
|
'type'; error or warning
|
||||||
'msg': text message
|
'msg': text message
|
||||||
'file' : filename
|
'file' : filename
|
||||||
'line': line number
|
'line': line number
|
||||||
|
errors: Number of errors
|
||||||
|
warnings: Number of warnings
|
||||||
|
checks: Number of checks
|
||||||
lines: Number of lines
|
lines: Number of lines
|
||||||
|
stdout: Full output of checkpatch
|
||||||
"""
|
"""
|
||||||
result = False
|
fields = ['ok', 'problems', 'errors', 'warnings', 'checks', 'lines',
|
||||||
error_count, warning_count, lines = 0, 0, 0
|
'stdout']
|
||||||
problems = []
|
result = collections.namedtuple('CheckPatchResult', fields)
|
||||||
|
result.ok = False
|
||||||
|
result.errors, result.warning, result.checks = 0, 0, 0
|
||||||
|
result.lines = 0
|
||||||
|
result.problems = []
|
||||||
chk = FindCheckPatch()
|
chk = FindCheckPatch()
|
||||||
item = {}
|
item = {}
|
||||||
stdout = command.Output(chk, '--no-tree', fname)
|
result.stdout = command.Output(chk, '--no-tree', fname)
|
||||||
#pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
#pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||||
#stdout, stderr = pipe.communicate()
|
#stdout, stderr = pipe.communicate()
|
||||||
|
|
||||||
# total: 0 errors, 0 warnings, 159 lines checked
|
# total: 0 errors, 0 warnings, 159 lines checked
|
||||||
|
# or:
|
||||||
|
# total: 0 errors, 2 warnings, 7 checks, 473 lines checked
|
||||||
re_stats = re.compile('total: (\\d+) errors, (\d+) warnings, (\d+)')
|
re_stats = re.compile('total: (\\d+) errors, (\d+) warnings, (\d+)')
|
||||||
|
re_stats_full = re.compile('total: (\\d+) errors, (\d+) warnings, (\d+)'
|
||||||
|
' checks, (\d+)')
|
||||||
re_ok = re.compile('.*has no obvious style problems')
|
re_ok = re.compile('.*has no obvious style problems')
|
||||||
re_bad = re.compile('.*has style problems, please review')
|
re_bad = re.compile('.*has style problems, please review')
|
||||||
re_error = re.compile('ERROR: (.*)')
|
re_error = re.compile('ERROR: (.*)')
|
||||||
re_warning = re.compile('WARNING: (.*)')
|
re_warning = re.compile('WARNING: (.*)')
|
||||||
|
re_check = re.compile('CHECK: (.*)')
|
||||||
re_file = re.compile('#\d+: FILE: ([^:]*):(\d+):')
|
re_file = re.compile('#\d+: FILE: ([^:]*):(\d+):')
|
||||||
|
|
||||||
for line in stdout.splitlines():
|
for line in result.stdout.splitlines():
|
||||||
if verbose:
|
if verbose:
|
||||||
print line
|
print line
|
||||||
|
|
||||||
# A blank line indicates the end of a message
|
# A blank line indicates the end of a message
|
||||||
if not line and item:
|
if not line and item:
|
||||||
problems.append(item)
|
result.problems.append(item)
|
||||||
item = {}
|
item = {}
|
||||||
|
match = re_stats_full.match(line)
|
||||||
|
if not match:
|
||||||
match = re_stats.match(line)
|
match = re_stats.match(line)
|
||||||
if match:
|
if match:
|
||||||
error_count = int(match.group(1))
|
result.errors = int(match.group(1))
|
||||||
warning_count = int(match.group(2))
|
result.warnings = int(match.group(2))
|
||||||
lines = int(match.group(3))
|
if len(match.groups()) == 4:
|
||||||
|
result.checks = int(match.group(3))
|
||||||
|
result.lines = int(match.group(4))
|
||||||
|
else:
|
||||||
|
result.lines = int(match.group(3))
|
||||||
elif re_ok.match(line):
|
elif re_ok.match(line):
|
||||||
result = True
|
result.ok = True
|
||||||
elif re_bad.match(line):
|
elif re_bad.match(line):
|
||||||
result = False
|
result.ok = False
|
||||||
match = re_error.match(line)
|
err_match = re_error.match(line)
|
||||||
if match:
|
warn_match = re_warning.match(line)
|
||||||
item['msg'] = match.group(1)
|
file_match = re_file.match(line)
|
||||||
|
check_match = re_check.match(line)
|
||||||
|
if err_match:
|
||||||
|
item['msg'] = err_match.group(1)
|
||||||
item['type'] = 'error'
|
item['type'] = 'error'
|
||||||
match = re_warning.match(line)
|
elif warn_match:
|
||||||
if match:
|
item['msg'] = warn_match.group(1)
|
||||||
item['msg'] = match.group(1)
|
|
||||||
item['type'] = 'warning'
|
item['type'] = 'warning'
|
||||||
match = re_file.match(line)
|
elif check_match:
|
||||||
if match:
|
item['msg'] = check_match.group(1)
|
||||||
item['file'] = match.group(1)
|
item['type'] = 'check'
|
||||||
item['line'] = int(match.group(2))
|
elif file_match:
|
||||||
|
item['file'] = file_match.group(1)
|
||||||
|
item['line'] = int(file_match.group(2))
|
||||||
|
|
||||||
return result, problems, error_count, warning_count, lines, stdout
|
return result
|
||||||
|
|
||||||
def GetWarningMsg(col, msg_type, fname, line, msg):
|
def GetWarningMsg(col, msg_type, fname, line, msg):
|
||||||
'''Create a message for a given file/line
|
'''Create a message for a given file/line
|
||||||
@ -128,37 +152,39 @@ def GetWarningMsg(col, msg_type, fname, line, msg):
|
|||||||
msg_type = col.Color(col.YELLOW, msg_type)
|
msg_type = col.Color(col.YELLOW, msg_type)
|
||||||
elif msg_type == 'error':
|
elif msg_type == 'error':
|
||||||
msg_type = col.Color(col.RED, msg_type)
|
msg_type = col.Color(col.RED, msg_type)
|
||||||
|
elif msg_type == 'check':
|
||||||
|
msg_type = col.Color(col.MAGENTA, msg_type)
|
||||||
return '%s: %s,%d: %s' % (msg_type, fname, line, msg)
|
return '%s: %s,%d: %s' % (msg_type, fname, line, msg)
|
||||||
|
|
||||||
def CheckPatches(verbose, args):
|
def CheckPatches(verbose, args):
|
||||||
'''Run the checkpatch.pl script on each patch'''
|
'''Run the checkpatch.pl script on each patch'''
|
||||||
error_count = 0
|
error_count, warning_count, check_count = 0, 0, 0
|
||||||
warning_count = 0
|
|
||||||
col = terminal.Color()
|
col = terminal.Color()
|
||||||
|
|
||||||
for fname in args:
|
for fname in args:
|
||||||
ok, problems, errors, warnings, lines, stdout = CheckPatch(fname,
|
result = CheckPatch(fname, verbose)
|
||||||
verbose)
|
if not result.ok:
|
||||||
if not ok:
|
error_count += result.errors
|
||||||
error_count += errors
|
warning_count += result.warnings
|
||||||
warning_count += warnings
|
check_count += result.checks
|
||||||
print '%d errors, %d warnings for %s:' % (errors,
|
print '%d errors, %d warnings, %d checks for %s:' % (result.errors,
|
||||||
warnings, fname)
|
result.warnings, result.checks, col.Color(col.BLUE, fname))
|
||||||
if len(problems) != error_count + warning_count:
|
if (len(result.problems) != result.errors + result.warnings +
|
||||||
|
result.checks):
|
||||||
print "Internal error: some problems lost"
|
print "Internal error: some problems lost"
|
||||||
for item in problems:
|
for item in result.problems:
|
||||||
print GetWarningMsg(col, item['type'],
|
print GetWarningMsg(col, item.get('type', '<unknown>'),
|
||||||
item.get('file', '<unknown>'),
|
item.get('file', '<unknown>'),
|
||||||
item.get('line', 0), item['msg'])
|
item.get('line', 0), item.get('msg', 'message'))
|
||||||
|
print
|
||||||
#print stdout
|
#print stdout
|
||||||
if error_count != 0 or warning_count != 0:
|
if error_count or warning_count or check_count:
|
||||||
str = 'checkpatch.pl found %d error(s), %d warning(s)' % (
|
str = 'checkpatch.pl found %d error(s), %d warning(s), %d checks(s)'
|
||||||
error_count, warning_count)
|
|
||||||
color = col.GREEN
|
color = col.GREEN
|
||||||
if warning_count:
|
if warning_count:
|
||||||
color = col.YELLOW
|
color = col.YELLOW
|
||||||
if error_count:
|
if error_count:
|
||||||
color = col.RED
|
color = col.RED
|
||||||
print col.Color(color, str)
|
print col.Color(color, str % (error_count, warning_count, check_count))
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
@ -190,6 +190,11 @@ index 0000000..2234c87
|
|||||||
+ rec->time_us = (uint32_t)timer_get_us();
|
+ rec->time_us = (uint32_t)timer_get_us();
|
||||||
+ rec->name = name;
|
+ rec->name = name;
|
||||||
+ }
|
+ }
|
||||||
|
+ if (!rec->name &&
|
||||||
|
+ %ssomething_else) {
|
||||||
|
+ rec->time_us = (uint32_t)timer_get_us();
|
||||||
|
+ rec->name = name;
|
||||||
|
+ }
|
||||||
+%sreturn rec->time_us;
|
+%sreturn rec->time_us;
|
||||||
+}
|
+}
|
||||||
--
|
--
|
||||||
@ -197,15 +202,18 @@ index 0000000..2234c87
|
|||||||
'''
|
'''
|
||||||
signoff = 'Signed-off-by: Simon Glass <sjg@chromium.org>\n'
|
signoff = 'Signed-off-by: Simon Glass <sjg@chromium.org>\n'
|
||||||
tab = ' '
|
tab = ' '
|
||||||
|
indent = ' '
|
||||||
if data_type == 'good':
|
if data_type == 'good':
|
||||||
pass
|
pass
|
||||||
elif data_type == 'no-signoff':
|
elif data_type == 'no-signoff':
|
||||||
signoff = ''
|
signoff = ''
|
||||||
elif data_type == 'spaces':
|
elif data_type == 'spaces':
|
||||||
tab = ' '
|
tab = ' '
|
||||||
|
elif data_type == 'indent':
|
||||||
|
indent = tab
|
||||||
else:
|
else:
|
||||||
print 'not implemented'
|
print 'not implemented'
|
||||||
return data % (signoff, tab, tab)
|
return data % (signoff, tab, indent, tab)
|
||||||
|
|
||||||
def SetupData(self, data_type):
|
def SetupData(self, data_type):
|
||||||
inhandle, inname = tempfile.mkstemp()
|
inhandle, inname = tempfile.mkstemp()
|
||||||
@ -215,33 +223,49 @@ index 0000000..2234c87
|
|||||||
infd.close()
|
infd.close()
|
||||||
return inname
|
return inname
|
||||||
|
|
||||||
def testCheckpatch(self):
|
def testGood(self):
|
||||||
"""Test checkpatch operation"""
|
"""Test checkpatch operation"""
|
||||||
inf = self.SetupData('good')
|
inf = self.SetupData('good')
|
||||||
result, problems, err, warn, lines, stdout = checkpatch.CheckPatch(inf)
|
result = checkpatch.CheckPatch(inf)
|
||||||
self.assertEqual(result, True)
|
self.assertEqual(result.ok, True)
|
||||||
self.assertEqual(problems, [])
|
self.assertEqual(result.problems, [])
|
||||||
self.assertEqual(err, 0)
|
self.assertEqual(result.errors, 0)
|
||||||
self.assertEqual(warn, 0)
|
self.assertEqual(result.warnings, 0)
|
||||||
self.assertEqual(lines, 67)
|
self.assertEqual(result.checks, 0)
|
||||||
|
self.assertEqual(result.lines, 67)
|
||||||
os.remove(inf)
|
os.remove(inf)
|
||||||
|
|
||||||
|
def testNoSignoff(self):
|
||||||
inf = self.SetupData('no-signoff')
|
inf = self.SetupData('no-signoff')
|
||||||
result, problems, err, warn, lines, stdout = checkpatch.CheckPatch(inf)
|
result = checkpatch.CheckPatch(inf)
|
||||||
self.assertEqual(result, False)
|
self.assertEqual(result.ok, False)
|
||||||
self.assertEqual(len(problems), 1)
|
self.assertEqual(len(result.problems), 1)
|
||||||
self.assertEqual(err, 1)
|
self.assertEqual(result.errors, 1)
|
||||||
self.assertEqual(warn, 0)
|
self.assertEqual(result.warnings, 0)
|
||||||
self.assertEqual(lines, 67)
|
self.assertEqual(result.checks, 0)
|
||||||
|
self.assertEqual(result.lines, 67)
|
||||||
os.remove(inf)
|
os.remove(inf)
|
||||||
|
|
||||||
|
def testSpaces(self):
|
||||||
inf = self.SetupData('spaces')
|
inf = self.SetupData('spaces')
|
||||||
result, problems, err, warn, lines, stdout = checkpatch.CheckPatch(inf)
|
result = checkpatch.CheckPatch(inf)
|
||||||
self.assertEqual(result, False)
|
self.assertEqual(result.ok, False)
|
||||||
self.assertEqual(len(problems), 2)
|
self.assertEqual(len(result.problems), 1)
|
||||||
self.assertEqual(err, 0)
|
self.assertEqual(result.errors, 0)
|
||||||
self.assertEqual(warn, 2)
|
self.assertEqual(result.warnings, 1)
|
||||||
self.assertEqual(lines, 67)
|
self.assertEqual(result.checks, 0)
|
||||||
|
self.assertEqual(result.lines, 67)
|
||||||
|
os.remove(inf)
|
||||||
|
|
||||||
|
def testIndent(self):
|
||||||
|
inf = self.SetupData('indent')
|
||||||
|
result = checkpatch.CheckPatch(inf)
|
||||||
|
self.assertEqual(result.ok, False)
|
||||||
|
self.assertEqual(len(result.problems), 1)
|
||||||
|
self.assertEqual(result.errors, 0)
|
||||||
|
self.assertEqual(result.warnings, 0)
|
||||||
|
self.assertEqual(result.checks, 1)
|
||||||
|
self.assertEqual(result.lines, 67)
|
||||||
os.remove(inf)
|
os.remove(inf)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user