home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 April / PCWorld_2001-04_cd.bin / Software / TemaCD / webclean / !!!python!!! / BeOpen-Python-2.0.exe / LOGMERGE.PY < prev    next >
Encoding:
Python Source  |  2000-09-28  |  4.0 KB  |  136 lines

  1. #! /usr/bin/env python
  2.  
  3. """Consolidate a bunch of CVS or RCS logs read from stdin.
  4.  
  5. Input should be the output of a CVS or RCS logging command, e.g.
  6.  
  7.     cvs log -rrelease14:
  8.  
  9. which dumps all log messages from release1.4 upwards (assuming that
  10. release 1.4 was tagged with tag 'release14').  Note the trailing
  11. colon!
  12.  
  13. This collects all the revision records and outputs them sorted by date
  14. rather than by file, collapsing duplicate revision record, i.e.,
  15. records with the same message for different files.
  16.  
  17. The -t option causes it to truncate (discard) the last revision log
  18. entry; this is useful when using something like the above cvs log
  19. command, which shows the revisions including the given tag, while you
  20. probably want everything *since* that tag.
  21.  
  22. XXX This code was created by reverse engineering CVS 1.9 and RCS 5.7
  23. from their output.
  24.  
  25. """
  26.  
  27. import os, sys, getopt, string, re
  28.  
  29. sep1 = '='*77 + '\n'                    # file separator
  30. sep2 = '-'*28 + '\n'                    # revision separator
  31.  
  32. def main():
  33.     """Main program"""
  34.     truncate_last = 0
  35.     reverse = 0
  36.     opts, args = getopt.getopt(sys.argv[1:], "tr")
  37.     for o, a in opts:
  38.         if o == '-t':
  39.             truncate_last = 1
  40.         elif o == '-r':
  41.             reverse = 1
  42.     database = []
  43.     while 1:
  44.         chunk = read_chunk(sys.stdin)
  45.         if not chunk:
  46.             break
  47.         records = digest_chunk(chunk)
  48.         if truncate_last:
  49.             del records[-1]
  50.         database[len(database):] = records
  51.     database.sort()
  52.     if not reverse:
  53.         database.reverse()
  54.     format_output(database)
  55.  
  56. def read_chunk(fp):
  57.     """Read a chunk -- data for one file, ending with sep1.
  58.  
  59.     Split the chunk in parts separated by sep2.
  60.  
  61.     """
  62.     chunk = []
  63.     lines = []
  64.     while 1:
  65.         line = fp.readline()
  66.         if not line:
  67.             break
  68.         if line == sep1:
  69.             if lines:
  70.                 chunk.append(lines)
  71.             break
  72.         if line == sep2:
  73.             if lines:
  74.                 chunk.append(lines)
  75.                 lines = []
  76.         else:
  77.             lines.append(line)
  78.     return chunk
  79.  
  80. def digest_chunk(chunk):
  81.     """Digest a chunk -- extrach working file name and revisions"""
  82.     lines = chunk[0]
  83.     key = 'Working file:'
  84.     keylen = len(key)
  85.     for line in lines:
  86.         if line[:keylen] == key:
  87.             working_file = string.strip(line[keylen:])
  88.             break
  89.     else:
  90.         working_file = None
  91.     records = []
  92.     for lines in chunk[1:]:
  93.         revline = lines[0]
  94.         dateline = lines[1]
  95.         text = lines[2:]
  96.         words = string.split(dateline)
  97.         author = None
  98.         if len(words) >= 3 and words[0] == 'date:':
  99.             dateword = words[1]
  100.             timeword = words[2]
  101.             if timeword[-1:] == ';':
  102.                 timeword = timeword[:-1]
  103.             date = dateword + ' ' + timeword
  104.             if len(words) >= 5 and words[3] == 'author:':
  105.                 author = words[4]
  106.                 if author[-1:] == ';':
  107.                     author = author[:-1]
  108.         else:
  109.             date = None
  110.             text.insert(0, revline)
  111.         words = string.split(revline)
  112.         if len(words) >= 2 and words[0] == 'revision':
  113.             rev = words[1]
  114.         else:
  115.             rev = None
  116.             text.insert(0, revline)
  117.         records.append((date, working_file, rev, author, text))
  118.     return records
  119.         
  120. def format_output(database):
  121.     prevtext = None
  122.     prev = []
  123.     database.append((None, None, None, None, None)) # Sentinel
  124.     for (date, working_file, rev, author, text) in database:
  125.         if text != prevtext:
  126.             if prev:
  127.                 print sep2,
  128.                 for (p_date, p_working_file, p_rev, p_author) in prev:
  129.                     print p_date, p_author, p_working_file
  130.                 sys.stdout.writelines(prevtext)
  131.             prev = []
  132.         prev.append((date, working_file, rev, author))
  133.         prevtext = text
  134.  
  135. main()
  136.