diff -r ffa851df0825 -r 2fb8b9db1c86 symbian-qemu-0.9.1-12/python-2.6.1/Tools/scripts/logmerge.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/symbian-qemu-0.9.1-12/python-2.6.1/Tools/scripts/logmerge.py Fri Jul 31 15:01:17 2009 +0100 @@ -0,0 +1,185 @@ +#! /usr/bin/env python + +"""Consolidate a bunch of CVS or RCS logs read from stdin. + +Input should be the output of a CVS or RCS logging command, e.g. + + cvs log -rrelease14: + +which dumps all log messages from release1.4 upwards (assuming that +release 1.4 was tagged with tag 'release14'). Note the trailing +colon! + +This collects all the revision records and outputs them sorted by date +rather than by file, collapsing duplicate revision record, i.e., +records with the same message for different files. + +The -t option causes it to truncate (discard) the last revision log +entry; this is useful when using something like the above cvs log +command, which shows the revisions including the given tag, while you +probably want everything *since* that tag. + +The -r option reverses the output (oldest first; the default is oldest +last). + +The -b tag option restricts the output to *only* checkin messages +belonging to the given branch tag. The form -b HEAD restricts the +output to checkin messages belonging to the CVS head (trunk). (It +produces some output if tag is a non-branch tag, but this output is +not very useful.) + +-h prints this message and exits. + +XXX This code was created by reverse engineering CVS 1.9 and RCS 5.7 +from their output. +""" + +import sys, errno, getopt, re + +sep1 = '='*77 + '\n' # file separator +sep2 = '-'*28 + '\n' # revision separator + +def main(): + """Main program""" + truncate_last = 0 + reverse = 0 + branch = None + opts, args = getopt.getopt(sys.argv[1:], "trb:h") + for o, a in opts: + if o == '-t': + truncate_last = 1 + elif o == '-r': + reverse = 1 + elif o == '-b': + branch = a + elif o == '-h': + print __doc__ + sys.exit(0) + database = [] + while 1: + chunk = read_chunk(sys.stdin) + if not chunk: + break + records = digest_chunk(chunk, branch) + if truncate_last: + del records[-1] + database[len(database):] = records + database.sort() + if not reverse: + database.reverse() + format_output(database) + +def read_chunk(fp): + """Read a chunk -- data for one file, ending with sep1. + + Split the chunk in parts separated by sep2. + + """ + chunk = [] + lines = [] + while 1: + line = fp.readline() + if not line: + break + if line == sep1: + if lines: + chunk.append(lines) + break + if line == sep2: + if lines: + chunk.append(lines) + lines = [] + else: + lines.append(line) + return chunk + +def digest_chunk(chunk, branch=None): + """Digest a chunk -- extract working file name and revisions""" + lines = chunk[0] + key = 'Working file:' + keylen = len(key) + for line in lines: + if line[:keylen] == key: + working_file = line[keylen:].strip() + break + else: + working_file = None + if branch is None: + pass + elif branch == "HEAD": + branch = re.compile(r"^\d+\.\d+$") + else: + revisions = {} + key = 'symbolic names:\n' + found = 0 + for line in lines: + if line == key: + found = 1 + elif found: + if line[0] in '\t ': + tag, rev = line.split() + if tag[-1] == ':': + tag = tag[:-1] + revisions[tag] = rev + else: + found = 0 + rev = revisions.get(branch) + branch = re.compile(r"^<>$") # <> to force a mismatch by default + if rev: + if rev.find('.0.') >= 0: + rev = rev.replace('.0.', '.') + branch = re.compile(r"^" + re.escape(rev) + r"\.\d+$") + records = [] + for lines in chunk[1:]: + revline = lines[0] + dateline = lines[1] + text = lines[2:] + words = dateline.split() + author = None + if len(words) >= 3 and words[0] == 'date:': + dateword = words[1] + timeword = words[2] + if timeword[-1:] == ';': + timeword = timeword[:-1] + date = dateword + ' ' + timeword + if len(words) >= 5 and words[3] == 'author:': + author = words[4] + if author[-1:] == ';': + author = author[:-1] + else: + date = None + text.insert(0, revline) + words = revline.split() + if len(words) >= 2 and words[0] == 'revision': + rev = words[1] + else: + # No 'revision' line -- weird... + rev = None + text.insert(0, revline) + if branch: + if rev is None or not branch.match(rev): + continue + records.append((date, working_file, rev, author, text)) + return records + +def format_output(database): + prevtext = None + prev = [] + database.append((None, None, None, None, None)) # Sentinel + for (date, working_file, rev, author, text) in database: + if text != prevtext: + if prev: + print sep2, + for (p_date, p_working_file, p_rev, p_author) in prev: + print p_date, p_author, p_working_file, p_rev + sys.stdout.writelines(prevtext) + prev = [] + prev.append((date, working_file, rev, author)) + prevtext = text + +if __name__ == '__main__': + try: + main() + except IOError, e: + if e.errno != errno.EPIPE: + raise