xref: /rk3399_rockchip-uboot/tools/patman/checkpatch.py (revision d29fe6e2d2cbcbfd1bfaaf886818d84edde0fc0d)
10d24de9dSSimon Glass# Copyright (c) 2011 The Chromium OS Authors.
20d24de9dSSimon Glass#
30d24de9dSSimon Glass# See file CREDITS for list of people who contributed to this
40d24de9dSSimon Glass# project.
50d24de9dSSimon Glass#
60d24de9dSSimon Glass# This program is free software; you can redistribute it and/or
70d24de9dSSimon Glass# modify it under the terms of the GNU General Public License as
80d24de9dSSimon Glass# published by the Free Software Foundation; either version 2 of
90d24de9dSSimon Glass# the License, or (at your option) any later version.
100d24de9dSSimon Glass#
110d24de9dSSimon Glass# This program is distributed in the hope that it will be useful,
120d24de9dSSimon Glass# but WITHOUT ANY WARRANTY; without even the implied warranty of
130d24de9dSSimon Glass# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
140d24de9dSSimon Glass# GNU General Public License for more details.
150d24de9dSSimon Glass#
160d24de9dSSimon Glass# You should have received a copy of the GNU General Public License
170d24de9dSSimon Glass# along with this program; if not, write to the Free Software
180d24de9dSSimon Glass# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
190d24de9dSSimon Glass# MA 02111-1307 USA
200d24de9dSSimon Glass#
210d24de9dSSimon Glass
22*d29fe6e2SSimon Glassimport collections
230d24de9dSSimon Glassimport command
240d24de9dSSimon Glassimport gitutil
250d24de9dSSimon Glassimport os
260d24de9dSSimon Glassimport re
2799adf6edSVadim Bendeburyimport sys
280d24de9dSSimon Glassimport terminal
290d24de9dSSimon Glass
300d24de9dSSimon Glassdef FindCheckPatch():
31d96ef37dSDoug Anderson    top_level = gitutil.GetTopLevel()
320d24de9dSSimon Glass    try_list = [
330d24de9dSSimon Glass        os.getcwd(),
340d24de9dSSimon Glass        os.path.join(os.getcwd(), '..', '..'),
35d96ef37dSDoug Anderson        os.path.join(top_level, 'tools'),
36d96ef37dSDoug Anderson        os.path.join(top_level, 'scripts'),
370d24de9dSSimon Glass        '%s/bin' % os.getenv('HOME'),
380d24de9dSSimon Glass        ]
390d24de9dSSimon Glass    # Look in current dir
400d24de9dSSimon Glass    for path in try_list:
410d24de9dSSimon Glass        fname = os.path.join(path, 'checkpatch.pl')
420d24de9dSSimon Glass        if os.path.isfile(fname):
430d24de9dSSimon Glass            return fname
440d24de9dSSimon Glass
450d24de9dSSimon Glass    # Look upwwards for a Chrome OS tree
460d24de9dSSimon Glass    while not os.path.ismount(path):
470d24de9dSSimon Glass        fname = os.path.join(path, 'src', 'third_party', 'kernel', 'files',
480d24de9dSSimon Glass                'scripts', 'checkpatch.pl')
490d24de9dSSimon Glass        if os.path.isfile(fname):
500d24de9dSSimon Glass            return fname
510d24de9dSSimon Glass        path = os.path.dirname(path)
5299adf6edSVadim Bendebury
5399adf6edSVadim Bendebury    print >> sys.stderr, ('Cannot find checkpatch.pl - please put it in your ' +
5499adf6edSVadim Bendebury                '~/bin directory or use --no-check')
5599adf6edSVadim Bendebury    sys.exit(1)
560d24de9dSSimon Glass
570d24de9dSSimon Glassdef CheckPatch(fname, verbose=False):
580d24de9dSSimon Glass    """Run checkpatch.pl on a file.
590d24de9dSSimon Glass
600d24de9dSSimon Glass    Returns:
61*d29fe6e2SSimon Glass        namedtuple containing:
62*d29fe6e2SSimon Glass            ok: False=failure, True=ok
630d24de9dSSimon Glass            problems: List of problems, each a dict:
640d24de9dSSimon Glass                'type'; error or warning
650d24de9dSSimon Glass                'msg': text message
660d24de9dSSimon Glass                'file' : filename
670d24de9dSSimon Glass                'line': line number
68*d29fe6e2SSimon Glass            errors: Number of errors
69*d29fe6e2SSimon Glass            warnings: Number of warnings
70*d29fe6e2SSimon Glass            checks: Number of checks
710d24de9dSSimon Glass            lines: Number of lines
72*d29fe6e2SSimon Glass            stdout: Full output of checkpatch
730d24de9dSSimon Glass    """
74*d29fe6e2SSimon Glass    fields = ['ok', 'problems', 'errors', 'warnings', 'checks', 'lines',
75*d29fe6e2SSimon Glass              'stdout']
76*d29fe6e2SSimon Glass    result = collections.namedtuple('CheckPatchResult', fields)
77*d29fe6e2SSimon Glass    result.ok = False
78*d29fe6e2SSimon Glass    result.errors, result.warning, result.checks = 0, 0, 0
79*d29fe6e2SSimon Glass    result.lines = 0
80*d29fe6e2SSimon Glass    result.problems = []
810d24de9dSSimon Glass    chk = FindCheckPatch()
820d24de9dSSimon Glass    item = {}
83*d29fe6e2SSimon Glass    result.stdout = command.Output(chk, '--no-tree', fname)
840d24de9dSSimon Glass    #pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE)
850d24de9dSSimon Glass    #stdout, stderr = pipe.communicate()
860d24de9dSSimon Glass
870d24de9dSSimon Glass    # total: 0 errors, 0 warnings, 159 lines checked
88*d29fe6e2SSimon Glass    # or:
89*d29fe6e2SSimon Glass    # total: 0 errors, 2 warnings, 7 checks, 473 lines checked
900d24de9dSSimon Glass    re_stats = re.compile('total: (\\d+) errors, (\d+) warnings, (\d+)')
91*d29fe6e2SSimon Glass    re_stats_full = re.compile('total: (\\d+) errors, (\d+) warnings, (\d+)'
92*d29fe6e2SSimon Glass                               ' checks, (\d+)')
930d24de9dSSimon Glass    re_ok = re.compile('.*has no obvious style problems')
940d24de9dSSimon Glass    re_bad = re.compile('.*has style problems, please review')
950d24de9dSSimon Glass    re_error = re.compile('ERROR: (.*)')
960d24de9dSSimon Glass    re_warning = re.compile('WARNING: (.*)')
97*d29fe6e2SSimon Glass    re_check = re.compile('CHECK: (.*)')
980d24de9dSSimon Glass    re_file = re.compile('#\d+: FILE: ([^:]*):(\d+):')
990d24de9dSSimon Glass
100*d29fe6e2SSimon Glass    for line in result.stdout.splitlines():
1010d24de9dSSimon Glass        if verbose:
1020d24de9dSSimon Glass            print line
1030d24de9dSSimon Glass
1040d24de9dSSimon Glass        # A blank line indicates the end of a message
1050d24de9dSSimon Glass        if not line and item:
106*d29fe6e2SSimon Glass            result.problems.append(item)
1070d24de9dSSimon Glass            item = {}
108*d29fe6e2SSimon Glass        match = re_stats_full.match(line)
109*d29fe6e2SSimon Glass        if not match:
1100d24de9dSSimon Glass            match = re_stats.match(line)
1110d24de9dSSimon Glass        if match:
112*d29fe6e2SSimon Glass            result.errors = int(match.group(1))
113*d29fe6e2SSimon Glass            result.warnings = int(match.group(2))
114*d29fe6e2SSimon Glass            if len(match.groups()) == 4:
115*d29fe6e2SSimon Glass                result.checks = int(match.group(3))
116*d29fe6e2SSimon Glass                result.lines = int(match.group(4))
117*d29fe6e2SSimon Glass            else:
118*d29fe6e2SSimon Glass                result.lines = int(match.group(3))
1190d24de9dSSimon Glass        elif re_ok.match(line):
120*d29fe6e2SSimon Glass            result.ok = True
1210d24de9dSSimon Glass        elif re_bad.match(line):
122*d29fe6e2SSimon Glass            result.ok = False
123*d29fe6e2SSimon Glass        err_match = re_error.match(line)
124*d29fe6e2SSimon Glass        warn_match = re_warning.match(line)
125*d29fe6e2SSimon Glass        file_match = re_file.match(line)
126*d29fe6e2SSimon Glass        check_match = re_check.match(line)
127*d29fe6e2SSimon Glass        if err_match:
128*d29fe6e2SSimon Glass            item['msg'] = err_match.group(1)
1290d24de9dSSimon Glass            item['type'] = 'error'
130*d29fe6e2SSimon Glass        elif warn_match:
131*d29fe6e2SSimon Glass            item['msg'] = warn_match.group(1)
1320d24de9dSSimon Glass            item['type'] = 'warning'
133*d29fe6e2SSimon Glass        elif check_match:
134*d29fe6e2SSimon Glass            item['msg'] = check_match.group(1)
135*d29fe6e2SSimon Glass            item['type'] = 'check'
136*d29fe6e2SSimon Glass        elif file_match:
137*d29fe6e2SSimon Glass            item['file'] = file_match.group(1)
138*d29fe6e2SSimon Glass            item['line'] = int(file_match.group(2))
1390d24de9dSSimon Glass
140*d29fe6e2SSimon Glass    return result
1410d24de9dSSimon Glass
1420d24de9dSSimon Glassdef GetWarningMsg(col, msg_type, fname, line, msg):
1430d24de9dSSimon Glass    '''Create a message for a given file/line
1440d24de9dSSimon Glass
1450d24de9dSSimon Glass    Args:
1460d24de9dSSimon Glass        msg_type: Message type ('error' or 'warning')
1470d24de9dSSimon Glass        fname: Filename which reports the problem
1480d24de9dSSimon Glass        line: Line number where it was noticed
1490d24de9dSSimon Glass        msg: Message to report
1500d24de9dSSimon Glass    '''
1510d24de9dSSimon Glass    if msg_type == 'warning':
1520d24de9dSSimon Glass        msg_type = col.Color(col.YELLOW, msg_type)
1530d24de9dSSimon Glass    elif msg_type == 'error':
1540d24de9dSSimon Glass        msg_type = col.Color(col.RED, msg_type)
155*d29fe6e2SSimon Glass    elif msg_type == 'check':
156*d29fe6e2SSimon Glass        msg_type = col.Color(col.MAGENTA, msg_type)
1570d24de9dSSimon Glass    return '%s: %s,%d: %s' % (msg_type, fname, line, msg)
1580d24de9dSSimon Glass
1590d24de9dSSimon Glassdef CheckPatches(verbose, args):
1600d24de9dSSimon Glass    '''Run the checkpatch.pl script on each patch'''
161*d29fe6e2SSimon Glass    error_count, warning_count, check_count = 0, 0, 0
1620d24de9dSSimon Glass    col = terminal.Color()
1630d24de9dSSimon Glass
1640d24de9dSSimon Glass    for fname in args:
165*d29fe6e2SSimon Glass        result = CheckPatch(fname, verbose)
166*d29fe6e2SSimon Glass        if not result.ok:
167*d29fe6e2SSimon Glass            error_count += result.errors
168*d29fe6e2SSimon Glass            warning_count += result.warnings
169*d29fe6e2SSimon Glass            check_count += result.checks
170*d29fe6e2SSimon Glass            print '%d errors, %d warnings, %d checks for %s:' % (result.errors,
171*d29fe6e2SSimon Glass                    result.warnings, result.checks, col.Color(col.BLUE, fname))
172*d29fe6e2SSimon Glass            if (len(result.problems) != result.errors + result.warnings +
173*d29fe6e2SSimon Glass                    result.checks):
1740d24de9dSSimon Glass                print "Internal error: some problems lost"
175*d29fe6e2SSimon Glass            for item in result.problems:
176*d29fe6e2SSimon Glass                print GetWarningMsg(col, item.get('type', '<unknown>'),
177afb9bf55SSimon Glass                        item.get('file', '<unknown>'),
178*d29fe6e2SSimon Glass                        item.get('line', 0), item.get('msg', 'message'))
179*d29fe6e2SSimon Glass            print
1800d24de9dSSimon Glass            #print stdout
181*d29fe6e2SSimon Glass    if error_count or warning_count or check_count:
182*d29fe6e2SSimon Glass        str = 'checkpatch.pl found %d error(s), %d warning(s), %d checks(s)'
1830d24de9dSSimon Glass        color = col.GREEN
1840d24de9dSSimon Glass        if warning_count:
1850d24de9dSSimon Glass            color = col.YELLOW
1860d24de9dSSimon Glass        if error_count:
1870d24de9dSSimon Glass            color = col.RED
188*d29fe6e2SSimon Glass        print col.Color(color, str % (error_count, warning_count, check_count))
1890d24de9dSSimon Glass        return False
1900d24de9dSSimon Glass    return True
191