#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
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, re, sys, 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)
