xref: /rk3399_rockchip-uboot/tools/patman/checkpatch.py (revision 21342d4aed6c77a4aa7a5b2579b3c23e21aea31a)
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
3731e2141dSMasahiro 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 = {}
66785f1548SSimon Glass    result.stdout = command.Output(chk, '--no-tree', fname,
67785f1548SSimon Glass                                   raise_on_error=False)
680d24de9dSSimon Glass    #pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE)
690d24de9dSSimon Glass    #stdout, stderr = pipe.communicate()
700d24de9dSSimon Glass
710d24de9dSSimon Glass    # total: 0 errors, 0 warnings, 159 lines checked
72d29fe6e2SSimon Glass    # or:
73d29fe6e2SSimon Glass    # total: 0 errors, 2 warnings, 7 checks, 473 lines checked
740d24de9dSSimon Glass    re_stats = re.compile('total: (\\d+) errors, (\d+) warnings, (\d+)')
75d29fe6e2SSimon Glass    re_stats_full = re.compile('total: (\\d+) errors, (\d+) warnings, (\d+)'
76d29fe6e2SSimon Glass                               ' checks, (\d+)')
770d24de9dSSimon Glass    re_ok = re.compile('.*has no obvious style problems')
780d24de9dSSimon Glass    re_bad = re.compile('.*has style problems, please review')
790d24de9dSSimon Glass    re_error = re.compile('ERROR: (.*)')
800d24de9dSSimon Glass    re_warning = re.compile('WARNING: (.*)')
81d29fe6e2SSimon Glass    re_check = re.compile('CHECK: (.*)')
820d24de9dSSimon Glass    re_file = re.compile('#\d+: FILE: ([^:]*):(\d+):')
830d24de9dSSimon Glass
84d29fe6e2SSimon Glass    for line in result.stdout.splitlines():
850d24de9dSSimon Glass        if verbose:
86a920a17bSPaul Burton            print(line)
870d24de9dSSimon Glass
880d24de9dSSimon Glass        # A blank line indicates the end of a message
890d24de9dSSimon Glass        if not line and item:
90d29fe6e2SSimon Glass            result.problems.append(item)
910d24de9dSSimon Glass            item = {}
92d29fe6e2SSimon Glass        match = re_stats_full.match(line)
93d29fe6e2SSimon Glass        if not match:
940d24de9dSSimon Glass            match = re_stats.match(line)
950d24de9dSSimon Glass        if match:
96d29fe6e2SSimon Glass            result.errors = int(match.group(1))
97d29fe6e2SSimon Glass            result.warnings = int(match.group(2))
98d29fe6e2SSimon Glass            if len(match.groups()) == 4:
99d29fe6e2SSimon Glass                result.checks = int(match.group(3))
100d29fe6e2SSimon Glass                result.lines = int(match.group(4))
101d29fe6e2SSimon Glass            else:
102d29fe6e2SSimon Glass                result.lines = int(match.group(3))
1030d24de9dSSimon Glass        elif re_ok.match(line):
104d29fe6e2SSimon Glass            result.ok = True
1050d24de9dSSimon Glass        elif re_bad.match(line):
106d29fe6e2SSimon Glass            result.ok = False
107d29fe6e2SSimon Glass        err_match = re_error.match(line)
108d29fe6e2SSimon Glass        warn_match = re_warning.match(line)
109d29fe6e2SSimon Glass        file_match = re_file.match(line)
110d29fe6e2SSimon Glass        check_match = re_check.match(line)
111d29fe6e2SSimon Glass        if err_match:
112d29fe6e2SSimon Glass            item['msg'] = err_match.group(1)
1130d24de9dSSimon Glass            item['type'] = 'error'
114d29fe6e2SSimon Glass        elif warn_match:
115d29fe6e2SSimon Glass            item['msg'] = warn_match.group(1)
1160d24de9dSSimon Glass            item['type'] = 'warning'
117d29fe6e2SSimon Glass        elif check_match:
118d29fe6e2SSimon Glass            item['msg'] = check_match.group(1)
119d29fe6e2SSimon Glass            item['type'] = 'check'
120d29fe6e2SSimon Glass        elif file_match:
121d29fe6e2SSimon Glass            item['file'] = file_match.group(1)
122d29fe6e2SSimon Glass            item['line'] = int(file_match.group(2))
1230d24de9dSSimon Glass
124d29fe6e2SSimon Glass    return result
1250d24de9dSSimon Glass
1260d24de9dSSimon Glassdef GetWarningMsg(col, msg_type, fname, line, msg):
1270d24de9dSSimon Glass    '''Create a message for a given file/line
1280d24de9dSSimon Glass
1290d24de9dSSimon Glass    Args:
1300d24de9dSSimon Glass        msg_type: Message type ('error' or 'warning')
1310d24de9dSSimon Glass        fname: Filename which reports the problem
1320d24de9dSSimon Glass        line: Line number where it was noticed
1330d24de9dSSimon Glass        msg: Message to report
1340d24de9dSSimon Glass    '''
1350d24de9dSSimon Glass    if msg_type == 'warning':
1360d24de9dSSimon Glass        msg_type = col.Color(col.YELLOW, msg_type)
1370d24de9dSSimon Glass    elif msg_type == 'error':
1380d24de9dSSimon Glass        msg_type = col.Color(col.RED, msg_type)
139d29fe6e2SSimon Glass    elif msg_type == 'check':
140d29fe6e2SSimon Glass        msg_type = col.Color(col.MAGENTA, msg_type)
141*8aa41363SSimon Glass    return '%s:%d: %s: %s\n' % (fname, line, msg_type, msg)
1420d24de9dSSimon Glass
1430d24de9dSSimon Glassdef CheckPatches(verbose, args):
1440d24de9dSSimon Glass    '''Run the checkpatch.pl script on each patch'''
145d29fe6e2SSimon Glass    error_count, warning_count, check_count = 0, 0, 0
1460d24de9dSSimon Glass    col = terminal.Color()
1470d24de9dSSimon Glass
1480d24de9dSSimon Glass    for fname in args:
149d29fe6e2SSimon Glass        result = CheckPatch(fname, verbose)
150d29fe6e2SSimon Glass        if not result.ok:
151d29fe6e2SSimon Glass            error_count += result.errors
152d29fe6e2SSimon Glass            warning_count += result.warnings
153d29fe6e2SSimon Glass            check_count += result.checks
154a920a17bSPaul Burton            print('%d errors, %d warnings, %d checks for %s:' % (result.errors,
155a920a17bSPaul Burton                    result.warnings, result.checks, col.Color(col.BLUE, fname)))
156d29fe6e2SSimon Glass            if (len(result.problems) != result.errors + result.warnings +
157d29fe6e2SSimon Glass                    result.checks):
158a920a17bSPaul Burton                print("Internal error: some problems lost")
159d29fe6e2SSimon Glass            for item in result.problems:
160*8aa41363SSimon Glass                sys.stderr.write(
161*8aa41363SSimon Glass                    GetWarningMsg(col, item.get('type', '<unknown>'),
162afb9bf55SSimon Glass                        item.get('file', '<unknown>'),
163a920a17bSPaul Burton                        item.get('line', 0), item.get('msg', 'message')))
164d29fe6e2SSimon Glass            print
165a920a17bSPaul Burton            #print(stdout)
166d29fe6e2SSimon Glass    if error_count or warning_count or check_count:
167d29fe6e2SSimon Glass        str = 'checkpatch.pl found %d error(s), %d warning(s), %d checks(s)'
1680d24de9dSSimon Glass        color = col.GREEN
1690d24de9dSSimon Glass        if warning_count:
1700d24de9dSSimon Glass            color = col.YELLOW
1710d24de9dSSimon Glass        if error_count:
1720d24de9dSSimon Glass            color = col.RED
173a920a17bSPaul Burton        print(col.Color(color, str % (error_count, warning_count, check_count)))
1740d24de9dSSimon Glass        return False
1750d24de9dSSimon Glass    return True
176