#!/usr/bin/env python3
# -*- coding: utf-8-unix -*-

# Print GNU-style ChangeLog to standard output based on git log.
#
# git commit messages are left untouched to avoid ruining formatting, so they
# are expected to have been wrapped at 72 characters. All commit messages that
# appear to be full ChangeLog messages are used as is, i.e. date and author
# information from git log is not used for those entries.

import os
import re
import sys
import textwrap

re_commit = re.compile((r"^commit \w+?\n"
                        r"^Author: (?P<name>.*?) <(?P<email>.*?)>\n"
                        r"^Date:   (?P<date>.*?)\n"
                        r"^$\n"
                        r"(?P<message>(^    .*?$\n)+)"
                        r"^$\n"
                        r"(?P<files>(^.+?$\n)+?)"
                        r"^$\n"
                        ),
                       re.MULTILINE)

re_change_log_message = re.compile(r"^\d\d\d\d-\d\d-\d\d  ")
re_trailing_space = re.compile(r"\s*$", re.MULTILINE)
wrapper = textwrap.TextWrapper(initial_indent="\t", subsequent_indent="\t")

def write_commit(match):
    message = textwrap.dedent(match.group("message"))
    if re_change_log_message.search(message):
        sys.stdout.write(message)
    else: # Normal git commit message.
        write_message(match.group("date"),
                      match.group("name"),
                      match.group("email"),
                      match.group("files").splitlines(),
                      message)

    sys.stdout.write("\n")

def write_message(date, name, email, files, message):
    sys.stdout.write("{}  {}  <{}>\n".format(date, name, email))
    message_lines = message.splitlines()
    if len(files) == 1:
        text = "* {}: {}".format(files[0], message_lines.pop(0))
        sys.stdout.write("\n{}\n".format(wrapper.fill(text)))
    else: # Multiple changed files.
        for name in files:
            sys.stdout.write("\n\t* {}:".format(name))
        sys.stdout.write("\n\n")
    for line in message_lines:
        line = re_trailing_space.sub("", "\t{}".format(line))
        sys.stdout.write("{}\n".format(line))

text = os.popen("git log --stat -M -C --name-only --date=short", "r").read()
for match in re_commit.finditer(text):
    write_commit(match)
