Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1811)

Side by Side Diff: owners.py

Issue 6677090: Fix the owners implementation to validate method inputs. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools/
Patch Set: '' Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/owners_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 collections
7 import re 8 import re
8 9
9 10
10 # If this is present by itself on a line, this means that everyone can review. 11 # If this is present by itself on a line, this means that everyone can review.
11 EVERYONE = '*' 12 EVERYONE = '*'
12 13
13 14
14 # Recognizes 'X@Y' email addresses. Very simplistic. 15 # Recognizes 'X@Y' email addresses. Very simplistic.
15 BASIC_EMAIL_REGEXP = r'^[\w\-\+\%\.]+\@[\w\-\+\%\.]+$' 16 BASIC_EMAIL_REGEXP = r'^[\w\-\+\%\.]+\@[\w\-\+\%\.]+$'
16 17
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 self.owned_by = {EVERYONE: set()} 52 self.owned_by = {EVERYONE: set()}
52 53
53 # Mapping of paths to authorized owners. 54 # Mapping of paths to authorized owners.
54 self.owners_for = {} 55 self.owners_for = {}
55 56
56 # Set of paths that stop us from looking above them for owners. 57 # Set of paths that stop us from looking above them for owners.
57 # (This is implicitly true for the root directory). 58 # (This is implicitly true for the root directory).
58 self.stop_looking = set(['']) 59 self.stop_looking = set([''])
59 60
60 def reviewers_for(self, files): 61 def reviewers_for(self, files):
61 """Returns a suggested set of reviewers that will cover the set of files. 62 """Returns a suggested set of reviewers that will cover the files.
62 63
63 files is a set of paths relative to (and under) self.root.""" 64 files is a sequence of paths relative to (and under) self.root."""
64 self._check_paths(files) 65 self._check_paths(files)
65 self._load_data_needed_for(files) 66 self._load_data_needed_for(files)
66 return self._covering_set_of_owners_for(files) 67 return self._covering_set_of_owners_for(files)
67 68
68 def files_are_covered_by(self, files, reviewers): 69 def files_are_covered_by(self, files, reviewers):
69 """Returns whether every file is owned by at least one reviewer.""" 70 """Returns whether every file is owned by at least one reviewer."""
70 return not self.files_not_covered_by(files, reviewers) 71 return not self.files_not_covered_by(files, reviewers)
71 72
72 def files_not_covered_by(self, files, reviewers): 73 def files_not_covered_by(self, files, reviewers):
73 """Returns the set of files that are not owned by at least one reviewer.""" 74 """Returns the set of files that are not owned by at least one reviewer.
75
76 Args:
77 files is a sequence of paths relative to (and under) self.root.
78 reviewers is a sequence of strings matching self.email_regexp."""
74 self._check_paths(files) 79 self._check_paths(files)
75 self._check_reviewers(reviewers) 80 self._check_reviewers(reviewers)
76 if not reviewers: 81 if not reviewers:
77 return files 82 return files
78 83
79 self._load_data_needed_for(files) 84 self._load_data_needed_for(files)
80 files_by_dir = self._files_by_dir(files) 85 files_by_dir = self._files_by_dir(files)
81 covered_dirs = self._dirs_covered_by(reviewers) 86 covered_dirs = self._dirs_covered_by(reviewers)
82 uncovered_files = [] 87 uncovered_files = []
83 for d, files_in_d in files_by_dir.iteritems(): 88 for d, files_in_d in files_by_dir.iteritems():
84 if not self._is_dir_covered_by(d, covered_dirs): 89 if not self._is_dir_covered_by(d, covered_dirs):
85 uncovered_files.extend(files_in_d) 90 uncovered_files.extend(files_in_d)
86 return set(uncovered_files) 91 return set(uncovered_files)
87 92
93 def _check_collection(self, obj):
M-A Ruel 2011/03/17 01:27:47 I prefer this function to not be a member function
94 assert (isinstance(obj, collections.Iterable) and
M-A Ruel 2011/03/17 01:27:47 assert (isinstance(obj, (collections.Iterable, col
95 isinstance(obj, collections.Sized) and
96 not isinstance(obj, basestring))
97
88 def _check_paths(self, files): 98 def _check_paths(self, files):
89 def _is_under(f, pfx): 99 def _is_under(f, pfx):
90 return self.os_path.abspath(self.os_path.join(pfx, f)).startswith(pfx) 100 return self.os_path.abspath(self.os_path.join(pfx, f)).startswith(pfx)
101 self._check_collection(files)
91 assert all(_is_under(f, self.os_path.abspath(self.root)) for f in files) 102 assert all(_is_under(f, self.os_path.abspath(self.root)) for f in files)
92 103
93 def _check_reviewers(self, reviewers): 104 def _check_reviewers(self, reviewers):
94 """Verifies each reviewer is a valid email address.""" 105 self._check_collection(reviewers)
95 assert all(self.email_regexp.match(r) for r in reviewers) 106 assert all(self.email_regexp.match(r) for r in reviewers)
96 107
97 def _files_by_dir(self, files): 108 def _files_by_dir(self, files):
98 dirs = {} 109 dirs = {}
99 for f in files: 110 for f in files:
100 dirs.setdefault(self.os_path.dirname(f), []).append(f) 111 dirs.setdefault(self.os_path.dirname(f), []).append(f)
101 return dirs 112 return dirs
102 113
103 def _dirs_covered_by(self, reviewers): 114 def _dirs_covered_by(self, reviewers):
104 dirs = self.owned_by[EVERYONE] 115 dirs = self.owned_by[EVERYONE]
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 # short combinations of owners. 165 # short combinations of owners.
155 every_owner = set() 166 every_owner = set()
156 for f in files: 167 for f in files:
157 dirname = self.os_path.dirname(f) 168 dirname = self.os_path.dirname(f)
158 while dirname in self.owners_for: 169 while dirname in self.owners_for:
159 every_owner |= self.owners_for[dirname] 170 every_owner |= self.owners_for[dirname]
160 if self._stop_looking(dirname): 171 if self._stop_looking(dirname):
161 break 172 break
162 dirname = self.os_path.dirname(dirname) 173 dirname = self.os_path.dirname(dirname)
163 return every_owner 174 return every_owner
OLDNEW
« no previous file with comments | « no previous file | tests/owners_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698