diff --git a/tools/scripts/lint.py b/tools/scripts/lint.py new file mode 100644 index 0000000..5643a88 --- /dev/null +++ b/tools/scripts/lint.py @@ -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:])