| OLD | NEW |
| 1 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """A database of OWNERS files.""" | 5 """A database of OWNERS files.""" |
| 6 | 6 |
| 7 import re | 7 import re |
| 8 | 8 |
| 9 | 9 |
| 10 # If this is present by itself on a line, this means that everyone can review. | 10 # If this is present by itself on a line, this means that everyone can review. |
| 11 EVERYONE = '*' | 11 EVERYONE = '*' |
| 12 | 12 |
| 13 | 13 |
| 14 # Recognizes 'X@Y' email addresses. Very simplistic. | 14 # Recognizes 'X@Y' email addresses. Very simplistic. |
| 15 BASIC_EMAIL_REGEXP = r'^[\w\-\+\%\.]+\@[\w\-\+\%\.]+$' | 15 BASIC_EMAIL_REGEXP = r'^[\w\-\+\%\.]+\@[\w\-\+\%\.]+$' |
| 16 | 16 |
| 17 | 17 |
| 18 class SyntaxErrorInOwnersFile(Exception): | 18 class SyntaxErrorInOwnersFile(Exception): |
| 19 def __init__(self, path, line, msg): | 19 def __init__(self, path, lineno, msg): |
| 20 super(SyntaxErrorInOwnersFile, self).__init__((path, line, msg)) | 20 super(SyntaxErrorInOwnersFile, self).__init__((path, lineno, msg)) |
| 21 self.path = path | 21 self.path = path |
| 22 self.line = line | 22 self.lineno = lineno |
| 23 self.msg = msg | 23 self.msg = msg |
| 24 | 24 |
| 25 def __str__(self): | 25 def __str__(self): |
| 26 if self.msg: | 26 return "%s:%d syntax error: %s" % (self.path, self.lineno, self.msg) |
| 27 return "%s:%d syntax error: %s" % (self.path, self.line, self.msg) | |
| 28 else: | |
| 29 return "%s:%d syntax error" % (self.path, self.line) | |
| 30 | 27 |
| 31 | 28 |
| 32 class Database(object): | 29 class Database(object): |
| 33 """A database of OWNERS files for a repository. | 30 """A database of OWNERS files for a repository. |
| 34 | 31 |
| 35 This class allows you to find a suggested set of reviewers for a list | 32 This class allows you to find a suggested set of reviewers for a list |
| 36 of changed files, and see if a list of changed files is covered by a | 33 of changed files, and see if a list of changed files is covered by a |
| 37 list of reviewers.""" | 34 list of reviewers.""" |
| 38 | 35 |
| 39 def __init__(self, root, fopen, os_path): | 36 def __init__(self, root, fopen, os_path): |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 | 131 |
| 135 lineno = 0 | 132 lineno = 0 |
| 136 for line in self.fopen(owners_path): | 133 for line in self.fopen(owners_path): |
| 137 lineno += 1 | 134 lineno += 1 |
| 138 line = line.strip() | 135 line = line.strip() |
| 139 if line.startswith('#'): | 136 if line.startswith('#'): |
| 140 continue | 137 continue |
| 141 if line == 'set noparent': | 138 if line == 'set noparent': |
| 142 self.stop_looking.add(dirpath) | 139 self.stop_looking.add(dirpath) |
| 143 continue | 140 continue |
| 141 if line.startswith('set '): |
| 142 raise SyntaxErrorInOwnersFile(owners_path, lineno, |
| 143 'unknown option: "%s"' % line[4:].strip()) |
| 144 if self.email_regexp.match(line) or line == EVERYONE: | 144 if self.email_regexp.match(line) or line == EVERYONE: |
| 145 self.owned_by.setdefault(line, set()).add(dirpath) | 145 self.owned_by.setdefault(line, set()).add(dirpath) |
| 146 self.owners_for.setdefault(dirpath, set()).add(line) | 146 self.owners_for.setdefault(dirpath, set()).add(line) |
| 147 continue | 147 continue |
| 148 raise SyntaxErrorInOwnersFile(owners_path, lineno, line) | 148 raise SyntaxErrorInOwnersFile(owners_path, lineno, |
| 149 ('line is not a comment, a "set" directive, ' |
| 150 'or an email address: "%s"' % line)) |
| 149 | 151 |
| 150 def _covering_set_of_owners_for(self, files): | 152 def _covering_set_of_owners_for(self, files): |
| 151 # TODO(dpranke): implement the greedy algorithm for covering sets, and | 153 # TODO(dpranke): implement the greedy algorithm for covering sets, and |
| 152 # consider returning multiple options in case there are several equally | 154 # consider returning multiple options in case there are several equally |
| 153 # short combinations of owners. | 155 # short combinations of owners. |
| 154 every_owner = set() | 156 every_owner = set() |
| 155 for f in files: | 157 for f in files: |
| 156 dirname = self.os_path.dirname(f) | 158 dirname = self.os_path.dirname(f) |
| 157 while dirname in self.owners_for: | 159 while dirname in self.owners_for: |
| 158 every_owner |= self.owners_for[dirname] | 160 every_owner |= self.owners_for[dirname] |
| 159 if self._stop_looking(dirname): | 161 if self._stop_looking(dirname): |
| 160 break | 162 break |
| 161 dirname = self.os_path.dirname(dirname) | 163 dirname = self.os_path.dirname(dirname) |
| 162 return every_owner | 164 return every_owner |
| OLD | NEW |