2 # Copyright (c) 2016 Red Hat, Inc.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 from __future__ import print_function
26 def print_error(message, lineno=None):
28 if lineno is not None:
29 print("E(%d): %s" % (lineno, message))
31 print("E: %s" % (message))
33 __errors = __errors + 1
36 def print_warning(message, lineno=None):
39 print("W(%d): %s" % (lineno, message))
41 print("W: %s" % (message))
43 __warnings = __warnings + 1
46 __regex_added_line = re.compile(r'^\+{1,2}[^\+][\w\W]*')
47 __regex_leading_with_whitespace_at_all = re.compile(r'^\s+')
48 __regex_leading_with_spaces = re.compile(r'^ +[\S]+')
49 __regex_trailing_whitespace = re.compile(r'[^\S]+$')
50 __regex_for_if_missing_whitespace = re.compile(r'(if|for|while)[\(]')
51 __regex_for_if_too_much_whitespace = re.compile(r'(if|for|while) +[\(]')
52 __regex_for_if_parens_whitespace = re.compile(r'(if|for|while) \( +[\s\S]+\)')
54 skip_leading_whitespace_check = False
55 skip_trailing_whitespace_check = False
56 skip_block_whitespace_check = False
57 skip_signoff_check = False
59 # Don't enforce character limit on files that include these characters in their
60 # name, as they may have legitimate reasons to have longer lines.
62 # Python isn't checked as flake8 performs these checks during build.
63 line_length_blacklist = ['.am', '.at', 'etc', '.in', '.m4', '.mk', '.patch',
67 def is_added_line(line):
68 """Returns TRUE if the line in question is an added line.
70 return __regex_added_line.search(line) is not None
73 def leading_whitespace_is_spaces(line):
74 """Returns TRUE if the leading whitespace in added lines is spaces
76 if skip_leading_whitespace_check:
78 if __regex_leading_with_whitespace_at_all.search(line) is not None:
79 return __regex_leading_with_spaces.search(line) is not None
83 def trailing_whitespace_or_crlf(line):
84 """Returns TRUE if the trailing characters is whitespace
86 if skip_trailing_whitespace_check:
88 return __regex_trailing_whitespace.search(line) is not None
91 def if_and_for_whitespace_checks(line):
92 """Return TRUE if there is appropriate whitespace after if, for, while
94 if skip_block_whitespace_check:
96 if (__regex_for_if_missing_whitespace.search(line) is not None or
97 __regex_for_if_too_much_whitespace.search(line) is not None or
98 __regex_for_if_parens_whitespace.search(line)):
103 def ovs_checkpatch_parse(text):
110 scissors = re.compile(r'^[\w]*---[\w]*')
111 hunks = re.compile('^(---|\+\+\+) (\S+)')
112 is_signature = re.compile(r'((\s*Signed-off-by: )(.*))$',
114 is_co_author = re.compile(r'(\s*(Co-authored-by: )(.*))$',
116 skip_line_length_check = False
118 for line in text.split('\n'):
119 if current_file != previous_file:
120 previous_file = current_file
121 if any([fmt in current_file for fmt in line_length_blacklist]):
122 skip_line_length_check = True
124 skip_line_length_check = False
131 match = hunks.match(line)
134 current_file = match.group(2)
137 if scissors.match(line):
139 if not skip_signoff_check:
140 if len(signatures) == 0:
141 print_error("No signatures found.")
142 if len(signatures) != 1 + len(co_authors):
143 print_error("Too many signoffs; "
144 "are you missing Co-authored-by lines?")
145 if not set(co_authors) <= set(signatures):
146 print_error("Co-authored-by/Signed-off-by corruption")
147 elif is_signature.match(line):
148 m = is_signature.match(line)
149 signatures.append(m.group(3))
150 elif is_co_author.match(line):
151 m = is_co_author.match(line)
152 co_authors.append(m.group(3))
155 newfile = hunks.match(line)
157 current_file = newfile.group(2)
159 if not is_added_line(line):
161 # Skip files which have /datapath in them, since they are
162 # linux or windows coding standards
163 if '/datapath' in current_file:
165 if (not current_file.endswith('.mk') and
166 not leading_whitespace_is_spaces(line[1:])):
168 print_warning("Line has non-spaces leading whitespace",
170 if trailing_whitespace_or_crlf(line[1:]):
172 print_warning("Line has trailing whitespace", lineno)
173 if len(line[1:]) > 79 and not skip_line_length_check:
175 print_warning("Line is greater than 79-characters long",
177 if not if_and_for_whitespace_checks(line[1:]):
179 print_warning("Improper whitespace around control block",
183 if __errors or __warnings:
189 print("Open vSwitch checkpatch.py")
190 print("Checks a patch for trivial mistakes.")
192 print("%s [options] [patch file]" % sys.argv[0])
194 print("-h|--help\t\t\t\tThis help message")
195 print("-b|--skip-block-whitespace\t"
196 "Skips the if/while/for whitespace tests")
197 print("-l|--skip-leading-whitespace\t"
198 "Skips the leading whitespace test")
199 print("-s|--skip-signoff-lines\t"
200 "Do not emit an error if no Signed-off-by line is present")
201 print("-t|--skip-trailing-whitespace\t"
202 "Skips the trailing whitespace test")
205 def ovs_checkpatch_file(filename):
207 mail = email.message_from_file(open(filename, 'r'))
209 print_error("Unable to parse file '%s'. Is it a patch?" % filename)
212 for part in mail.walk():
213 if part.get_content_maintype() == 'multipart':
215 return ovs_checkpatch_parse(part.get_payload(decode=True))
217 if __name__ == '__main__':
219 optlist, args = getopt.getopt(sys.argv[1:], 'bhlst',
221 "skip-block-whitespace",
222 "skip-leading-whitespace",
223 "skip-signoff-lines",
224 "skip-trailing-whitespace"])
226 print("Unknown option encountered. Please rerun with -h for help.")
230 if o in ("-h", "--help"):
233 elif o in ("-b", "--skip-block-whitespace"):
234 skip_block_whitespace_check = True
235 elif o in ("-l", "--skip-leading-whitespace"):
236 skip_leading_whitespace_check = True
237 elif o in ("-s", "--skip-signoff-lines"):
238 skip_signoff_check = True
239 elif o in ("-t", "--skip-trailing-whitespace"):
240 skip_trailing_whitespace_check = True
242 print("Unknown option '%s'" % o)
247 if sys.stdin.isatty():
250 sys.exit(ovs_checkpatch_parse(sys.stdin.read()))
251 sys.exit(ovs_checkpatch_file(filename))