--- /dev/null
+#!/usr/bin/env python
+# Copyright (c) 2016 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+from __future__ import print_function
+
+import email
+import getopt
+import re
+import sys
+
+__errors = 0
+__warnings = 0
+
+
+def print_error(message, lineno=None):
+ global __errors
+ if lineno is not None:
+ print("E(%d): %s" % (lineno, message))
+ else:
+ print("E: %s" % (message))
+
+ __errors = __errors + 1
+
+
+def print_warning(message, lineno=None):
+ global __warnings
+ if lineno:
+ print("W(%d): %s" % (lineno, message))
+ else:
+ print("W: %s" % (message))
+
+ __warnings = __warnings + 1
+
+
+__regex_added_line = re.compile(r'^\+{1,2}[^\+][\w\W]*')
+__regex_leading_with_whitespace_at_all = re.compile(r'^\s+')
+__regex_leading_with_spaces = re.compile(r'^ +[\S]+')
+__regex_trailing_whitespace = re.compile(r'[^\S]+$')
+__regex_for_if_missing_whitespace = re.compile(r'(if|for|while)[\(]')
+__regex_for_if_too_much_whitespace = re.compile(r'(if|for|while) +[\(]')
+__regex_for_if_parens_whitespace = re.compile(r'(if|for|while) \( +[\s\S]+\)')
+
+skip_leading_whitespace_check = False
+skip_trailing_whitespace_check = False
+skip_block_whitespace_check = False
+skip_signoff_check = False
+
+
+def is_added_line(line):
+ """Returns TRUE if the line in question is an added line.
+ """
+ return __regex_added_line.search(line) is not None
+
+
+def leading_whitespace_is_spaces(line):
+ """Returns TRUE if the leading whitespace in added lines is spaces
+ """
+ if skip_leading_whitespace_check:
+ return True
+ if __regex_leading_with_whitespace_at_all.search(line) is not None:
+ return __regex_leading_with_spaces.search(line) is not None
+ return True
+
+
+def trailing_whitespace_or_crlf(line):
+ """Returns TRUE if the trailing characters is whitespace
+ """
+ if skip_trailing_whitespace_check:
+ return False
+ return __regex_trailing_whitespace.search(line) is not None
+
+
+def if_and_for_whitespace_checks(line):
+ """Return TRUE if there is appropriate whitespace after if, for, while
+ """
+ if skip_block_whitespace_check:
+ return True
+ if (__regex_for_if_missing_whitespace.search(line) is not None or
+ __regex_for_if_too_much_whitespace.search(line) is not None or
+ __regex_for_if_parens_whitespace.search(line)):
+ return False
+ return True
+
+
+def ovs_checkpatch_parse(text):
+ lineno = 0
+ signatures = []
+ co_authors = []
+ parse = 0
+ current_file = ''
+ scissors = re.compile(r'^[\w]*---[\w]*')
+ hunks = re.compile('^(---|\+\+\+) (\S+)')
+ is_signature = re.compile(r'((\s*Signed-off-by: )(.*))$',
+ re.I | re.M | re.S)
+ is_co_author = re.compile(r'(\s*(Co-authored-by: )(.*))$',
+ re.I | re.M | re.S)
+
+ for line in text.split('\n'):
+ lineno = lineno + 1
+ if len(line) <= 0:
+ continue
+
+ if parse == 1:
+ match = hunks.match(line)
+ if match:
+ parse = parse + 1
+ current_file = match.group(2)
+ continue
+ elif parse == 0:
+ if scissors.match(line):
+ parse = parse + 1
+ if not skip_signoff_check:
+ if len(signatures) == 0:
+ print_error("No signatures found.")
+ if len(signatures) != 1 + len(co_authors):
+ print_error("Too many signoffs; "
+ "are you missing Co-authored-by lines?")
+ if not set(co_authors) <= set(signatures):
+ print_error("Co-authored-by/Signed-off-by corruption")
+ elif is_signature.match(line):
+ m = is_signature.match(line)
+ signatures.append(m.group(3))
+ elif is_co_author.match(line):
+ m = is_co_author.match(line)
+ co_authors.append(m.group(3))
+ elif parse == 2:
+ print_line = False
+ newfile = hunks.match(line)
+ if newfile:
+ current_file = newfile.group(2)
+ continue
+ if not is_added_line(line):
+ continue
+ # Skip files which have /datapath in them, since they are
+ # linux or windows coding standards
+ if '/datapath' in current_file:
+ continue
+ if (not current_file.endswith('.mk') and
+ not leading_whitespace_is_spaces(line[1:])):
+ print_line = True
+ print_warning("Line has non-spaces leading whitespace",
+ lineno)
+ if trailing_whitespace_or_crlf(line[1:]):
+ print_line = True
+ print_warning("Line has trailing whitespace", lineno)
+ if len(line[1:]) > 79:
+ print_line = True
+ print_warning("Line is greater than 79-characters long",
+ lineno)
+ if not if_and_for_whitespace_checks(line[1:]):
+ print_line = True
+ print_warning("Improper whitespace around control block",
+ lineno)
+ if print_line:
+ print(line)
+ if __errors or __warnings:
+ return -1
+ return 0
+
+
+def usage():
+ print("Open vSwitch checkpatch.py")
+ print("Checks a patch for trivial mistakes.")
+ print("usage:")
+ print("%s [options] [patch file]" % sys.argv[0])
+ print("options:")
+ print("-h|--help\t\t\t\tThis help message")
+ print("-b|--skip-block-whitespace\t"
+ "Skips the if/while/for whitespace tests")
+ print("-l|--skip-leading-whitespace\t"
+ "Skips the leading whitespace test")
+ print("-s|--skip-signoff-lines\t"
+ "Do not emit an error if no Signed-off-by line is present")
+ print("-t|--skip-trailing-whitespace\t"
+ "Skips the trailing whitespace test")
+
+def ovs_checkpatch_file(filename):
+ try:
+ mail = email.message_from_file(open(filename, 'r'))
+ except:
+ print_error("Unable to parse file '%s'. Is it a patch?" % filename)
+ return -1
+
+ for part in mail.walk():
+ if part.get_content_maintype() == 'multipart':
+ continue
+ return ovs_checkpatch_parse(part.get_payload(decode=True))
+
+if __name__ == '__main__':
+ try:
+ optlist, args = getopt.getopt(sys.argv[1:], 'bhlst',
+ ["help",
+ "skip-block-whitespace",
+ "skip-leading-whitespace",
+ "skip-signoff-lines",
+ "skip-trailing-whitespace"])
+ except:
+ print("Unknown option encountered. Please rerun with -h for help.")
+ sys.exit(-1)
+
+ for o, a in optlist:
+ if o in ("-h", "--help"):
+ usage()
+ sys.exit(0)
+ elif o in ("-b", "--skip-block-whitespace"):
+ skip_block_whitespace_check = True
+ elif o in ("-l", "--skip-leading-whitespace"):
+ skip_leading_whitespace_check = True
+ elif o in ("-s", "--skip-signoff-lines"):
+ skip_signoff_check = True
+ elif o in ("-t", "--skip-trailing-whitespace"):
+ skip_trailing_whitespace_check = True
+ else:
+ print("Unknown option '%s'" % o)
+ sys.exit(-1)
+ try:
+ filename = args[0]
+ except:
+ if sys.stdin.isatty():
+ usage()
+ sys.exit(-1)
+ sys.exit(ovs_checkpatch_parse(sys.stdin.read()))
+ sys.exit(ovs_checkpatch_file(filename))