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