#!/usr/bin/env python
#
# This script generates simple Changelog where items are grouped by
# subsystem prefix from commit subject.
#
# 	$ git log --pretty=format:"%h %s"
#	1dea05a blockdev: use LU and LLU for BLKGETSIZE and BLKGETSIZE64
#	3281d42 blockdev: fix "blockdev --getsz" for large devices
#	1002156 mount: should set proper permissions on locktime
#
#	$ git-groupedlog
#	blockdev:
#	   - use LU and LLU for BLKGETSIZE and BLKGETSIZE64
#	   - fix "blockdev --getsz" for large devices
#	mount:
#      - should set proper permissions on locktime
#
#
# Copyright (C) 2007 Karel Zak <kzak@redhat.com>
#

import sys
import os
import string
import re

class GitRepo:
    def __init__(self, repodir=None):
        self.repodir = dir
        if repodir:
            os.environ['GIT_DIR'] = repodir

    def get_ids(self, commit1, commit2=None):
        """returns list of commits' ID from commit1 to commit2
           -- commit2 is optional
        """
        if commit2:
            cmd = 'git rev-list --no-merges %s..%s' % (commit1, commit2)
        else:
            cmd = 'git rev-list --no-merges %s..' % commit1
        p = os.popen(cmd, 'r')
        lns = p.readlines()
        p.close()

        res=[]
        for l in lns:
            res.append(l[:-1])
        return res

    def get_commit(self, id, fields):
        """returns a commit as python dict, fields is reqested list of GIT
           --pretty=format placeholders
        """
        fmt = '{'
        for f in fields:
            fmt += '"'+f+'":""" %'+f+' """,'
        fmt += '}'
        cmd = "git diff-tree --quiet --pretty=format:'%s' %s" % (fmt, id)
        p = os.popen(cmd, 'r')
        data = ''
        while True:
            lns = p.read()
            if len(lns) == 0:
                break
            data += lns
        p.close()

        try:
            c = eval(data)
        except:
            print "evaluate commit %s failed" % id
            raise ValueError
        cmt = {}
        for key, data in c.iteritems():
            cmt[key] = data.strip()
        return cmt

    def get_body_field(self, body, name):
        """returns lists of commit body fields (e.g Signed-off-by)"""
        if name.endswith(':'):
            name = name[:-1]
        return re.findall('^%s:[ ]*(.*)$' % name, body, re.MULTILINE | re.IGNORECASE)

#
# Main
#
if len(sys.argv) == 1:
    print 'Usage: %s <FROM-tree-ish> [<TO-tree-ish>]' % sys.argv[0]

v1 = sys.argv[1]
if len(sys.argv) > 2:
    v2 = sys.argv[2]
else:
    v2 = None

git = GitRepo()
ids = git.get_ids(v1, v2)

fls = {}

def rem_email(str):
    idx = str.rfind('<')
    if idx:
        return str[:idx].strip()

    return str.strip()

for id in ids:
    cmmt = git.get_commit(id, ['an','ae','s','b'])
    f = git.get_body_field(cmmt['b'], 'From')
    ca = git.get_body_field(cmmt['b'], 'Co-Author')
    an = []

    # "From:" overwrites "Author:"
    if not f or len(f) == 0:
        an.append(cmmt['an'])
    else:
        an.append = rem_email(f[0])

    for c in ca:
        if c not in an:
            an.append(rem_email(c))

    # read prefix
    x = cmmt['s'].split(':')
    item = ''
    if len(x) < 2:
        key = 'unknown'
        item = cmmt['s']
    else:
        key = x[0].strip()
        item = string.join(x[1:])
    if not fls.has_key(key):
        fls[key] = []
    item = item.strip() + '  [%s]' % string.join(an, ', ')
    if item not in fls[key]:
        fls[key].append(item)

keys = fls.keys()
keys.sort()
for key in keys:
    if key == 'unknown':
        continue
    print "%s:" % key
    ents = fls[key]
    ents.sort()
    for ent in ents:
        print "   - %s" % ent

if fls.has_key('unknown'):
    print
    ents = fls[key]
    ents.sort()
    for ent in ents:
        print "- %s" % ent



# vim: set tabstop=4:
# vim: set shiftwidth=4:
# vim: set expandtab:
