Provide script 'check-style' for validating patches
Run the script with a patch file as the first argument in order to validate the patch in terms of coding style, like so: ./tools/check-style my-patch.diff As a shortcut, you can also check current changes: ./tools/check-style .
This commit is contained in:
parent
3aad0189c4
commit
0ca6c68f0c
1 changed files with 161 additions and 0 deletions
161
tools/check-style
Executable file
161
tools/check-style
Executable file
|
@ -0,0 +1,161 @@
|
|||
#! /usr/bin/env python
|
||||
|
||||
# Copyright (C) 2010 Christian Dywan <christian@twotoasts.de>
|
||||
# Copyright (C) 2010 Arno Renevier <arno@renevier.net>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# See the file COPYING for the full license text.
|
||||
#
|
||||
# check-style: Verify C source code according to coding style.
|
||||
|
||||
import glob, re, string, subprocess, sys, os
|
||||
|
||||
if len (sys.argv) < 2:
|
||||
name = os.path.basename (sys.argv[0])
|
||||
print ('Usage:\n ' + name + ' FILENAMES\n'
|
||||
' Pass "-" to read stdin, eg. "cat my-feature.diff | ' + name + ' -"\n'
|
||||
' Pass "." to mean "git diff ^HEAD | ' + name + ' -"')
|
||||
sys.exit (1)
|
||||
|
||||
# Coding style violations
|
||||
violations = [
|
||||
['.{101}', 'Line longer than 100 columns'],
|
||||
['^[ ]{1,3}[^ ]+', 'Indentation is less than 4 spaces'],
|
||||
# FIXME: Don't match empty strings
|
||||
# FIXME: Don't match indented function arguments
|
||||
# ['^(?!(([ ]{4})*[^ ]+))', 'Indentation is not 4 spaces'],
|
||||
['.*[ ]+$', 'Trailing whitespace'],
|
||||
[r"\t+", 'Tabs instead of spaces'],
|
||||
["[^0-9],[^ ][^0-9]", 'No space after comma'],
|
||||
# ['(([A-Z][a-z]+)+)\*?[ ][a-z]{2,}', 'Good variable name'],
|
||||
# ['(g?char|g(boolean|pointer))\*?[ ][a-z]{2,}', 'Good variable name'],
|
||||
# ['(g?int|guint)[ ][a-z]+', 'Good iterator name'],
|
||||
# ['(struct)[ ]+[_]?([A-Z][a-z]+)+', 'Good type name'],
|
||||
['^\s*\w+(?<!\\breturn)\s+\*\s*\w*\s*[;,]', 'Space between type and asterisk'],
|
||||
["(\w[+|-|*|/|<|>|=]{1,2}\w)", 'No space around operators'],
|
||||
["\/\*[^ *\n]", 'No space after open comment'],
|
||||
['[^ *]\*\/', 'No space before close comment'],
|
||||
['\)\{', 'No space between ) and {'],
|
||||
[';[^ \s]', 'No space or newline after semicolon'],
|
||||
# ['(if)( \([^ ].*[^ ]\))$', 'Good if style'],
|
||||
['^#\s+(if(n?def)?|define|else|elif)[ ].*$', 'Space between # and cpp'],
|
||||
[r'^\s*\*\w+(\+\+|--);', 'Invalid increment, use (*i)++ or *i += 1'],
|
||||
['asctime|ctime|getgrgid|getprgnam|getlogin \
|
||||
|getpwnam|getpwuid|gmtime|localtime \
|
||||
|rand|readdir|strtok|ttyname', 'Not thread-safe posix, use _r variant'],
|
||||
]
|
||||
# No validation for strings, comments, includes
|
||||
omissions = [
|
||||
[r'["]{1}.*["]', 'STRING'],
|
||||
["'\\\?.'", 'CHAR'],
|
||||
["^\s*\/\*.*\*\/\s*$", 'COMMENT'],
|
||||
['#include <.*>', 'INCLUDE'],
|
||||
]
|
||||
|
||||
# Output format
|
||||
fmt = '%s - %d: %s'
|
||||
|
||||
# Pre-compile expressions
|
||||
for violation in violations:
|
||||
violation[0] = re.compile (violation[0])
|
||||
for omission in omissions:
|
||||
omission[0] = re.compile (omission[0])
|
||||
|
||||
for filename_or_glob in sys.argv[1:]:
|
||||
if filename_or_glob == '-':
|
||||
handles = [sys.stdin]
|
||||
else:
|
||||
handles = []
|
||||
for filename in glob.glob (filename_or_glob):
|
||||
if os.path.isdir (filename):
|
||||
gitdiff = subprocess.Popen (['git', 'diff', '^HEAD',
|
||||
'--relative', filename], stdout=subprocess.PIPE)
|
||||
handles.append (gitdiff.stdout)
|
||||
else:
|
||||
handles.append (open (filename))
|
||||
if not handles:
|
||||
print (filename_or_glob + ' not found')
|
||||
sys.exit (1)
|
||||
|
||||
for handle in handles:
|
||||
previous = ''
|
||||
i = 0
|
||||
mode = ''
|
||||
filename = handle.name
|
||||
comment = False
|
||||
curly = []
|
||||
|
||||
for line in handle:
|
||||
line = line[:-1]
|
||||
i += 1
|
||||
|
||||
# Parse diff, only validate modified lines
|
||||
if i == 1 and 'diff' in line:
|
||||
mode = 'diff'
|
||||
if mode == 'diff':
|
||||
if line[:3] == '+++':
|
||||
filename = line[6:]
|
||||
comment = False
|
||||
curly = []
|
||||
continue
|
||||
if line[:2] == '@@':
|
||||
i = int (line.split (' ')[2].split (',')[0][1:]) - 1
|
||||
curly = []
|
||||
if line[0] == '-':
|
||||
i = i -1
|
||||
if line[0] != '+':
|
||||
continue
|
||||
line = line[1:]
|
||||
|
||||
# Spurious blank lines
|
||||
if previous == line == '':
|
||||
print (fmt % (filename, i, 'Spurious blank line'))
|
||||
previous = line
|
||||
continue
|
||||
previous = line
|
||||
|
||||
# Skip multi-line comment blocks
|
||||
if '/*' in line and not '*/' in line:
|
||||
comment = True
|
||||
if comment:
|
||||
if '*/' in line and not '/*' in line:
|
||||
comment = False
|
||||
continue
|
||||
|
||||
cleaned = line
|
||||
for omission in omissions:
|
||||
cleaned = omission[0].sub (omission[1], cleaned)
|
||||
|
||||
# Validate curly bracket indentation
|
||||
if '{' in cleaned and not '}' in cleaned:
|
||||
curly.append ((cleaned.index ('{'), cleaned))
|
||||
if '}' in cleaned and not '{' in cleaned and not '},' in cleaned:
|
||||
if len (curly) == 0 or curly[-1][0] != cleaned.index ('}'):
|
||||
print (fmt % (filename, i, 'Misindented curly bracket'))
|
||||
print (curly[-1][1])
|
||||
print (line)
|
||||
curly.pop()
|
||||
continue
|
||||
curly.pop()
|
||||
|
||||
# Validate preprocessor indentation
|
||||
# FIXME: Don't warn if the *following* line is a curly
|
||||
cpp = cleaned.find ('#if')
|
||||
if cpp != -1:
|
||||
if len (curly) != 0 and cpp != curly[-1][0] + 4:
|
||||
print (fmt % (filename, i, 'Misindented preprocessor #if'))
|
||||
print (curly[-1][1])
|
||||
print (line)
|
||||
|
||||
violated = False
|
||||
for violation in violations:
|
||||
if violation[0].search (cleaned):
|
||||
violated = True
|
||||
print (fmt % (filename, i, violation[1]))
|
||||
if violated:
|
||||
print (line)
|
||||
|
Loading…
Reference in a new issue