xref: /rk3399_rockchip-uboot/tools/patman/checkpatch.py (revision 0d24de9d558209fa525f350d1320c343f241c3f5)
1*0d24de9dSSimon Glass# Copyright (c) 2011 The Chromium OS Authors.
2*0d24de9dSSimon Glass#
3*0d24de9dSSimon Glass# See file CREDITS for list of people who contributed to this
4*0d24de9dSSimon Glass# project.
5*0d24de9dSSimon Glass#
6*0d24de9dSSimon Glass# This program is free software; you can redistribute it and/or
7*0d24de9dSSimon Glass# modify it under the terms of the GNU General Public License as
8*0d24de9dSSimon Glass# published by the Free Software Foundation; either version 2 of
9*0d24de9dSSimon Glass# the License, or (at your option) any later version.
10*0d24de9dSSimon Glass#
11*0d24de9dSSimon Glass# This program is distributed in the hope that it will be useful,
12*0d24de9dSSimon Glass# but WITHOUT ANY WARRANTY; without even the implied warranty of
13*0d24de9dSSimon Glass# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*0d24de9dSSimon Glass# GNU General Public License for more details.
15*0d24de9dSSimon Glass#
16*0d24de9dSSimon Glass# You should have received a copy of the GNU General Public License
17*0d24de9dSSimon Glass# along with this program; if not, write to the Free Software
18*0d24de9dSSimon Glass# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19*0d24de9dSSimon Glass# MA 02111-1307 USA
20*0d24de9dSSimon Glass#
21*0d24de9dSSimon Glass
22*0d24de9dSSimon Glassimport command
23*0d24de9dSSimon Glassimport gitutil
24*0d24de9dSSimon Glassimport os
25*0d24de9dSSimon Glassimport re
26*0d24de9dSSimon Glassimport terminal
27*0d24de9dSSimon Glass
28*0d24de9dSSimon Glassdef FindCheckPatch():
29*0d24de9dSSimon Glass    try_list = [
30*0d24de9dSSimon Glass        os.getcwd(),
31*0d24de9dSSimon Glass        os.path.join(os.getcwd(), '..', '..'),
32*0d24de9dSSimon Glass        os.path.join(gitutil.GetTopLevel(), 'tools'),
33*0d24de9dSSimon Glass        '%s/bin' % os.getenv('HOME'),
34*0d24de9dSSimon Glass        ]
35*0d24de9dSSimon Glass    # Look in current dir
36*0d24de9dSSimon Glass    for path in try_list:
37*0d24de9dSSimon Glass        fname = os.path.join(path, 'checkpatch.pl')
38*0d24de9dSSimon Glass        if os.path.isfile(fname):
39*0d24de9dSSimon Glass            return fname
40*0d24de9dSSimon Glass
41*0d24de9dSSimon Glass    # Look upwwards for a Chrome OS tree
42*0d24de9dSSimon Glass    while not os.path.ismount(path):
43*0d24de9dSSimon Glass        fname = os.path.join(path, 'src', 'third_party', 'kernel', 'files',
44*0d24de9dSSimon Glass                'scripts', 'checkpatch.pl')
45*0d24de9dSSimon Glass        if os.path.isfile(fname):
46*0d24de9dSSimon Glass            return fname
47*0d24de9dSSimon Glass        path = os.path.dirname(path)
48*0d24de9dSSimon Glass    print 'Could not find checkpatch.pl'
49*0d24de9dSSimon Glass    return None
50*0d24de9dSSimon Glass
51*0d24de9dSSimon Glassdef CheckPatch(fname, verbose=False):
52*0d24de9dSSimon Glass    """Run checkpatch.pl on a file.
53*0d24de9dSSimon Glass
54*0d24de9dSSimon Glass    Returns:
55*0d24de9dSSimon Glass        4-tuple containing:
56*0d24de9dSSimon Glass            result: False=failure, True=ok
57*0d24de9dSSimon Glass            problems: List of problems, each a dict:
58*0d24de9dSSimon Glass                'type'; error or warning
59*0d24de9dSSimon Glass                'msg': text message
60*0d24de9dSSimon Glass                'file' : filename
61*0d24de9dSSimon Glass                'line': line number
62*0d24de9dSSimon Glass            lines: Number of lines
63*0d24de9dSSimon Glass    """
64*0d24de9dSSimon Glass    result = False
65*0d24de9dSSimon Glass    error_count, warning_count, lines = 0, 0, 0
66*0d24de9dSSimon Glass    problems = []
67*0d24de9dSSimon Glass    chk = FindCheckPatch()
68*0d24de9dSSimon Glass    if not chk:
69*0d24de9dSSimon Glass        raise OSError, ('Cannot find checkpatch.pl - please put it in your ' +
70*0d24de9dSSimon Glass                '~/bin directory')
71*0d24de9dSSimon Glass    item = {}
72*0d24de9dSSimon Glass    stdout = command.Output(chk, '--no-tree', fname)
73*0d24de9dSSimon Glass    #pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE)
74*0d24de9dSSimon Glass    #stdout, stderr = pipe.communicate()
75*0d24de9dSSimon Glass
76*0d24de9dSSimon Glass    # total: 0 errors, 0 warnings, 159 lines checked
77*0d24de9dSSimon Glass    re_stats = re.compile('total: (\\d+) errors, (\d+) warnings, (\d+)')
78*0d24de9dSSimon Glass    re_ok = re.compile('.*has no obvious style problems')
79*0d24de9dSSimon Glass    re_bad = re.compile('.*has style problems, please review')
80*0d24de9dSSimon Glass    re_error = re.compile('ERROR: (.*)')
81*0d24de9dSSimon Glass    re_warning = re.compile('WARNING: (.*)')
82*0d24de9dSSimon Glass    re_file = re.compile('#\d+: FILE: ([^:]*):(\d+):')
83*0d24de9dSSimon Glass
84*0d24de9dSSimon Glass    for line in stdout.splitlines():
85*0d24de9dSSimon Glass        if verbose:
86*0d24de9dSSimon Glass            print line
87*0d24de9dSSimon Glass
88*0d24de9dSSimon Glass        # A blank line indicates the end of a message
89*0d24de9dSSimon Glass        if not line and item:
90*0d24de9dSSimon Glass            problems.append(item)
91*0d24de9dSSimon Glass            item = {}
92*0d24de9dSSimon Glass        match = re_stats.match(line)
93*0d24de9dSSimon Glass        if match:
94*0d24de9dSSimon Glass            error_count = int(match.group(1))
95*0d24de9dSSimon Glass            warning_count = int(match.group(2))
96*0d24de9dSSimon Glass            lines = int(match.group(3))
97*0d24de9dSSimon Glass        elif re_ok.match(line):
98*0d24de9dSSimon Glass            result = True
99*0d24de9dSSimon Glass        elif re_bad.match(line):
100*0d24de9dSSimon Glass            result = False
101*0d24de9dSSimon Glass        match = re_error.match(line)
102*0d24de9dSSimon Glass        if match:
103*0d24de9dSSimon Glass            item['msg'] = match.group(1)
104*0d24de9dSSimon Glass            item['type'] = 'error'
105*0d24de9dSSimon Glass        match = re_warning.match(line)
106*0d24de9dSSimon Glass        if match:
107*0d24de9dSSimon Glass            item['msg'] = match.group(1)
108*0d24de9dSSimon Glass            item['type'] = 'warning'
109*0d24de9dSSimon Glass        match = re_file.match(line)
110*0d24de9dSSimon Glass        if match:
111*0d24de9dSSimon Glass            item['file'] = match.group(1)
112*0d24de9dSSimon Glass            item['line'] = int(match.group(2))
113*0d24de9dSSimon Glass
114*0d24de9dSSimon Glass    return result, problems, error_count, warning_count, lines, stdout
115*0d24de9dSSimon Glass
116*0d24de9dSSimon Glassdef GetWarningMsg(col, msg_type, fname, line, msg):
117*0d24de9dSSimon Glass    '''Create a message for a given file/line
118*0d24de9dSSimon Glass
119*0d24de9dSSimon Glass    Args:
120*0d24de9dSSimon Glass        msg_type: Message type ('error' or 'warning')
121*0d24de9dSSimon Glass        fname: Filename which reports the problem
122*0d24de9dSSimon Glass        line: Line number where it was noticed
123*0d24de9dSSimon Glass        msg: Message to report
124*0d24de9dSSimon Glass    '''
125*0d24de9dSSimon Glass    if msg_type == 'warning':
126*0d24de9dSSimon Glass        msg_type = col.Color(col.YELLOW, msg_type)
127*0d24de9dSSimon Glass    elif msg_type == 'error':
128*0d24de9dSSimon Glass        msg_type = col.Color(col.RED, msg_type)
129*0d24de9dSSimon Glass    return '%s: %s,%d: %s' % (msg_type, fname, line, msg)
130*0d24de9dSSimon Glass
131*0d24de9dSSimon Glassdef CheckPatches(verbose, args):
132*0d24de9dSSimon Glass    '''Run the checkpatch.pl script on each patch'''
133*0d24de9dSSimon Glass    error_count = 0
134*0d24de9dSSimon Glass    warning_count = 0
135*0d24de9dSSimon Glass    col = terminal.Color()
136*0d24de9dSSimon Glass
137*0d24de9dSSimon Glass    for fname in args:
138*0d24de9dSSimon Glass        ok, problems, errors, warnings, lines, stdout = CheckPatch(fname,
139*0d24de9dSSimon Glass                verbose)
140*0d24de9dSSimon Glass        if not ok:
141*0d24de9dSSimon Glass            error_count += errors
142*0d24de9dSSimon Glass            warning_count += warnings
143*0d24de9dSSimon Glass            print '%d errors, %d warnings for %s:' % (errors,
144*0d24de9dSSimon Glass                    warnings, fname)
145*0d24de9dSSimon Glass            if len(problems) != error_count + warning_count:
146*0d24de9dSSimon Glass                print "Internal error: some problems lost"
147*0d24de9dSSimon Glass            for item in problems:
148*0d24de9dSSimon Glass                print GetWarningMsg(col, item['type'], item['file'],
149*0d24de9dSSimon Glass                        item['line'], item['msg'])
150*0d24de9dSSimon Glass            #print stdout
151*0d24de9dSSimon Glass    if error_count != 0 or warning_count != 0:
152*0d24de9dSSimon Glass        str = 'checkpatch.pl found %d error(s), %d warning(s)' % (
153*0d24de9dSSimon Glass            error_count, warning_count)
154*0d24de9dSSimon Glass        color = col.GREEN
155*0d24de9dSSimon Glass        if warning_count:
156*0d24de9dSSimon Glass            color = col.YELLOW
157*0d24de9dSSimon Glass        if error_count:
158*0d24de9dSSimon Glass            color = col.RED
159*0d24de9dSSimon Glass        print col.Color(color, str)
160*0d24de9dSSimon Glass        return False
161*0d24de9dSSimon Glass    return True
162