#!/usr/bin/env python """Script to locate email addresses in the CVS logs.""" __version__ = '$Revision: 1.2 $' import os import re import sys import UserDict import cvsinfo class Acknowledgements(UserDict.UserDict): def add(self, email, name, path): d = self.data d.setdefault(email, {})[path] = name def open_cvs_log(info, paths=None): cvsroot = info.get_cvsroot() cmd = "cvs -q -d%s log " % cvsroot if paths: cmd += " ".join(paths) return os.popen(cmd, "r") email_rx = re.compile("<([a-z][-a-z0-9._]*@[-a-z0-9.]+)>", re.IGNORECASE) def find_acks(f, acks): prev = '' filename = None MAGIC_WORDS = ('van', 'von') while 1: line = f.readline() if not line: break if line.startswith("Working file: "): filename = line.split(None, 2)[2].strip() prev = line continue m = email_rx.search(line) if m: words = prev.split() + line[:m.start()].split() L = [] while words \ and (words[-1][0].isupper() or words[-1] in MAGIC_WORDS): L.insert(0, words.pop()) name = " ".join(L) email = m.group(1).lower() acks.add(email, name, filename) prev = line def load_cvs_log_acks(acks, args): repolist = cvsinfo.get_repository_list(args or [""]) for info, paths in repolist: print >>sys.stderr, "Repository:", info.get_cvsroot() f = open_cvs_log(info, paths) find_acks(f, acks) f.close() def load_tex_source_acks(acks, args): for path in args: path = path or os.curdir if os.path.isfile(path): read_acks_from_tex_file(acks, path) else: read_acks_from_tex_dir(acks, path) def read_acks_from_tex_file(acks, path): f = open(path) while 1: line = f.readline() if not line: break if line.startswith(r"\sectionauthor{"): line = line[len(r"\sectionauthor"):] name, line = extract_tex_group(line) email, line = extract_tex_group(line) acks.add(email, name, path) def read_acks_from_tex_dir(acks, path): stack = [path] while stack: p = stack.pop() for n in os.listdir(p): n = os.path.join(p, n) if os.path.isdir(n): stack.insert(0, n) elif os.path.normpath(n).endswith(".tex"): read_acks_from_tex_file(acks, n) def extract_tex_group(s): c = 0 for i in range(len(s)): if s[i] == '{': c += 1 elif s[i] == '}': c -= 1 if c == 0: return s[1:i], s[i+1:] def print_acks(acks): first = 1 for email, D in acks.items(): if first: first = 0 else: print L = D.items() L.sort() prefname = L[0][1] for file, name in L[1:]: if name != prefname: prefname = "" break if prefname: print prefname, "<%s>:" % email else: print email + ":" for file, name in L: if name == prefname: print " " + file else: print " %s (as %s)" % (file, name) def print_ack_names(acks): names = [] for email, D in acks.items(): L = D.items() L.sort() prefname = L[0][1] for file, name in L[1:]: prefname = prefname or name names.append(prefname or email) def f(s1, s2): s1 = s1.lower() s2 = s2.lower() return cmp((s1.split()[-1], s1), (s2.split()[-1], s2)) names.sort(f) for name in names: print name def main(): args = sys.argv[1:] acks = Acknowledgements() load_cvs_log_acks(acks, args) load_tex_source_acks(acks, args) print_ack_names(acks) if __name__ == "__main__": main()