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

Side by Side Diff: owners.py

Issue 9621012: Show a list of directories missing OWNER reviewers on upload, and show directories rather than file… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools/
Patch Set: Created 8 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 | presubmit_canned_checks.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 collections
8 import re 8 import re
9 9
10 10
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
68 self.stop_looking = set(['']) 68 self.stop_looking = set([''])
69 69
70 def reviewers_for(self, files): 70 def reviewers_for(self, files):
71 """Returns a suggested set of reviewers that will cover the files. 71 """Returns a suggested set of reviewers that will cover the files.
72 72
73 files is a sequence of paths relative to (and under) self.root.""" 73 files is a sequence of paths relative to (and under) self.root."""
74 self._check_paths(files) 74 self._check_paths(files)
75 self._load_data_needed_for(files) 75 self._load_data_needed_for(files)
76 return self._covering_set_of_owners_for(files) 76 return self._covering_set_of_owners_for(files)
77 77
78 def files_are_covered_by(self, files, reviewers): 78 def directories_not_covered_by(self, files, reviewers):
79 """Returns whether every file is owned by at least one reviewer.""" 79 """Returns the set of directories that are not owned by a reviewer.
80 return not self.files_not_covered_by(files, reviewers)
81 80
82 def files_not_covered_by(self, files, reviewers): 81 Determines which of the given files are not owned by at least one of the
83 """Returns the set of files that are not owned by at least one reviewer. 82 reviewers, then returns a set containing the applicable enclosing
83 directories, i.e. the ones upward from the files that have OWNERS files.
84 84
85 Args: 85 Args:
86 files is a sequence of paths relative to (and under) self.root. 86 files is a sequence of paths relative to (and under) self.root.
87 reviewers is a sequence of strings matching self.email_regexp.""" 87 reviewers is a sequence of strings matching self.email_regexp.
88 """
88 self._check_paths(files) 89 self._check_paths(files)
89 self._check_reviewers(reviewers) 90 self._check_reviewers(reviewers)
90 if not reviewers: 91 self._load_data_needed_for(files)
91 return files
92 92
93 self._load_data_needed_for(files) 93 dirs = set([self.os_path.dirname(f) for f in files])
94 files_by_dir = self._files_by_dir(files)
95 covered_dirs = self._dirs_covered_by(reviewers) 94 covered_dirs = self._dirs_covered_by(reviewers)
96 uncovered_files = [] 95 uncovered_dirs = [self._enclosing_dir_with_owners(d) for d in dirs
97 for d, files_in_d in files_by_dir.iteritems(): 96 if not self._is_dir_covered_by(d, covered_dirs)]
98 if not self._is_dir_covered_by(d, covered_dirs): 97
99 uncovered_files.extend(files_in_d) 98 return set(uncovered_dirs)
100 return set(uncovered_files)
101 99
102 def _check_paths(self, files): 100 def _check_paths(self, files):
103 def _is_under(f, pfx): 101 def _is_under(f, pfx):
104 return self.os_path.abspath(self.os_path.join(pfx, f)).startswith(pfx) 102 return self.os_path.abspath(self.os_path.join(pfx, f)).startswith(pfx)
105 _assert_is_collection(files) 103 _assert_is_collection(files)
106 assert all(_is_under(f, self.os_path.abspath(self.root)) for f in files) 104 assert all(_is_under(f, self.os_path.abspath(self.root)) for f in files)
107 105
108 def _check_reviewers(self, reviewers): 106 def _check_reviewers(self, reviewers):
109 _assert_is_collection(reviewers) 107 _assert_is_collection(reviewers)
110 assert all(self.email_regexp.match(r) for r in reviewers) 108 assert all(self.email_regexp.match(r) for r in reviewers)
111 109
112 def _files_by_dir(self, files):
113 dirs = {}
114 for f in files:
115 dirs.setdefault(self.os_path.dirname(f), []).append(f)
116 return dirs
117
118 def _dirs_covered_by(self, reviewers): 110 def _dirs_covered_by(self, reviewers):
119 dirs = self.owned_by[EVERYONE] 111 dirs = self.owned_by[EVERYONE]
120 for r in reviewers: 112 for r in reviewers:
121 dirs = dirs | self.owned_by.get(r, set()) 113 dirs = dirs | self.owned_by.get(r, set())
122 return dirs 114 return dirs
123 115
124 def _stop_looking(self, dirname): 116 def _stop_looking(self, dirname):
125 return dirname in self.stop_looking 117 return dirname in self.stop_looking
126 118
127 def _is_dir_covered_by(self, dirname, covered_dirs): 119 def _is_dir_covered_by(self, dirname, covered_dirs):
128 while not dirname in covered_dirs and not self._stop_looking(dirname): 120 while not dirname in covered_dirs and not self._stop_looking(dirname):
129 dirname = self.os_path.dirname(dirname) 121 dirname = self.os_path.dirname(dirname)
130 return dirname in covered_dirs 122 return dirname in covered_dirs
131 123
124 def _enclosing_dir_with_owners(self, directory):
125 """Returns the innermost enclosing directory that has an OWNERS file."""
126 dirpath = directory
127 while not dirpath in self.owners_for:
128 if self._stop_looking(dirpath):
129 break
130 dirpath = self.os_path.dirname(dirpath)
131 return dirpath
132
132 def _load_data_needed_for(self, files): 133 def _load_data_needed_for(self, files):
133 for f in files: 134 for f in files:
134 dirpath = self.os_path.dirname(f) 135 dirpath = self.os_path.dirname(f)
135 while not dirpath in self.owners_for: 136 while not dirpath in self.owners_for:
136 self._read_owners_in_dir(dirpath) 137 self._read_owners_in_dir(dirpath)
137 if self._stop_looking(dirpath): 138 if self._stop_looking(dirpath):
138 break 139 break
139 dirpath = self.os_path.dirname(dirpath) 140 dirpath = self.os_path.dirname(dirpath)
140 141
141 def _read_owners_in_dir(self, dirpath): 142 def _read_owners_in_dir(self, dirpath):
(...skipping 27 matching lines...) Expand all
169 # short combinations of owners. 170 # short combinations of owners.
170 every_owner = set() 171 every_owner = set()
171 for f in files: 172 for f in files:
172 dirname = self.os_path.dirname(f) 173 dirname = self.os_path.dirname(f)
173 while dirname in self.owners_for: 174 while dirname in self.owners_for:
174 every_owner |= self.owners_for[dirname] 175 every_owner |= self.owners_for[dirname]
175 if self._stop_looking(dirname): 176 if self._stop_looking(dirname):
176 break 177 break
177 dirname = self.os_path.dirname(dirname) 178 dirname = self.os_path.dirname(dirname)
178 return every_owner 179 return every_owner
OLDNEW
« no previous file with comments | « no previous file | presubmit_canned_checks.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698