|
|
@ -0,0 +1,61 @@ |
|
|
|
#!/usr/bin/env python3 |
|
|
|
|
|
|
|
import glob |
|
|
|
import os |
|
|
|
import re |
|
|
|
import sys |
|
|
|
|
|
|
|
|
|
|
|
MAX_LINE_LENGTH = 100 |
|
|
|
|
|
|
|
|
|
|
|
# Files with any of these as a substring of their filename are excluded from |
|
|
|
# consideration. |
|
|
|
FILES_TO_EXCLUDE = [ |
|
|
|
'/obj/', |
|
|
|
'/bin/', |
|
|
|
'/AssemblyInfo.cs', |
|
|
|
'/Resource.Designer.cs', |
|
|
|
'Shared/Levels.cs'] |
|
|
|
|
|
|
|
|
|
|
|
def emit_error(filename, line_num, error): |
|
|
|
print('%s:%d: %s' % (filename, line_num, error)) |
|
|
|
|
|
|
|
|
|
|
|
def lint_csharp(filename): |
|
|
|
errors = [] |
|
|
|
with open(filename) as f: |
|
|
|
for i, line in enumerate(f): |
|
|
|
line_num = i + 1 |
|
|
|
line = line[:-1] # Strip trailing newline. |
|
|
|
if len(line) > MAX_LINE_LENGTH: |
|
|
|
if not re.match(r'\s*// https?:', line): |
|
|
|
emit_error(filename, line_num, 'line too long') |
|
|
|
if re.search(r'\t', line): |
|
|
|
emit_error(filename, line_num, 'illegal \\t character') |
|
|
|
if re.search(r'\r', line): |
|
|
|
emit_error(filename, line_num, 'illegal \\r character') |
|
|
|
if re.search(r'\s+$', line): |
|
|
|
emit_error(filename, line_num, 'trailing whitespace') |
|
|
|
if re.match(r'\s*//\S', line): |
|
|
|
emit_error(filename, line_num, 'no space between // and comment') |
|
|
|
|
|
|
|
|
|
|
|
def main(args): |
|
|
|
this_dir = os.path.dirname(os.path.realpath(__file__)) |
|
|
|
sneak_root = os.path.join(this_dir, '..', '..') |
|
|
|
os.chdir(sneak_root) |
|
|
|
|
|
|
|
csharp_files = sorted(glob.glob('**/*.cs', recursive=True)) |
|
|
|
# Remove generated files (of which there's lots). |
|
|
|
for exclusion_pattern in FILES_TO_EXCLUDE: |
|
|
|
csharp_files = [x for x in csharp_files if exclusion_pattern not in x] |
|
|
|
print('checking %d files' % len(csharp_files)) |
|
|
|
|
|
|
|
for filename in csharp_files: |
|
|
|
lint_csharp(filename) |
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
|
main(sys.argv[1:]) |