* 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

View File

@ -2,7 +2,7 @@
# Copyright 2009, Alexandre Deckner, alex@zappotek.com
# Distributed under the terms of the MIT License.
#
import re, sys
import re, sys, os
from utils import *
@ -12,44 +12,73 @@ def processMatches(matches, name, text, highlights):
highlights.append((match.start(), match.end(), name))
def run(sourceFile, rules):
file = open(sourceFile, 'r')
text = file.read()
def run(fileSet, rules, outputFileName):
openHtml(fileSet, outputFileName)
highlights = []
for fileName in fileSet:
print "\nChecking " + fileName + ":"
file = open(fileName, 'r')
text = file.read()
for name, regexp in rules.items():
processMatches(regexp.finditer(text), name, text, highlights)
highlights = []
highlights.sort()
highlights = checkHighlights(highlights)
for name, regexp in rules.items():
processMatches(regexp.finditer(text), name, text, highlights)
file.close()
renderHtml(text, highlights, sourceFile, "styleviolations.html")
highlights.sort()
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["Line over 80 char"] = re.compile('[^\n]{81,}')
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 after operator"] \
= 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["Mixed tabs/spaces"] = re.compile('( \t]|\t )+')
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"] = re.compile('\n}([ \t]*\n){0,2}.')
cppRules["Lines between functions > 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
#cppRules["-Comment 1"] = re.compile('[^/]/\*(.|[\r\n])*?\*/')
#cppRules["-Comment 2"] = re.compile('(//)[^\n]*')
if len(sys.argv) == 2 and sys.argv[1] != "--help":
run(sys.argv[1], cppRules)
if len(sys.argv) >= 2 and sys.argv[1] != "--help":
run(makeFileSet(sys.argv[1:]), cppRules, "styleviolations.html")
else:
print "Usage: python checkstyle.py file.cpp\n"
print "Checks a c++ source file against the Haiku Coding Guidelines."
print "Outputs an highlighted html report in the styleviolations.html file.\n"
print "Usage: python checkstyle.py file.cpp [file2.cpp] [directory]\n"
print "Checks c++ source files against the Haiku Coding Guidelines."
print "Outputs an html report in the styleviolations.html file.\n"

View File

@ -15,29 +15,43 @@ def printMatch(name, match, source):
+ "): '" + match.group().replace('\n','\\n') + "'"
# render in html, the file style.css is embedded
def renderHtml(text, highlights, sourceFileName, outputFileName):
splittedText = highlightSplit(text, highlights)
#styleFile = open("style.css")
#style = styleFile.read()
#styleFile.close()
def openHtml(fileList, outputFileName):
file = open(outputFileName, 'w')
file.write("""
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Style violations in """ + sourceFileName.split('/')[-1] \
+ """</title>
<title>Style violations</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css">""" + cssStyle() + """</style>
</head>
<body>
<p>""" + sourceFileName + """</p>
<pre class="code">""")
<p><b>File list:</b><br>""")
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 = ""
count = 0
for slice in splittedText:
@ -50,15 +64,19 @@ def renderHtml(text, highlights, sourceFileName, outputFileName):
temp += "</span>" # close the superfluous last highlight
file.write('<table><tr><td><pre class="code"><span class="linenumber">')
count = 1
for line in temp.split('\n'):
file.write(str(count).rjust(4) + ' |' + line + '<br>')
file.write(str(count).rjust(4)+"<br>")
count += 1
file.write("""
</pre>
</body>
</html>""")
file.write('</span></pre></td><td><pre class="code">')
for line in temp.split('\n'):
file.write('<span class="linehead"> </span>' + line.replace('\r', ' ') \
+ '<br>')
file.write("</pre></td></tr></table>")
file.close()
@ -130,12 +148,36 @@ def checkHighlights(highlights):
def cssStyle():
return """
return """
.highlight {
background: #ffff00;
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 {
font-family: monospace;
}