Chromium Code Reviews| Index: owners.py |
| diff --git a/owners.py b/owners.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..921b21a7ba7996c07623294583c0cfbf0d7ef1bb |
| --- /dev/null |
| +++ b/owners.py |
| @@ -0,0 +1,98 @@ |
| +# Copyright (c) 2010 The Chromium Authors. All rights reserved. |
|
M-A Ruel
2011/02/24 16:25:57
2011
|
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| + |
| +"""A database of OWNERS files.""" |
| + |
| +import os |
| +import pdb |
|
M-A Ruel
2011/02/24 16:25:57
remove
|
| + |
| + |
| +class Assertion(AssertionError): |
| + pass |
| + |
| +class Database(object): |
| + def __init__(self, root, all_owners=None, |
|
M-A Ruel
2011/02/24 16:25:57
Either all align one per line or all packed at 80
|
| + open=file, |
| + os_path=os.path): |
| + """Initialize the database of owners for a repository. |
|
M-A Ruel
2011/02/24 16:25:57
Initializes
|
| + |
| + Args: |
| + root: the path to the root of the Repository |
| + all_owners: the list of every owner in the system |
| + open: function callback to open a text file for reading |
| + os_path: module/object callback with fields for 'exists', |
| + 'dirname', and 'join' |
| + """ |
| + self.root = root |
| + self.all_owners = all_owners or set() |
| + self.open = open |
| + self.os_path = os_path |
| + |
| + # Mapping of files to authorized owners. |
| + self.files_owned_by = {} |
| + |
| + # Mapping of owners to the files they own. |
| + self.owners_for = {} |
| + |
| + # In-memory cached map of files to their OWNERS files. |
| + self.owners_file_for = {} |
| + |
| + # In-memory cache of OWNERS files and their contents |
| + self.owners_files = {} |
| + |
| + def OwnersFor(self, files): |
| + """Returns a list of sets of reviewers that will cover the set of files. |
| + |
| + The set of files are paths relative to (and under) self.root.""" |
| + self._LoadDataNeededFor(files) |
| + return self._FindCoveringSets(files) |
| + |
| + def AreCovered(self, files, reviewers): |
| + return len(self.not_covered(files, reviewers)) == 0 |
|
M-A Ruel
2011/02/24 16:25:57
return not self.not_covered(files, reviewers)
|
| + |
| + def FilesNotCoveredBy(self, files, reviewers): |
| + covered_files = set() |
| + for reviewer in reviewers: |
| + covered_files = covered_files.union(self.files_owned_by(reviewer)) |
| + return files.difference(covered_files) |
| + |
| + def _LoadDataNeededFor(self, files): |
| + for f in files: |
| + self._LoadOwnersFor(f) |
| + |
| + def _LoadOwnersFor(self, f): |
| + if f not in self.owners_for: |
| + owner_file = self._FindOwnersFileFor(f) |
| + self.owners_file_for[f] = owner_file |
| + self._ReadOwnersFile(owner_file, f) |
| + |
| + def _FindOwnersFileFor(self, f): |
| + # This is really a "do ... until dirname = ''" |
| + dirname = self.os_path.dirname(f) |
| + while dirname: |
| + owner_path = self.os_path.join(dirname, 'OWNERS') |
| + if self.os_path.exists(owner_path): |
| + return owner_path |
| + dirname = self.os_path.dirname(dirname) |
| + owner_path = self.os_path.join(dirname, 'OWNERS') |
| + if self.os_path.exists(owner_path): |
| + return owner_path |
| + |
| + raise Assertion('No OWNERS file found for %s' % f) |
|
M-A Ruel
2011/02/24 16:25:57
Is this really an exceptional event? I think it sh
|
| + |
| + def _ReadOwnersFile(self, owner_file, affected_file): |
| + owners_for = self.owners_for.setdefault(affected_file, set()) |
| + for owner in self.open(owner_file).readlines(): |
|
M-A Ruel
2011/02/24 16:25:57
.readlines() is implied.
|
| + owner = owner.strip() |
| + self.files_owned_by.setdefault(owner, set()).add(affected_file) |
| + owners_for.add(owner) |
| + |
| + def _FindCoveringSets(self, files): |
| + # TODO(dpranke): implement the greedy algorithm for covering sets. |
| + # For now we return the list of every owner that touches at least |
| + # one file in the set. |
| + all_owners = set() |
| + for f in files: |
| + all_owners = all_owners.union(self.owners_for[f]) |
| + return [all_owners] |
|
M-A Ruel
2011/02/24 16:25:57
Did you mean:
return list(all_owners)
?
|