symbian-qemu-0.9.1-12/python-2.6.1/Tools/scripts/logmerge.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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 The -r option reverses the output (oldest first; the default is oldest
       
    23 last).
       
    24 
       
    25 The -b tag option restricts the output to *only* checkin messages
       
    26 belonging to the given branch tag.  The form -b HEAD restricts the
       
    27 output to checkin messages belonging to the CVS head (trunk).  (It
       
    28 produces some output if tag is a non-branch tag, but this output is
       
    29 not very useful.)
       
    30 
       
    31 -h prints this message and exits.
       
    32 
       
    33 XXX This code was created by reverse engineering CVS 1.9 and RCS 5.7
       
    34 from their output.
       
    35 """
       
    36 
       
    37 import sys, errno, getopt, re
       
    38 
       
    39 sep1 = '='*77 + '\n'                    # file separator
       
    40 sep2 = '-'*28 + '\n'                    # revision separator
       
    41 
       
    42 def main():
       
    43     """Main program"""
       
    44     truncate_last = 0
       
    45     reverse = 0
       
    46     branch = None
       
    47     opts, args = getopt.getopt(sys.argv[1:], "trb:h")
       
    48     for o, a in opts:
       
    49         if o == '-t':
       
    50             truncate_last = 1
       
    51         elif o == '-r':
       
    52             reverse = 1
       
    53         elif o == '-b':
       
    54             branch = a
       
    55         elif o == '-h':
       
    56             print __doc__
       
    57             sys.exit(0)
       
    58     database = []
       
    59     while 1:
       
    60         chunk = read_chunk(sys.stdin)
       
    61         if not chunk:
       
    62             break
       
    63         records = digest_chunk(chunk, branch)
       
    64         if truncate_last:
       
    65             del records[-1]
       
    66         database[len(database):] = records
       
    67     database.sort()
       
    68     if not reverse:
       
    69         database.reverse()
       
    70     format_output(database)
       
    71 
       
    72 def read_chunk(fp):
       
    73     """Read a chunk -- data for one file, ending with sep1.
       
    74 
       
    75     Split the chunk in parts separated by sep2.
       
    76 
       
    77     """
       
    78     chunk = []
       
    79     lines = []
       
    80     while 1:
       
    81         line = fp.readline()
       
    82         if not line:
       
    83             break
       
    84         if line == sep1:
       
    85             if lines:
       
    86                 chunk.append(lines)
       
    87             break
       
    88         if line == sep2:
       
    89             if lines:
       
    90                 chunk.append(lines)
       
    91                 lines = []
       
    92         else:
       
    93             lines.append(line)
       
    94     return chunk
       
    95 
       
    96 def digest_chunk(chunk, branch=None):
       
    97     """Digest a chunk -- extract working file name and revisions"""
       
    98     lines = chunk[0]
       
    99     key = 'Working file:'
       
   100     keylen = len(key)
       
   101     for line in lines:
       
   102         if line[:keylen] == key:
       
   103             working_file = line[keylen:].strip()
       
   104             break
       
   105     else:
       
   106         working_file = None
       
   107     if branch is None:
       
   108         pass
       
   109     elif branch == "HEAD":
       
   110         branch = re.compile(r"^\d+\.\d+$")
       
   111     else:
       
   112         revisions = {}
       
   113         key = 'symbolic names:\n'
       
   114         found = 0
       
   115         for line in lines:
       
   116             if line == key:
       
   117                 found = 1
       
   118             elif found:
       
   119                 if line[0] in '\t ':
       
   120                     tag, rev = line.split()
       
   121                     if tag[-1] == ':':
       
   122                         tag = tag[:-1]
       
   123                     revisions[tag] = rev
       
   124                 else:
       
   125                     found = 0
       
   126         rev = revisions.get(branch)
       
   127         branch = re.compile(r"^<>$") # <> to force a mismatch by default
       
   128         if rev:
       
   129             if rev.find('.0.') >= 0:
       
   130                 rev = rev.replace('.0.', '.')
       
   131                 branch = re.compile(r"^" + re.escape(rev) + r"\.\d+$")
       
   132     records = []
       
   133     for lines in chunk[1:]:
       
   134         revline = lines[0]
       
   135         dateline = lines[1]
       
   136         text = lines[2:]
       
   137         words = dateline.split()
       
   138         author = None
       
   139         if len(words) >= 3 and words[0] == 'date:':
       
   140             dateword = words[1]
       
   141             timeword = words[2]
       
   142             if timeword[-1:] == ';':
       
   143                 timeword = timeword[:-1]
       
   144             date = dateword + ' ' + timeword
       
   145             if len(words) >= 5 and words[3] == 'author:':
       
   146                 author = words[4]
       
   147                 if author[-1:] == ';':
       
   148                     author = author[:-1]
       
   149         else:
       
   150             date = None
       
   151             text.insert(0, revline)
       
   152         words = revline.split()
       
   153         if len(words) >= 2 and words[0] == 'revision':
       
   154             rev = words[1]
       
   155         else:
       
   156             # No 'revision' line -- weird...
       
   157             rev = None
       
   158             text.insert(0, revline)
       
   159         if branch:
       
   160             if rev is None or not branch.match(rev):
       
   161                 continue
       
   162         records.append((date, working_file, rev, author, text))
       
   163     return records
       
   164 
       
   165 def format_output(database):
       
   166     prevtext = None
       
   167     prev = []
       
   168     database.append((None, None, None, None, None)) # Sentinel
       
   169     for (date, working_file, rev, author, text) in database:
       
   170         if text != prevtext:
       
   171             if prev:
       
   172                 print sep2,
       
   173                 for (p_date, p_working_file, p_rev, p_author) in prev:
       
   174                     print p_date, p_author, p_working_file, p_rev
       
   175                 sys.stdout.writelines(prevtext)
       
   176             prev = []
       
   177         prev.append((date, working_file, rev, author))
       
   178         prevtext = text
       
   179 
       
   180 if __name__ == '__main__':
       
   181     try:
       
   182         main()
       
   183     except IOError, e:
       
   184         if e.errno != errno.EPIPE:
       
   185             raise