* Add multi file/directory support

* Refined some rules to not include the new-line
* Added 'windows line ending' rule
* Enhanced the html output, not an expert there though



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33889 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Alexandre Deckner
2009-11-05 03:23:50 +00:00
parent eb32e334f8
commit ae762f316d
2 changed files with 109 additions and 38 deletions
+49 -20
View File
@@ -2,7 +2,7 @@
# Copyright 2009, Alexandre Deckner, [email protected] # Copyright 2009, Alexandre Deckner, [email protected]
# Distributed under the terms of the MIT License. # Distributed under the terms of the MIT License.
# #
import re, sys import re, sys, os
from utils import * from utils import *
@@ -12,44 +12,73 @@ def processMatches(matches, name, text, highlights):
highlights.append((match.start(), match.end(), name)) highlights.append((match.start(), match.end(), name))
def run(sourceFile, rules): def run(fileSet, rules, outputFileName):
file = open(sourceFile, 'r') openHtml(fileSet, outputFileName)
text = file.read()
highlights = [] for fileName in fileSet:
print "\nChecking " + fileName + ":"
file = open(fileName, 'r')
text = file.read()
for name, regexp in rules.items(): highlights = []
processMatches(regexp.finditer(text), name, text, highlights)
highlights.sort() for name, regexp in rules.items():
highlights = checkHighlights(highlights) processMatches(regexp.finditer(text), name, text, highlights)
file.close() highlights.sort()
renderHtml(text, highlights, sourceFile, "styleviolations.html") highlights = checkHighlights(highlights)
file.close()
renderHtml(text, highlights, fileName, outputFileName)
closeHtml(outputFileName)
# make a flat list of files recursively from the arg list
def makeFileSet(args):
files = []
extensions = [".cpp", ".h"]
for arg in args:
if os.path.isfile(arg) and os.path.splitext(arg)[1] in extensions:
files.append(arg)
elif os.path.isdir(arg):
for content in os.listdir(arg):
path = os.path.join(arg, content)
if os.path.isfile(path) \
and os.path.splitext(path)[1] in extensions:
files.append(path)
elif os.path.isdir(path) and os.path.basename(path) != ".svn":
files.extend(makeFileSet([path]))
return files
cppRules = {} cppRules = {}
cppRules["Line over 80 char"] = re.compile('[^\n]{81,}') cppRules["Line over 80 char"] = re.compile('[^\n]{81,}')
cppRules["Spaces instead of tabs"] = re.compile(' ') cppRules["Spaces instead of tabs"] = re.compile(' ')
cppRules["Missing space after for/if/select/while"] = re.compile('(for|if|select|while)\(') cppRules["Missing space after for/if/select/while"] \
= re.compile('(for|if|select|while)\(')
cppRules["Missing space at comment start"] = re.compile('//[a-zA-Z0-9]') cppRules["Missing space at comment start"] = re.compile('//[a-zA-Z0-9]')
cppRules["Missing space after operator"] \ cppRules["Missing space after operator"] \
= re.compile('[a-zA-Z0-9](==|[,=>/+\-*;\|])[a-zA-Z0-9]') = re.compile('[a-zA-Z0-9](==|[,=>/+\-*;\|])[a-zA-Z0-9]')
cppRules["Operator at line end"] = re.compile('([*=/+\-\|\&\?]|\&&|\|\|)\n') cppRules["Operator at line end"] = re.compile('([*=/+\-\|\&\?]|\&&|\|\|)(?=\n)')
cppRules["Missing space"] = re.compile('\){') cppRules["Missing space"] = re.compile('\){')
cppRules["Mixed tabs/spaces"] = re.compile('( \t]|\t )+') cppRules["Mixed tabs/spaces"] = re.compile('( \t]|\t )+')
cppRules["Malformed else"] = re.compile('}[ \t]*\n[ \t]*else') cppRules["Malformed else"] = re.compile('}[ \t]*\n[ \t]*else')
cppRules["Lines between functions > 2"] = re.compile('\n}([ \t]*\n){4,}') cppRules["Lines between functions > 2"] \
cppRules["Lines between functions < 2"] = re.compile('\n}([ \t]*\n){0,2}.') = re.compile('(?<=\n})([ \t]*\n){3,}(?=\n)')
cppRules["Lines between functions < 2"] \
= re.compile('(?<=\n})([ \t]*\n){0,2}(?=.)')
cppRules["Windows Line Ending"] = re.compile('\r')
# TODO: ignore some rules in comments # TODO: ignore some rules in comments
#cppRules["-Comment 1"] = re.compile('[^/]/\*(.|[\r\n])*?\*/') #cppRules["-Comment 1"] = re.compile('[^/]/\*(.|[\r\n])*?\*/')
#cppRules["-Comment 2"] = re.compile('(//)[^\n]*') #cppRules["-Comment 2"] = re.compile('(//)[^\n]*')
if len(sys.argv) == 2 and sys.argv[1] != "--help": if len(sys.argv) >= 2 and sys.argv[1] != "--help":
run(sys.argv[1], cppRules) run(makeFileSet(sys.argv[1:]), cppRules, "styleviolations.html")
else: else:
print "Usage: python checkstyle.py file.cpp\n" print "Usage: python checkstyle.py file.cpp [file2.cpp] [directory]\n"
print "Checks a c++ source file against the Haiku Coding Guidelines." print "Checks c++ source files against the Haiku Coding Guidelines."
print "Outputs an highlighted html report in the styleviolations.html file.\n" print "Outputs an html report in the styleviolations.html file.\n"
+60 -18
View File
@@ -15,29 +15,43 @@ def printMatch(name, match, source):
+ "): '" + match.group().replace('\n','\\n') + "'" + "): '" + match.group().replace('\n','\\n') + "'"
# render in html, the file style.css is embedded def openHtml(fileList, outputFileName):
def renderHtml(text, highlights, sourceFileName, outputFileName):
splittedText = highlightSplit(text, highlights)
#styleFile = open("style.css")
#style = styleFile.read()
#styleFile.close()
file = open(outputFileName, 'w') file = open(outputFileName, 'w')
file.write(""" file.write("""
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<title>Style violations in """ + sourceFileName.split('/')[-1] \ <title>Style violations</title>
+ """</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css">""" + cssStyle() + """</style> <style type="text/css">""" + cssStyle() + """</style>
</head> </head>
<body> <body>
<p>""" + sourceFileName + """</p> <p><b>File list:</b><br>""")
<pre class="code">""") for fileName in fileList:
file.write(fileName + "<br>")
file.write("</p>")
file.close()
def closeHtml(outputFileName):
file = open(outputFileName, 'a')
file.write("""
</pre>
</body>
</html>""")
file.close()
# render in html
def renderHtml(text, highlights, sourceFileName, outputFileName):
splittedText = highlightSplit(text, highlights)
file = open(outputFileName, 'a')
file.write("<hr/><p><b>" + sourceFileName + "</b></p>")
# insert highlight tags in a temp buffer
temp = "" temp = ""
count = 0 count = 0
for slice in splittedText: for slice in splittedText:
@@ -50,15 +64,19 @@ def renderHtml(text, highlights, sourceFileName, outputFileName):
temp += "</span>" # close the superfluous last highlight temp += "</span>" # close the superfluous last highlight
file.write('<table><tr><td><pre class="code"><span class="linenumber">')
count = 1 count = 1
for line in temp.split('\n'): for line in temp.split('\n'):
file.write(str(count).rjust(4) + ' |' + line + '<br>') file.write(str(count).rjust(4)+"<br>")
count += 1 count += 1
file.write(""" file.write('</span></pre></td><td><pre class="code">')
</pre>
</body> for line in temp.split('\n'):
</html>""") file.write('<span class="linehead"> </span>' + line.replace('\r', ' ') \
+ '<br>')
file.write("</pre></td></tr></table>")
file.close() file.close()
@@ -130,12 +148,36 @@ def checkHighlights(highlights):
def cssStyle(): def cssStyle():
return """ return """
.highlight { .highlight {
background: #ffff00; background: #ffff00;
color: #000000; color: #000000;
} }
.linehead {
background: #ddd;
font-size: 1px;
}
.highlight .linehead {
background: #ffff00;;
color: #999;
text-align: right;
font-size: 8px;
}
.linenumber {
background: #eee;
color: #999;
text-align: right;
}
td {
border-spacing: 0px;
border-width: 0px;
padding: 0px
}
div.code pre { div.code pre {
font-family: monospace; font-family: monospace;
} }