* 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:
@@ -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"
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user