blob: d35859bd50fad9b23f1b127974eef8fa906af6a9 [file] [log] [blame]
Fred Drake1654b432000-10-03 22:10:25 +00001#!/usr/bin/env python
2"""Script to locate email addresses in the CVS logs."""
3__version__ = '$Revision$'
4
5import os
6import re
7import sys
8import UserDict
9
10import fdrake.cvstools.info
11cvstools = fdrake.cvstools
12
13
14class Acknowledgements(UserDict.UserDict):
15 def add(self, email, name, path):
16 d = self.data
17 d.setdefault(email, {})[path] = name
18
19
20def open_cvs_log(info, paths=None):
21 cvsroot = info.get_cvsroot()
22 cmd = "cvs -q -d%s log " % cvsroot
23 if paths:
24 cmd += " ".join(paths)
25 return os.popen(cmd, "r")
26
27
28email_rx = re.compile("<([a-z][-a-z0-9._]*@[-a-z0-9.]+)>", re.IGNORECASE)
29
30def find_acks(f, acks):
31 prev = ''
32 filename = None
33 MAGIC_WORDS = ('van', 'von')
34 while 1:
35 line = f.readline()
36 if not line:
37 break
38 if line.startswith("Working file: "):
39 filename = line.split(None, 2)[2].strip()
40 prev = line
41 continue
42 m = email_rx.search(line)
43 if m:
44 words = prev.split() + line[:m.start()].split()
45 L = []
46 while words \
47 and (words[-1][0].isupper() or words[-1] in MAGIC_WORDS):
48 L.insert(0, words.pop())
49 name = " ".join(L)
50 email = m.group(1).lower()
51 acks.add(email, name, filename)
52 prev = line
53
54
55def load_cvs_log_acks(acks, args):
56 repolist = cvstools.info.get_repository_list(args or [""])
57 for info, paths in repolist:
58 print >>sys.stderr, "Repository:", info.get_cvsroot()
59 f = open_cvs_log(info, paths)
60 find_acks(f, acks)
61 f.close()
62
63
64def load_tex_source_acks(acks, args):
65 for path in args:
66 path = path or os.curdir
67 if os.path.isfile(path):
68 read_acks_from_tex_file(acks, path)
69 else:
70 read_acks_from_tex_dir(acks, path)
71
72
73def read_acks_from_tex_file(acks, path):
74 f = open(path)
75 while 1:
76 line = f.readline()
77 if not line:
78 break
79 if line.startswith(r"\sectionauthor{"):
80 line = line[len(r"\sectionauthor"):]
81 name, line = extract_tex_group(line)
82 email, line = extract_tex_group(line)
83 acks.add(email, name, path)
84
85
86def read_acks_from_tex_dir(acks, path):
87 stack = [path]
88 while stack:
89 p = stack.pop()
90 for n in os.listdir(p):
91 n = os.path.join(p, n)
92 if os.path.isdir(n):
93 stack.insert(0, n)
94 elif os.path.normpath(n).endswith(".tex"):
95 read_acks_from_tex_file(acks, n)
96
97
98def extract_tex_group(s):
99 c = 0
100 for i in range(len(s)):
101 if s[i] == '{':
102 c += 1
103 elif s[i] == '}':
104 c -= 1
105 if c == 0:
106 return s[1:i], s[i+1:]
107
108
109def print_acks(acks):
110 first = 1
111 for email, D in acks.items():
112 if first:
113 first = 0
114 else:
115 print
116 L = D.items()
117 L.sort()
118 prefname = L[0][1]
119 for file, name in L[1:]:
120 if name != prefname:
121 prefname = ""
122 break
123 if prefname:
124 print prefname, "<%s>:" % email
125 else:
126 print email + ":"
127 for file, name in L:
128 if name == prefname:
129 print " " + file
130 else:
131 print " %s (as %s)" % (file, name)
132
133
134def print_ack_names(acks):
135 names = []
136 for email, D in acks.items():
137 L = D.items()
138 L.sort()
139 prefname = L[0][1]
140 for file, name in L[1:]:
141 prefname = prefname or name
142 names.append(prefname or email)
143 def f(s1, s2):
144 s1 = s1.lower()
145 s2 = s2.lower()
146 return cmp((s1.split()[-1], s1),
147 (s2.split()[-1], s2))
148 names.sort(f)
149 for name in names:
150 print name
151
152
153def main():
154 args = sys.argv[1:]
155 acks = Acknowledgements()
156 load_cvs_log_acks(acks, args)
157 load_tex_source_acks(acks, args)
158 print_ack_names(acks)
159
160
161if __name__ == "__main__":
162 main()