|
|
@ -1,3 +1,4 @@
|
|
|
|
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
import re, os, sys
|
|
|
|
import re, os, sys
|
|
|
|
|
|
|
|
|
|
|
|
valid_extensions = ['c', 'cpp', 'h', 'hpp', 'mm', 'lua', 'rb', 'proto',
|
|
|
|
valid_extensions = ['c', 'cpp', 'h', 'hpp', 'mm', 'lua', 'rb', 'proto',
|
|
|
@ -18,28 +19,13 @@ def valid_file(filename):
|
|
|
|
not len(list(filter(lambda path: path.replace('\\', '/') in filename.replace('\\', '/'), path_blacklist)))
|
|
|
|
not len(list(filter(lambda path: path.replace('\\', '/') in filename.replace('\\', '/'), path_blacklist)))
|
|
|
|
|
|
|
|
|
|
|
|
success = True
|
|
|
|
success = True
|
|
|
|
def error(msg):
|
|
|
|
def error(msg=None):
|
|
|
|
global success
|
|
|
|
global success
|
|
|
|
success = False
|
|
|
|
success = False
|
|
|
|
|
|
|
|
if msg:
|
|
|
|
sys.stderr.write(msg + '\n')
|
|
|
|
sys.stderr.write(msg + '\n')
|
|
|
|
|
|
|
|
|
|
|
|
class LinterError(Exception): pass
|
|
|
|
def format_lines(lines, total):
|
|
|
|
|
|
|
|
|
|
|
|
class Linter(object):
|
|
|
|
|
|
|
|
ignore = False
|
|
|
|
|
|
|
|
def check(self, lines):
|
|
|
|
|
|
|
|
failures = []
|
|
|
|
|
|
|
|
for i, line in enumerate(lines):
|
|
|
|
|
|
|
|
if not self.check_line(line):
|
|
|
|
|
|
|
|
failures.append(i + 1)
|
|
|
|
|
|
|
|
if len(failures):
|
|
|
|
|
|
|
|
raise LinterError('%s: %s' % (self.msg, self.display_lines(failures, len(lines))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def fix(self, lines):
|
|
|
|
|
|
|
|
for i in range(len(lines)):
|
|
|
|
|
|
|
|
lines[i] = self.fix_line(lines[i])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def display_lines(self, lines, total):
|
|
|
|
|
|
|
|
if len(lines) == total - 1:
|
|
|
|
if len(lines) == total - 1:
|
|
|
|
return 'entire file'
|
|
|
|
return 'entire file'
|
|
|
|
if not len(lines):
|
|
|
|
if not len(lines):
|
|
|
@ -64,6 +50,34 @@ class Linter(object):
|
|
|
|
s += ('%i-%i, ' % (range_start, range_end))
|
|
|
|
s += ('%i-%i, ' % (range_start, range_end))
|
|
|
|
return s.rstrip(' ').rstrip(',')
|
|
|
|
return s.rstrip(' ').rstrip(',')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LinterError(Exception):
|
|
|
|
|
|
|
|
def __init__(self, message, lines, total_lines):
|
|
|
|
|
|
|
|
self.message = message
|
|
|
|
|
|
|
|
self.lines = lines
|
|
|
|
|
|
|
|
self.total_lines = total_lines
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
|
|
|
return '%s: %s' % (self.message, format_lines(self.lines, self.total_lines))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def github_actions_workflow_command(self, filename):
|
|
|
|
|
|
|
|
first_line = self.lines[0] if self.lines else 1
|
|
|
|
|
|
|
|
return '::error file=%s,line=%i::%s' % (filename, first_line, self)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Linter(object):
|
|
|
|
|
|
|
|
ignore = False
|
|
|
|
|
|
|
|
def check(self, lines):
|
|
|
|
|
|
|
|
failures = []
|
|
|
|
|
|
|
|
for i, line in enumerate(lines):
|
|
|
|
|
|
|
|
if not self.check_line(line):
|
|
|
|
|
|
|
|
failures.append(i + 1)
|
|
|
|
|
|
|
|
if len(failures):
|
|
|
|
|
|
|
|
raise LinterError(self.msg, failures, len(lines))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def fix(self, lines):
|
|
|
|
|
|
|
|
for i in range(len(lines)):
|
|
|
|
|
|
|
|
lines[i] = self.fix_line(lines[i])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NewlineLinter(Linter):
|
|
|
|
class NewlineLinter(Linter):
|
|
|
|
msg = 'Contains DOS-style newlines'
|
|
|
|
msg = 'Contains DOS-style newlines'
|
|
|
|
# git supports newline conversion. Catch in CI, ignore on Windows.
|
|
|
|
# git supports newline conversion. Catch in CI, ignore on Windows.
|
|
|
@ -91,6 +105,7 @@ class TabLinter(Linter):
|
|
|
|
linters = [cls() for cls in Linter.__subclasses__() if not cls.ignore]
|
|
|
|
linters = [cls() for cls in Linter.__subclasses__() if not cls.ignore]
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
def main():
|
|
|
|
|
|
|
|
is_github_actions = os.environ.get('GITHUB_ACTIONS')
|
|
|
|
root_path = os.path.abspath(sys.argv[1] if len(sys.argv) > 1 else '.')
|
|
|
|
root_path = os.path.abspath(sys.argv[1] if len(sys.argv) > 1 else '.')
|
|
|
|
if not os.path.exists(root_path):
|
|
|
|
if not os.path.exists(root_path):
|
|
|
|
print('Nonexistent path: %s' % root_path)
|
|
|
|
print('Nonexistent path: %s' % root_path)
|
|
|
@ -112,12 +127,21 @@ def main():
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
lines[i] = line.decode('utf-8')
|
|
|
|
lines[i] = line.decode('utf-8')
|
|
|
|
except UnicodeDecodeError:
|
|
|
|
except UnicodeDecodeError:
|
|
|
|
error('%s:%i: Invalid UTF-8 (other errors will be ignored)' % (rel_path, i + 1))
|
|
|
|
msg_params = (rel_path, i + 1, 'Invalid UTF-8 (other errors will be ignored)')
|
|
|
|
|
|
|
|
if is_github_actions:
|
|
|
|
|
|
|
|
error()
|
|
|
|
|
|
|
|
print('::error file=%s,line=%i::%s' % msg_params)
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
error('%s:%i: %s' % msg_params)
|
|
|
|
lines[i] = ''
|
|
|
|
lines[i] = ''
|
|
|
|
for linter in linters:
|
|
|
|
for linter in linters:
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
linter.check(lines)
|
|
|
|
linter.check(lines)
|
|
|
|
except LinterError as e:
|
|
|
|
except LinterError as e:
|
|
|
|
|
|
|
|
if is_github_actions:
|
|
|
|
|
|
|
|
error()
|
|
|
|
|
|
|
|
print(e.github_actions_workflow_command(rel_path))
|
|
|
|
|
|
|
|
else:
|
|
|
|
error('%s: %s' % (rel_path, e))
|
|
|
|
error('%s: %s' % (rel_path, e))
|
|
|
|
if fix:
|
|
|
|
if fix:
|
|
|
|
linter.fix(lines)
|
|
|
|
linter.fix(lines)
|
|
|
|