blob: 9d38faf49f8fc8cd1979a05e7a0c487b425fb217 [file] [log] [blame]
[email protected]b2ab4942009-06-11 21:39:191#!/usr/bin/python
2# Copyright (c) 2009 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Watchlists
7
8Watchlists is a mechanism that allow a developer (a "watcher") to watch over
9portions of code that he is interested in. A "watcher" will be cc-ed to
10changes that modify that portion of code, thereby giving him an opportunity
11to make comments on codereview.chromium.org even before the change is
12committed.
13Refer: http://dev.chromium.org/developers/contributing-code/watchlists
14
15When invoked directly from the base of a repository, this script lists out
16the watchers for files given on the command line. This is useful to verify
17changes to WATCHLISTS files.
18"""
19
20import logging
21import os
22import re
23import sys
24
25
26class Watchlists(object):
27 """Manage Watchlists.
28
29 This class provides mechanism to load watchlists for a repo and identify
30 watchers.
31 Usage:
32 wl = Watchlists("/path/to/repo/root")
33 watchers = wl.GetWatchersForPaths(["/path/to/file1",
34 "/path/to/file2",])
35 """
36
37 _RULES = "WATCHLISTS"
38 _RULES_FILENAME = _RULES
39 _repo_root = None
40 _defns = {} # Definitions
41 _watchlists = {} # name to email mapping
42
43 def __init__(self, repo_root):
44 self._repo_root = repo_root
45 self._LoadWatchlistRules()
46
47 def _GetRulesFilePath(self):
[email protected]b82e4092009-06-18 14:24:0848 """Returns path to WATCHLISTS file."""
[email protected]b2ab4942009-06-11 21:39:1949 return os.path.join(self._repo_root, self._RULES_FILENAME)
50
51 def _HasWatchlistsFile(self):
52 """Determine if watchlists are available for this repo."""
53 return os.path.exists(self._GetRulesFilePath())
54
[email protected]b82e4092009-06-18 14:24:0855 def _ContentsOfWatchlistsFile(self):
56 """Read the WATCHLISTS file and return its contents."""
57 try:
58 watchlists_file = open(self._GetRulesFilePath())
59 contents = watchlists_file.read()
60 watchlists_file.close()
61 return contents
62 except IOError, e:
63 logging.error("Cannot read %s: %s" % (self._GetRulesFilePath(), e))
64 return ''
65
[email protected]b2ab4942009-06-11 21:39:1966 def _LoadWatchlistRules(self):
[email protected]b82e4092009-06-18 14:24:0867 """Load watchlists from WATCHLISTS file. Does nothing if not present."""
[email protected]b2ab4942009-06-11 21:39:1968 if not self._HasWatchlistsFile():
69 return
[email protected]b2ab4942009-06-11 21:39:1970
[email protected]b82e4092009-06-18 14:24:0871 contents = self._ContentsOfWatchlistsFile()
[email protected]b2ab4942009-06-11 21:39:1972 watchlists_data = None
73 try:
74 watchlists_data = eval(contents, {'__builtins__': None}, None)
75 except SyntaxError, e:
76 logging.error("Cannot parse %s. %s" % (self._GetRulesFilePath(), e))
77 return
78
79 defns = watchlists_data.get("WATCHLIST_DEFINITIONS")
80 if not defns:
81 logging.error("WATCHLIST_DEFINITIONS not defined in %s" %
82 self._GetRulesFilePath())
83 return
84 watchlists = watchlists_data.get("WATCHLISTS")
85 if not watchlists:
86 logging.error("WATCHLISTS not defined in %s" % self._GetRulesFilePath())
87 return
88 self._defns = defns
89 self._watchlists = watchlists
90
91 # Verify that all watchlist names are defined
92 for name in watchlists:
93 if name not in defns:
94 logging.error("%s not defined in %s" % (name, self._GetRulesFilePath()))
95
96 def GetWatchersForPaths(self, paths):
97 """Fetch the list of watchers for |paths|
98
99 Args:
100 paths: [path1, path2, ...]
101
102 Returns:
103 [[email protected], [email protected], ...]
104 """
105 watchers = set() # A set, to avoid duplicates
106 for path in paths:
[email protected]76256af2009-06-18 22:52:12107 path = path.replace(os.sep, '/')
[email protected]b2ab4942009-06-11 21:39:19108 for name, rule in self._defns.iteritems():
109 if name not in self._watchlists: continue
110 rex_str = rule.get('filepath')
111 if not rex_str: continue
112 if re.search(rex_str, path):
113 map(watchers.add, self._watchlists[name])
114 return list(watchers)
115
116
117def main(argv):
118 # Confirm that watchlists can be parsed and spew out the watchers
119 if len(argv) < 2:
120 print "Usage (from the base of repo):"
121 print " %s [file-1] [file-2] ...." % argv[0]
122 return 1
123 wl = Watchlists(os.getcwd())
124 watchers = wl.GetWatchersForPaths(argv[1:])
125 print watchers
126
127
128if __name__ == '__main__':
129 main(sys.argv)