| 
									
										
										
										
											1997-08-14 22:04:00 +00:00
										 |  |  | #! /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. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-10-06 21:09:32 +00:00
										 |  |  |     cvs log -rrelease14: | 
					
						
							| 
									
										
										
										
											1997-08-14 22:04:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | which dumps all log messages from release1.4 upwards (assuming that | 
					
						
							| 
									
										
										
										
											1997-10-06 21:09:32 +00:00
										 |  |  | release 1.4 was tagged with tag 'release14').  Note the trailing | 
					
						
							|  |  |  | colon! | 
					
						
							| 
									
										
										
										
											1997-08-14 22:04:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-10-06 21:09:32 +00:00
										 |  |  | XXX This code was created by reverse engineering CVS 1.9 and RCS 5.7 | 
					
						
							|  |  |  | from their output. | 
					
						
							| 
									
										
										
										
											1997-08-14 22:04:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import os, sys, getopt, string, re | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  | sep1 = '='*77 + '\n'                    # file separator | 
					
						
							|  |  |  | sep2 = '-'*28 + '\n'                    # revision separator | 
					
						
							| 
									
										
										
										
											1997-08-14 22:04:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def main(): | 
					
						
							|  |  |  |     """Main program""" | 
					
						
							|  |  |  |     truncate_last = 0 | 
					
						
							|  |  |  |     opts, args = getopt.getopt(sys.argv[1:], "-t") | 
					
						
							|  |  |  |     for o, a in opts: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         if o == '-t': | 
					
						
							|  |  |  |             truncate_last = 1 | 
					
						
							| 
									
										
										
										
											1997-08-14 22:04:00 +00:00
										 |  |  |     database = [] | 
					
						
							|  |  |  |     while 1: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         chunk = read_chunk(sys.stdin) | 
					
						
							|  |  |  |         if not chunk: | 
					
						
							|  |  |  |             break | 
					
						
							|  |  |  |         records = digest_chunk(chunk) | 
					
						
							|  |  |  |         if truncate_last: | 
					
						
							|  |  |  |             del records[-1] | 
					
						
							|  |  |  |         database[len(database):] = records | 
					
						
							| 
									
										
										
										
											1997-08-14 22:04:00 +00:00
										 |  |  |     database.sort() | 
					
						
							|  |  |  |     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: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         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) | 
					
						
							| 
									
										
										
										
											1997-08-14 22:04:00 +00:00
										 |  |  |     return chunk | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def digest_chunk(chunk): | 
					
						
							|  |  |  |     """Digest a chunk -- extrach working file name and revisions""" | 
					
						
							|  |  |  |     lines = chunk[0] | 
					
						
							|  |  |  |     key = 'Working file:' | 
					
						
							|  |  |  |     keylen = len(key) | 
					
						
							|  |  |  |     for line in lines: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         if line[:keylen] == key: | 
					
						
							|  |  |  |             working_file = string.strip(line[keylen:]) | 
					
						
							|  |  |  |             break | 
					
						
							| 
									
										
										
										
											1997-08-14 22:04:00 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         working_file = None | 
					
						
							| 
									
										
										
										
											1997-08-14 22:04:00 +00:00
										 |  |  |     records = [] | 
					
						
							|  |  |  |     for lines in chunk[1:]: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         revline = lines[0] | 
					
						
							|  |  |  |         dateline = lines[1] | 
					
						
							|  |  |  |         text = lines[2:] | 
					
						
							|  |  |  |         words = string.split(dateline) | 
					
						
							|  |  |  |         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 = string.split(revline) | 
					
						
							|  |  |  |         if len(words) >= 2 and words[0] == 'revision': | 
					
						
							|  |  |  |             rev = words[1] | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             rev = None | 
					
						
							|  |  |  |             text.insert(0, revline) | 
					
						
							|  |  |  |         records.append((date, working_file, rev, author, text)) | 
					
						
							| 
									
										
										
										
											1997-08-14 22:04:00 +00:00
										 |  |  |     return records | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |          | 
					
						
							| 
									
										
										
										
											1997-08-14 22:04:00 +00:00
										 |  |  | def format_output(database): | 
					
						
							|  |  |  |     prevtext = None | 
					
						
							|  |  |  |     prev = [] | 
					
						
							| 
									
										
										
										
											1997-10-06 21:09:32 +00:00
										 |  |  |     database.append((None, None, None, None, None)) # Sentinel | 
					
						
							|  |  |  |     for (date, working_file, rev, author, text) in database: | 
					
						
							| 
									
										
										
										
											1998-03-24 05:30:29 +00:00
										 |  |  |         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 | 
					
						
							|  |  |  |                 sys.stdout.writelines(prevtext) | 
					
						
							|  |  |  |             prev = [] | 
					
						
							|  |  |  |         prev.append((date, working_file, rev, author)) | 
					
						
							|  |  |  |         prevtext = text | 
					
						
							| 
									
										
										
										
											1997-08-14 22:04:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | main() |