blob: a0a127ead55f113da2730984669d1296eb9a0507 [file] [log] [blame]
nirnimesh@chromium.orgb2ab4942009-06-11 21:39:19 +00001#!/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):
48 return os.path.join(self._repo_root, self._RULES_FILENAME)
49
50 def _HasWatchlistsFile(self):
51 """Determine if watchlists are available for this repo."""
52 return os.path.exists(self._GetRulesFilePath())
53
54 def _LoadWatchlistRules(self):
55 if not self._HasWatchlistsFile():
56 return
57 watchlists_file = open(self._GetRulesFilePath())
58 contents = watchlists_file.read()
59 watchlists_file.close()
60
61 watchlists_data = None
62 try:
63 watchlists_data = eval(contents, {'__builtins__': None}, None)
64 except SyntaxError, e:
65 logging.error("Cannot parse %s. %s" % (self._GetRulesFilePath(), e))
66 return
67
68 defns = watchlists_data.get("WATCHLIST_DEFINITIONS")
69 if not defns:
70 logging.error("WATCHLIST_DEFINITIONS not defined in %s" %
71 self._GetRulesFilePath())
72 return
73 watchlists = watchlists_data.get("WATCHLISTS")
74 if not watchlists:
75 logging.error("WATCHLISTS not defined in %s" % self._GetRulesFilePath())
76 return
77 self._defns = defns
78 self._watchlists = watchlists
79
80 # Verify that all watchlist names are defined
81 for name in watchlists:
82 if name not in defns:
83 logging.error("%s not defined in %s" % (name, self._GetRulesFilePath()))
84
85 def GetWatchersForPaths(self, paths):
86 """Fetch the list of watchers for |paths|
87
88 Args:
89 paths: [path1, path2, ...]
90
91 Returns:
92 [u1@chromium.org, u2@gmail.com, ...]
93 """
94 watchers = set() # A set, to avoid duplicates
95 for path in paths:
96 for name, rule in self._defns.iteritems():
97 if name not in self._watchlists: continue
98 rex_str = rule.get('filepath')
99 if not rex_str: continue
100 if re.search(rex_str, path):
101 map(watchers.add, self._watchlists[name])
102 return list(watchers)
103
104
105def main(argv):
106 # Confirm that watchlists can be parsed and spew out the watchers
107 if len(argv) < 2:
108 print "Usage (from the base of repo):"
109 print " %s [file-1] [file-2] ...." % argv[0]
110 return 1
111 wl = Watchlists(os.getcwd())
112 watchers = wl.GetWatchersForPaths(argv[1:])
113 print watchers
114
115
116if __name__ == '__main__':
117 main(sys.argv)