• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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