Chromium Code Reviews| Index: owners.py |
| diff --git a/owners.py b/owners.py |
| index cc667beea3c575f527470d9bd25269b4e95c6bae..9f0b58b077063a49e9c7d024e72716ca75bcd6a7 100644 |
| --- a/owners.py |
| +++ b/owners.py |
| @@ -78,7 +78,7 @@ class SyntaxErrorInOwnersFile(Exception): |
| self.msg = msg |
| def __str__(self): |
| - return "%s:%d syntax error: %s" % (self.path, self.lineno, self.msg) |
| + return '%s:%d syntax error: %s' % (self.path, self.lineno, self.msg) |
| class Database(object): |
| @@ -111,6 +111,9 @@ class Database(object): |
| # Mapping of paths to authorized owners. |
| self.owners_for = {} |
| + # Mapping reviewers to the preceding comment per file in the OWNERS files. |
| + self.comments = {} |
| + |
| # Set of paths that stop us from looking above them for owners. |
| # (This is implicitly true for the root directory). |
| self.stop_looking = set(['']) |
| @@ -122,7 +125,7 @@ class Database(object): |
| If author is nonempty, we ensure it is not included in the set returned |
| in order avoid suggesting the author as a reviewer for their own changes.""" |
| self._check_paths(files) |
| - self._load_data_needed_for(files) |
| + self.load_data_needed_for(files) |
| suggested_owners = self._covering_set_of_owners_for(files, author) |
| if EVERYONE in suggested_owners: |
| if len(suggested_owners) > 1: |
| @@ -140,7 +143,7 @@ class Database(object): |
| """ |
| self._check_paths(files) |
| self._check_reviewers(reviewers) |
| - self._load_data_needed_for(files) |
| + self.load_data_needed_for(files) |
| covered_objs = self._objs_covered_by(reviewers) |
| uncovered_files = [f for f in files |
| @@ -182,7 +185,7 @@ class Database(object): |
| dirpath = self.os_path.dirname(dirpath) |
| return dirpath |
| - def _load_data_needed_for(self, files): |
| + def load_data_needed_for(self, files): |
| for f in files: |
| dirpath = self.os_path.dirname(f) |
| while not dirpath in self.owners_for: |
| @@ -195,18 +198,27 @@ class Database(object): |
| owners_path = self.os_path.join(self.root, dirpath, 'OWNERS') |
| if not self.os_path.exists(owners_path): |
| return |
| - |
| + comment = [] |
| + in_comment = False |
| lineno = 0 |
| for line in self.fopen(owners_path): |
| lineno += 1 |
| line = line.strip() |
| - if line.startswith('#') or line == '': |
| + if line.startswith('#'): |
| + if not in_comment: |
| + comment = [] |
|
Dirk Pranke
2013/07/30 22:01:00
Can you just move "comment = []" next to line 215
Bei Zhang
2013/08/12 22:43:12
No, you can't. That will prevent comment sharing.
|
| + comment.append(line[1:].strip()) |
| + in_comment = True |
| continue |
| + if line == '': |
| + continue |
| + in_comment = False |
| + |
| if line == 'set noparent': |
| self.stop_looking.add(dirpath) |
| continue |
| - m = re.match("per-file (.+)=(.+)", line) |
| + m = re.match('per-file (.+)=(.+)', line) |
| if m: |
| glob_string = m.group(1).strip() |
| directive = m.group(2).strip() |
| @@ -217,20 +229,24 @@ class Database(object): |
| line) |
| baselines = self.glob(full_glob_string) |
| for baseline in (self.os_path.relpath(b, self.root) for b in baselines): |
| - self._add_entry(baseline, directive, "per-file line", |
| - owners_path, lineno) |
| + self._add_entry(baseline, directive, 'per-file line', |
| + owners_path, lineno, ' '.join(comment)) |
|
Dirk Pranke
2013/07/30 22:01:00
Do you really want to join with ' ' and not '\n' ?
Bei Zhang
2013/08/12 22:43:12
Good idea. So we can wrap exactly as was in OWNERS
|
| continue |
| if line.startswith('set '): |
| raise SyntaxErrorInOwnersFile(owners_path, lineno, |
| 'unknown option: "%s"' % line[4:].strip()) |
| - self._add_entry(dirpath, line, "line", owners_path, lineno) |
| + self._add_entry(dirpath, line, 'line', owners_path, lineno, |
| + ' '.join(comment)) |
| - def _add_entry(self, path, directive, line_type, owners_path, lineno): |
| - if directive == "set noparent": |
| + def _add_entry(self, path, directive, |
| + line_type, owners_path, lineno, comment): |
| + if directive == 'set noparent': |
| self.stop_looking.add(path) |
| elif self.email_regexp.match(directive) or directive == EVERYONE: |
| + self.comments.setdefault(directive, {}) |
| + self.comments[directive][path] = comment |
| self.owned_by.setdefault(directive, set()).add(path) |
| self.owners_for.setdefault(path, set()).add(directive) |
| else: |
| @@ -287,13 +303,13 @@ class Database(object): |
| if dirname in dirs: |
| total_distance += distance |
| num_directories_owned += 1 |
| - if num_directories_owned: |
| - total_costs_by_owner[owner] = (total_distance / |
| - pow(num_directories_owned, 1.75)) |
| + if num_directories_owned: |
| + total_costs_by_owner[owner] = (total_distance / |
| + pow(num_directories_owned, 1.75)) |
|
Dirk Pranke
2013/07/30 22:01:00
Is this change intentional? I.e., did you find a b
Bei Zhang
2013/08/12 22:43:12
Yes this is just an optimization.
On 2013/07/30 2
|
| # Return the lowest cost owner. In the case of a tie, pick one randomly. |
| lowest_cost = min(total_costs_by_owner.itervalues()) |
| lowest_cost_owners = filter( |
| - lambda owner: total_costs_by_owner[owner] == lowest_cost, |
| - total_costs_by_owner) |
| + lambda owner: total_costs_by_owner[owner] == lowest_cost, |
| + total_costs_by_owner) |
| return random.Random().choice(lowest_cost_owners) |