1#!/usr/bin/python 2 3"""Parse and check syntax errors of a given OWNERS file.""" 4 5import argparse 6import re 7import sys 8import urllib.request, urllib.parse, urllib.error 9import urllib.request, urllib.error, urllib.parse 10 11parser = argparse.ArgumentParser(description='Check OWNERS file syntax') 12parser.add_argument('-v', '--verbose', dest='verbose', 13 action='store_true', default=False, 14 help='Verbose output to debug') 15parser.add_argument('-c', '--check_address', dest='check_address', 16 action='store_true', default=False, 17 help='Check email addresses') 18parser.add_argument(dest='owners', metavar='OWNERS', nargs='+', 19 help='Path to OWNERS file') 20args = parser.parse_args() 21 22gerrit_server = 'https://android-review.googlesource.com' 23checked_addresses = {} 24 25 26def echo(msg): 27 if args.verbose: 28 print(msg) 29 30 31def find_address(address): 32 if address not in checked_addresses: 33 request = (gerrit_server + '/accounts/?n=1&q=email:' 34 + urllib.parse.quote(address)) 35 echo('Checking email address: ' + address) 36 result = urllib.request.urlopen(request).read() 37 checked_addresses[address] = result.find('"_account_id":') >= 0 38 if checked_addresses[address]: 39 echo('Found email address: ' + address) 40 return checked_addresses[address] 41 42 43def check_address(fname, num, address): 44 if find_address(address): 45 return 0 46 print('%s:%d: ERROR: unknown email address: %s' % (fname, num, address)) 47 return 1 48 49 50def main(): 51 # One regular expression to check all valid lines. 52 noparent = 'set +noparent' 53 email = '([^@ ]+@[^ @]+|\\*)' 54 emails = '(%s( *, *%s)*)' % (email, email) 55 file_directive = 'file: *([^ :]+ *: *)?[^ ]+' 56 directive = '(%s|%s|%s)' % (emails, noparent, file_directive) 57 glob = '[a-zA-Z0-9_\\.\\-\\*\\?]+' 58 globs = '(%s( *, *%s)*)' % (glob, glob) 59 perfile = 'per-file +' + globs + ' *= *' + directive 60 include = 'include +([^ :]+ *: *)?[^ ]+' 61 pats = '(|%s|%s|%s|%s|%s)$' % (noparent, email, perfile, include, file_directive) 62 patterns = re.compile(pats) 63 address_pattern = re.compile('([^@ ]+@[^ @]+)') 64 perfile_pattern = re.compile('per-file +.*=(.*)') 65 66 error = 0 67 for fname in args.owners: 68 echo('Checking file: ' + fname) 69 num = 0 70 for line in open(fname, 'r'): 71 num += 1 72 stripped_line = re.sub('#.*$', '', line).strip() 73 if not patterns.match(stripped_line): 74 error += 1 75 print('%s:%d: ERROR: unknown line [%s]' % (fname, num, line.strip())) 76 elif args.check_address: 77 if perfile_pattern.match(stripped_line): 78 for addr in perfile_pattern.match(stripped_line).group(1).split(','): 79 a = addr.strip() 80 if a and a != '*': 81 error += check_address(fname, num, addr.strip()) 82 elif address_pattern.match(stripped_line): 83 error += check_address(fname, num, stripped_line) 84 sys.exit(error) 85 86if __name__ == '__main__': 87 main() 88