OLD | NEW |
---|---|
(Empty) | |
1 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
M-A Ruel
2011/02/25 20:41:54
2011
| |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 """A database of OWNERS files.""" | |
6 | |
7 class Assertion(AssertionError): | |
8 pass | |
9 | |
10 class Database(object): | |
11 def __init__(self, root, fopen, os_path): | |
12 """Initializes the database of owners for a repository. | |
M-A Ruel
2011/02/25 20:41:54
Personal nit: constructor docstring are usually us
| |
13 | |
14 Args: | |
15 root: the path to the root of the Repository | |
16 all_owners: the list of every owner in the system | |
17 open: function callback to open a text file for reading | |
18 os_path: module/object callback with fields for 'exists', | |
19 'dirname', and 'join' | |
20 """ | |
21 self.root = root | |
22 self.fopen = fopen | |
23 self.os_path = os_path | |
24 | |
25 # Mapping of files to authorized owners. | |
26 self.files_owned_by = {} | |
27 | |
28 # Mapping of owners to the files they own. | |
29 self.owners_for = {} | |
30 | |
31 # In-memory cached map of files to their OWNERS files. | |
32 self.owners_file_for = {} | |
33 | |
34 # In-memory cache of OWNERS files and their contents | |
35 self.owners_files = {} | |
36 | |
37 def OwnersFor(self, files): | |
38 """Returns a sets of reviewers that will cover the set of files. | |
39 | |
40 The set of files are paths relative to (and under) self.root.""" | |
41 self._LoadDataNeededFor(files) | |
42 return self._CoveringSetOfOwnersFor(files) | |
43 | |
44 def FilesAreCoveredBy(self, files, reviewers): | |
45 return not self.FilesNotCoveredBy(files, reviewers) | |
46 | |
47 def FilesNotCoveredBy(self, files, reviewers): | |
48 covered_files = set() | |
49 for reviewer in reviewers: | |
50 covered_files = covered_files.union(self.files_owned_by[reviewer]) | |
51 return files.difference(covered_files) | |
52 | |
53 def _LoadDataNeededFor(self, files): | |
54 for f in files: | |
55 self._LoadOwnersFor(f) | |
56 | |
57 def _LoadOwnersFor(self, f): | |
M-A Ruel
2011/02/25 20:41:54
Is this function really needed? It's called only o
| |
58 if f not in self.owners_for: | |
59 owner_file = self._FindOwnersFileFor(f) | |
60 self.owners_file_for[f] = owner_file | |
61 self._ReadOwnersFile(owner_file, f) | |
62 | |
63 def _FindOwnersFileFor(self, f): | |
64 # This is really a "do ... until dirname = ''" | |
65 dirname = self.os_path.dirname(f) | |
66 while dirname: | |
67 owner_path = self.os_path.join(dirname, 'OWNERS') | |
68 if self.os_path.exists(owner_path): | |
69 return owner_path | |
70 dirname = self.os_path.dirname(dirname) | |
71 owner_path = self.os_path.join(dirname, 'OWNERS') | |
72 if self.os_path.exists(owner_path): | |
73 return owner_path | |
74 raise Assertion('No OWNERS file found for %s' % f) | |
75 | |
76 def _ReadOwnersFile(self, owner_file, affected_file): | |
77 owners_for = self.owners_for.setdefault(affected_file, set()) | |
78 for owner in self.fopen(owner_file): | |
79 owner = owner.strip() | |
80 self.files_owned_by.setdefault(owner, set()).add(affected_file) | |
81 owners_for.add(owner) | |
82 | |
83 def _CoveringSetOfOwnersFor(self, files): | |
84 # TODO(dpranke): implement the greedy algorithm for covering sets, and | |
85 # consider returning multiple options in case there are several equally | |
86 # short combinations of owners. | |
87 every_owner = set() | |
88 for f in files: | |
89 every_owner = every_owner.union(self.owners_for[f]) | |
90 return every_owner | |
OLD | NEW |