mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 18:07:40 +00:00
235 lines
8.0 KiB
Python
235 lines
8.0 KiB
Python
|
#!/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))
|