#!/usr/bin/env python3

import argparse
from os import path, getcwd, makedirs, listdir, remove, rename
from subprocess import run, DEVNULL


def folder(default_search, user_input):
    if path.sep in user_input:
        return user_input
    else:
        the_path = path.dirname(path.dirname(path.abspath(__file__)))
        the_path = path.join(the_path, default_search, user_input)
        return the_path


parser = argparse.ArgumentParser(description='''
    Shrink a git changelog into a patchset (based on git format-patch)
''')

parser.add_argument('worktree', metavar='WORKTREE', nargs='?', action='store', default=getcwd(), type=lambda x: folder('worktree', x), help='Worktree (default is cwd, or assumed in ../worktree/)')
parser.add_argument('patchset', metavar='PATCHSET', action='store', type=lambda x: folder('patchset', x), help='Destination patchset (assumed in ../patchset/)')
parser.add_argument('--raw', action='store_true', help='Do not neaten up commits')

args = parser.parse_args()


args.patchset = path.abspath(args.patchset)


assert not path.exists(path.join(args.patchset, '.git')) # protect against argument swap
assert path.exists(path.join(args.worktree, '.git'))


makedirs(args.patchset, exist_ok=True)

for do_delete in listdir(args.patchset):
    do_delete = path.join(args.patchset, do_delete)
    if path.splitext(do_delete)[1].lower() == '.patch':
        remove(do_delete)


run(['git', 'format-patch', '-o', args.patchset, '--anchored=;', 'master-patchset-base'], stdout=DEVNULL, cwd=args.worktree, check=True)

if args.raw: exit()

# Edit the patches to look a bit better (and be more reproducible)
patchnames = [x for x in sorted(listdir(args.patchset)) if path.splitext(x)[1].lower() == '.patch']
strip_chars = min(len(x) - len(x.lstrip('0')) for x in patchnames)

for do_edit in patchnames:
    real_file = path.join(args.patchset, do_edit)
    fake_file = path.join(args.patchset, do_edit + '~')
    new_file = path.join(args.patchset, do_edit[strip_chars:].lower())

    print(path.basename(new_file))

    rename(real_file, fake_file)

    with open(new_file, 'w') as o, open(fake_file, 'r') as i:
        for hdr_line in i:
            if hdr_line == '\n':
                o.write(hdr_line)
                break
            elif hdr_line.startswith('Subject:'):
                if '[' in hdr_line:
                    o.write('Subject:' + hdr_line.rpartition(']')[2])
                else:
                    o.write(hdr_line)
            elif hdr_line.startswith('From:'):
                o.write('From: Horst Beepmanh <>\n')

        for msg_line in i:
            o.write(msg_line)
            if msg_line == '---\n': break

        for junk_line in i:
            if junk_line == junk_line.lstrip():
                o.write(junk_line)
                break

        for diff_line in i:
            if diff_line.startswith('index'): # strip this hash line if possible
                next_line = next(i)
                if next_line.startswith('GIT binary patch'):
                    o.write(diff_line)
                    o.write(next_line)
                else:
                    o.write(next_line)
            else:
                o.write(diff_line)

    remove(fake_file)
