1#!/usr/bin/env python 2# 3# litlint 4# 5# Ensure RUN commands in lit tests are free of common errors. 6# 7# If any errors are detected, litlint returns a nonzero exit code. 8# 9 10import optparse 11import re 12import sys 13from io import open 14 15# Compile regex once for all files 16runRegex = re.compile(r'(?<!-o)(?<!%run) %t\s') 17 18def LintLine(s): 19 """ Validate a line 20 21 Args: 22 s: str, the line to validate 23 24 Returns: 25 Returns an error message and a 1-based column number if an error was 26 detected, otherwise (None, None). 27 """ 28 29 # Check that RUN command can be executed with an emulator 30 m = runRegex.search(s) 31 if m: 32 start, end = m.span() 33 return ('missing %run before %t', start + 2) 34 35 # No errors 36 return (None, None) 37 38 39def LintFile(p): 40 """ Check that each RUN command can be executed with an emulator 41 42 Args: 43 p: str, valid path to a file 44 45 Returns: 46 The number of errors detected. 47 """ 48 errs = 0 49 with open(p, 'r', encoding='utf-8') as f: 50 for i, s in enumerate(f.readlines(), start=1): 51 msg, col = LintLine(s) 52 if msg != None: 53 errs += 1 54 errorMsg = 'litlint: {}:{}:{}: error: {}.\n{}{}\n' 55 arrow = (col-1) * ' ' + '^' 56 sys.stderr.write(errorMsg.format(p, i, col, msg, s, arrow)) 57 return errs 58 59 60if __name__ == "__main__": 61 # Parse args 62 parser = optparse.OptionParser() 63 parser.add_option('--filter') # ignored 64 (options, filenames) = parser.parse_args() 65 66 # Lint each file 67 errs = 0 68 for p in filenames: 69 errs += LintFile(p) 70 71 # If errors, return nonzero 72 if errs > 0: 73 sys.exit(1) 74