#!/usr/bin/env python
# -*- mode: python -*-
#
# This python program has been copied from
# https://github.com/GNOME/gnet/blob/master/gen-changelog.py
#
# It has been authored by Edward Hervey, of GStreamer fame.  I have
# asked his permission to copy it and re-use it here, as part of the
# Libabigail project.  He granted me the permission to distribute the
# program under the terms of the GNU Lesser Public License as
# published by the Free Software Foundaion; either version 2, or (at
# your option) any later version.
#
# Thus, this program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; see the file COPYING-LGPLV2.  If
# not, see <http://www.gnu.org/licenses/>.

import sys
import subprocess
import re

# Makes a GNU-Style ChangeLog from a git repository
# Handles git-svn repositories also

# Arguments : same as for git log
release_refs={}

def process_commit(lines, files):
    # DATE NAME
    # BLANK LINE
    # Subject
    # BLANK LINE
    # ...
    # FILES
    fileincommit = False
    lines = [x.strip() for x in lines if x.strip() and not x.startswith('git-svn-id')]
    files = [x.strip() for x in files if x.strip()]
    for l in lines:
        if l.startswith('* '):
            fileincommit = True
            break

    top_line = lines[0]
    subject_line_index = 0 if lines[1].startswith('*') else 1;
    first_cl_body_line_index = 0;

    for i in range(1, len(lines)):
        if lines[i].startswith('*'):
            first_cl_body_line_index = i
            break;

    # Clean up top line of ChangeLog entry:
    fields = top_line.split(' ')

    # 1. remove the time and timezone stuff in "2008-05-13 07:10:28 +0000  name"
    if fields[2].startswith('+') or fields[2].startswith('-'):
      del fields[2]
    if fields[1][2] == ':' and fields[1][5] == ':':
      del fields[1]

    # 2. munge at least my @src.gnome.org e-mail address...
    if fields[-1] == '<tpm@src.gnome.org>':
      fields[-1] = '<tim@centricular.net>'

    top_line = ' '.join(fields)
    print(top_line.strip())
    print()

    if subject_line_index > 0:
        print('\t%s' % lines[subject_line_index].strip())

    if not fileincommit:
        for f in files:
            print('\t* %s:' % f.strip())
        print()

    if first_cl_body_line_index > 0:
        for l in lines[first_cl_body_line_index:]:
            if l.startswith('Signed-off-by:'):
                continue
            print('\t%s' % l.strip())
        print()

def output_commits():
    cmd = ['git', 'log', '--pretty=format:--START-COMMIT--%H%n%ai  %an <%ae>%n%n%s%n%b%n--END-COMMIT--',
           '--date=short', '--name-only']

    start_tag = find_start_tag()

    if start_tag is None:
        cmd.extend(sys.argv[1:])
    else:
        cmd.extend(["%s..HEAD" % (start_tag)])

    p = subprocess.Popen(args=cmd, shell=False,
                         stdout=subprocess.PIPE,
                         text=True)
    buf = []
    files = []
    filemode = False
    for lin in p.stdout.readlines():
        if lin.startswith("--START-COMMIT--"):
            if buf != []:
                process_commit(buf, files)
            hash = lin[16:].strip()
            try:
                rel = release_refs[hash]
                print("=== release %d.%d.%d ===\n" % (int(rel[0]), int(rel[1]), int(rel[2])))
            except:
                pass
            buf = []
            files = []
            filemode = False
        elif lin.startswith("--END-COMMIT--"):
            filemode = True
        elif filemode == True:
            files.append(lin)
        else:
            buf.append(lin)
    if buf != []:
        process_commit(buf, files)

def get_rel_tags():
    # Populate the release_refs dict with the tags for previous releases
    reltagre = re.compile("^([a-z0-9]{40}) refs\/tags\/GNET-([0-9]+)[-_.]([0-9]+)[-_.]([0-9]+)")

    cmd = ['git', 'show-ref', '--tags', '--dereference']
    p = subprocess.Popen(args=cmd, shell=False,
                         stdout=subprocess.PIPE,
                         text=True)
    for lin in p.stdout:
       match = reltagre.search(lin)
       if match:
           (sha, maj, min, nano) = match.groups()
           release_refs[sha] = (maj, min, nano)

def find_start_tag():
    starttagre = re.compile("^([a-z0-9]{40}) refs\/tags\/CHANGELOG_START")
    cmd = ['git', 'show-ref', '--tags']
    p = subprocess.Popen(args=cmd, shell=False,
                         stdout=subprocess.PIPE,
                         text=True)
    for lin in p.stdout:
       match = starttagre.search(lin)
       if match:
           return match.group(1)
    return None

if __name__ == "__main__":
    get_rel_tags()
    output_commits()
