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