xref: /rk3399_rockchip-uboot/tools/patman/checkpatch.py (revision 31e2141d5ad76b55e4e34ee7241adc1c3d9ef099)
10d24de9dSSimon Glass# Copyright (c) 2011 The Chromium OS Authors.
20d24de9dSSimon Glass#
31a459660SWolfgang Denk# SPDX-License-Identifier:	GPL-2.0+
40d24de9dSSimon Glass#
50d24de9dSSimon Glass
6d29fe6e2SSimon Glassimport collections
70d24de9dSSimon Glassimport command
80d24de9dSSimon Glassimport gitutil
90d24de9dSSimon Glassimport os
100d24de9dSSimon Glassimport re
1199adf6edSVadim Bendeburyimport sys
120d24de9dSSimon Glassimport terminal
130d24de9dSSimon Glass
140d24de9dSSimon Glassdef FindCheckPatch():
15d96ef37dSDoug Anderson    top_level = gitutil.GetTopLevel()
160d24de9dSSimon Glass    try_list = [
170d24de9dSSimon Glass        os.getcwd(),
180d24de9dSSimon Glass        os.path.join(os.getcwd(), '..', '..'),
19d96ef37dSDoug Anderson        os.path.join(top_level, 'tools'),
20d96ef37dSDoug Anderson        os.path.join(top_level, 'scripts'),
210d24de9dSSimon Glass        '%s/bin' % os.getenv('HOME'),
220d24de9dSSimon Glass        ]
230d24de9dSSimon Glass    # Look in current dir
240d24de9dSSimon Glass    for path in try_list:
250d24de9dSSimon Glass        fname = os.path.join(path, 'checkpatch.pl')
260d24de9dSSimon Glass        if os.path.isfile(fname):
270d24de9dSSimon Glass            return fname
280d24de9dSSimon Glass
290d24de9dSSimon Glass    # Look upwwards for a Chrome OS tree
300d24de9dSSimon Glass    while not os.path.ismount(path):
310d24de9dSSimon Glass        fname = os.path.join(path, 'src', 'third_party', 'kernel', 'files',
320d24de9dSSimon Glass                'scripts', 'checkpatch.pl')
330d24de9dSSimon Glass        if os.path.isfile(fname):
340d24de9dSSimon Glass            return fname
350d24de9dSSimon Glass        path = os.path.dirname(path)
3699adf6edSVadim Bendebury
37*31e2141dSMasahiro Yamada    sys.exit('Cannot find checkpatch.pl - please put it in your ' +
3899adf6edSVadim Bendebury             '~/bin directory or use --no-check')
390d24de9dSSimon Glass
400d24de9dSSimon Glassdef CheckPatch(fname, verbose=False):
410d24de9dSSimon Glass    """Run checkpatch.pl on a file.
420d24de9dSSimon Glass
430d24de9dSSimon Glass    Returns:
44d29fe6e2SSimon Glass        namedtuple containing:
45d29fe6e2SSimon Glass            ok: False=failure, True=ok
460d24de9dSSimon Glass            problems: List of problems, each a dict:
470d24de9dSSimon Glass                'type'; error or warning
480d24de9dSSimon Glass                'msg': text message
490d24de9dSSimon Glass                'file' : filename
500d24de9dSSimon Glass                'line': line number
51d29fe6e2SSimon Glass            errors: Number of errors
52d29fe6e2SSimon Glass            warnings: Number of warnings
53d29fe6e2SSimon Glass            checks: Number of checks
540d24de9dSSimon Glass            lines: Number of lines
55d29fe6e2SSimon Glass            stdout: Full output of checkpatch
560d24de9dSSimon Glass    """
57d29fe6e2SSimon Glass    fields = ['ok', 'problems', 'errors', 'warnings', 'checks', 'lines',
58d29fe6e2SSimon Glass              'stdout']
59d29fe6e2SSimon Glass    result = collections.namedtuple('CheckPatchResult', fields)
60d29fe6e2SSimon Glass    result.ok = False
61d29fe6e2SSimon Glass    result.errors, result.warning, result.checks = 0, 0, 0
62d29fe6e2SSimon Glass    result.lines = 0
63d29fe6e2SSimon Glass    result.problems = []
640d24de9dSSimon Glass    chk = FindCheckPatch()
650d24de9dSSimon Glass    item = {}
66d29fe6e2SSimon Glass    result.stdout = command.Output(chk, '--no-tree', fname)
670d24de9dSSimon Glass    #pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE)
680d24de9dSSimon Glass    #stdout, stderr = pipe.communicate()
690d24de9dSSimon Glass
700d24de9dSSimon Glass    # total: 0 errors, 0 warnings, 159 lines checked
71d29fe6e2SSimon Glass    # or:
72d29fe6e2SSimon Glass    # total: 0 errors, 2 warnings, 7 checks, 473 lines checked
730d24de9dSSimon Glass    re_stats = re.compile('total: (\\d+) errors, (\d+) warnings, (\d+)')
74d29fe6e2SSimon Glass    re_stats_full = re.compile('total: (\\d+) errors, (\d+) warnings, (\d+)'
75d29fe6e2SSimon Glass                               ' checks, (\d+)')
760d24de9dSSimon Glass    re_ok = re.compile('.*has no obvious style problems')
770d24de9dSSimon Glass    re_bad = re.compile('.*has style problems, please review')
780d24de9dSSimon Glass    re_error = re.compile('ERROR: (.*)')
790d24de9dSSimon Glass    re_warning = re.compile('WARNING: (.*)')
80d29fe6e2SSimon Glass    re_check = re.compile('CHECK: (.*)')
810d24de9dSSimon Glass    re_file = re.compile('#\d+: FILE: ([^:]*):(\d+):')
820d24de9dSSimon Glass
83d29fe6e2SSimon Glass    for line in result.stdout.splitlines():
840d24de9dSSimon Glass        if verbose:
850d24de9dSSimon Glass            print line
860d24de9dSSimon Glass
870d24de9dSSimon Glass        # A blank line indicates the end of a message
880d24de9dSSimon Glass        if not line and item:
89d29fe6e2SSimon Glass            result.problems.append(item)
900d24de9dSSimon Glass            item = {}
91d29fe6e2SSimon Glass        match = re_stats_full.match(line)
92d29fe6e2SSimon Glass        if not match:
930d24de9dSSimon Glass            match = re_stats.match(line)
940d24de9dSSimon Glass        if match:
95d29fe6e2SSimon Glass            result.errors = int(match.group(1))
96d29fe6e2SSimon Glass            result.warnings = int(match.group(2))
97d29fe6e2SSimon Glass            if len(match.groups()) == 4:
98d29fe6e2SSimon Glass                result.checks = int(match.group(3))
99d29fe6e2SSimon Glass                result.lines = int(match.group(4))
100d29fe6e2SSimon Glass            else:
101d29fe6e2SSimon Glass                result.lines = int(match.group(3))
1020d24de9dSSimon Glass        elif re_ok.match(line):
103d29fe6e2SSimon Glass            result.ok = True
1040d24de9dSSimon Glass        elif re_bad.match(line):
105d29fe6e2SSimon Glass            result.ok = False
106d29fe6e2SSimon Glass        err_match = re_error.match(line)
107d29fe6e2SSimon Glass        warn_match = re_warning.match(line)
108d29fe6e2SSimon Glass        file_match = re_file.match(line)
109d29fe6e2SSimon Glass        check_match = re_check.match(line)
110d29fe6e2SSimon Glass        if err_match:
111d29fe6e2SSimon Glass            item['msg'] = err_match.group(1)
1120d24de9dSSimon Glass            item['type'] = 'error'
113d29fe6e2SSimon Glass        elif warn_match:
114d29fe6e2SSimon Glass            item['msg'] = warn_match.group(1)
1150d24de9dSSimon Glass            item['type'] = 'warning'
116d29fe6e2SSimon Glass        elif check_match:
117d29fe6e2SSimon Glass            item['msg'] = check_match.group(1)
118d29fe6e2SSimon Glass            item['type'] = 'check'
119d29fe6e2SSimon Glass        elif file_match:
120d29fe6e2SSimon Glass            item['file'] = file_match.group(1)
121d29fe6e2SSimon Glass            item['line'] = int(file_match.group(2))
1220d24de9dSSimon Glass
123d29fe6e2SSimon Glass    return result
1240d24de9dSSimon Glass
1250d24de9dSSimon Glassdef GetWarningMsg(col, msg_type, fname, line, msg):
1260d24de9dSSimon Glass    '''Create a message for a given file/line
1270d24de9dSSimon Glass
1280d24de9dSSimon Glass    Args:
1290d24de9dSSimon Glass        msg_type: Message type ('error' or 'warning')
1300d24de9dSSimon Glass        fname: Filename which reports the problem
1310d24de9dSSimon Glass        line: Line number where it was noticed
1320d24de9dSSimon Glass        msg: Message to report
1330d24de9dSSimon Glass    '''
1340d24de9dSSimon Glass    if msg_type == 'warning':
1350d24de9dSSimon Glass        msg_type = col.Color(col.YELLOW, msg_type)
1360d24de9dSSimon Glass    elif msg_type == 'error':
1370d24de9dSSimon Glass        msg_type = col.Color(col.RED, msg_type)
138d29fe6e2SSimon Glass    elif msg_type == 'check':
139d29fe6e2SSimon Glass        msg_type = col.Color(col.MAGENTA, msg_type)
1400d24de9dSSimon Glass    return '%s: %s,%d: %s' % (msg_type, fname, line, msg)
1410d24de9dSSimon Glass
1420d24de9dSSimon Glassdef CheckPatches(verbose, args):
1430d24de9dSSimon Glass    '''Run the checkpatch.pl script on each patch'''
144d29fe6e2SSimon Glass    error_count, warning_count, check_count = 0, 0, 0
1450d24de9dSSimon Glass    col = terminal.Color()
1460d24de9dSSimon Glass
1470d24de9dSSimon Glass    for fname in args:
148d29fe6e2SSimon Glass        result = CheckPatch(fname, verbose)
149d29fe6e2SSimon Glass        if not result.ok:
150d29fe6e2SSimon Glass            error_count += result.errors
151d29fe6e2SSimon Glass            warning_count += result.warnings
152d29fe6e2SSimon Glass            check_count += result.checks
153d29fe6e2SSimon Glass            print '%d errors, %d warnings, %d checks for %s:' % (result.errors,
154d29fe6e2SSimon Glass                    result.warnings, result.checks, col.Color(col.BLUE, fname))
155d29fe6e2SSimon Glass            if (len(result.problems) != result.errors + result.warnings +
156d29fe6e2SSimon Glass                    result.checks):
1570d24de9dSSimon Glass                print "Internal error: some problems lost"
158d29fe6e2SSimon Glass            for item in result.problems:
159d29fe6e2SSimon Glass                print GetWarningMsg(col, item.get('type', '<unknown>'),
160afb9bf55SSimon Glass                        item.get('file', '<unknown>'),
161d29fe6e2SSimon Glass                        item.get('line', 0), item.get('msg', 'message'))
162d29fe6e2SSimon Glass            print
1630d24de9dSSimon Glass            #print stdout
164d29fe6e2SSimon Glass    if error_count or warning_count or check_count:
165d29fe6e2SSimon Glass        str = 'checkpatch.pl found %d error(s), %d warning(s), %d checks(s)'
1660d24de9dSSimon Glass        color = col.GREEN
1670d24de9dSSimon Glass        if warning_count:
1680d24de9dSSimon Glass            color = col.YELLOW
1690d24de9dSSimon Glass        if error_count:
1700d24de9dSSimon Glass            color = col.RED
171d29fe6e2SSimon Glass        print col.Color(color, str % (error_count, warning_count, check_count))
1720d24de9dSSimon Glass        return False
1730d24de9dSSimon Glass    return True
174