#!/usr/bin/python
#
# Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.

#
# This script lists obsolete (fully merged) branches. It is useful for periodic maintenance
# of our GIT tree.
#
# This script requires python 2.7 or 3.
#
# I have limited experience in Python. If things are done in a strange or uncommon way, there
# are no obscure reasons to do it that way, just plain lack of experience.
#
#                                                                        tomek

import string
import subprocess
import sys

class Branch:
    MERGED=1
    NOTMERGED=2
    name = ""
    status = NOTMERGED
    last_commit = ""


def branch_list_get(verbose):
    txt_list = subprocess.check_output(["git", "branch", "-r"])

    txt_list = txt_list.split(b"\n")

    out = []
    for branch in txt_list:
        if len(branch) == 0:
            continue
        if branch.find(b"->") != -1:
            continue
        if branch == b"origin/master":
            continue

        branch_info = Branch()

        # get branch name
        branch_info.name = branch.strip(b" ")
        branch_info.name = branch_info.name.decode("utf-8")

        # check if branch is merged or not
        if verbose:
            print("Checking branch %s" % branch_info.name)

        cmd = ["git", "diff", "master..." + branch_info.name ]
        diff = subprocess.check_output(cmd)
        if (len(diff) == 0):
            branch_info.status = Branch.MERGED
            # let's get the last contributor
            cmd = [ "git" , "log", "-n", "1", "--pretty=\"%ai,%ae,%an\"", branch_info.name ]

            offender = subprocess.check_output(cmd)
            offender = offender.strip(b"\n\"")

            # comment out this 2 lines to disable obfuscation
            offender = offender.replace(b"@", b"(at)")
            offender = offender.replace(b".", b"(dot)")

            branch_info.last_commit = offender.decode("utf-8")

        else:
            branch_info.status = Branch.NOTMERGED

        out.append(branch_info)
#        return (out)
    return (out)

def branch_print(branches, csv, print_merged, print_notmerged, print_stats):
    merged = 0
    notmerged = 0
    merged_str = ""
    notmerged_str = ""
    for branch in branches:
        if (branch.status==Branch.MERGED):
            merged = merged + 1
            if (not print_merged):
                continue
            if (csv):
                print("%s,merged,%s" % (branch.name, branch.last_commit) )
            else:
                merged_str = merged_str + " " + branch.name
        else:
            # NOT MERGED
            notmerged = notmerged + 1
            if (not print_notmerged):
                continue
            if (csv):
                print("%s,notmerged,%s" % (branch.name, branch.last_commit) )
            else:
                notmerged_str = notmerged_str + " " + branch.name

    if (not csv):
        if (print_merged):
            print("Merged branches    : %s" % (merged_str))
        if (print_notmerged):
            print("NOT merged branches: %s" % (notmerged_str))

    if (print_stats):
        print("#----------");
        print("#Merged    : %d" % merged)
        print("#Not merged: %d" % notmerged)

def show_help():
    print("This script prints out merged and/or unmerged branches of a GIT tree.")
    print("Supported command-line options:")
    print("")
    print("--csv          produce CSV (coma separated value) output")
    print("--unmerged     lists umerged branches")
    print("--skip-merged  do not print merged branches (that are listed by default)")
    print("--stats        prints out statistics")
    print("--help         prints out this help")

def main():
    usage = """%prog
    Lists all obsolete (fully merged into master) branches.
    """

    csv = False;
    merged = True;
    unmerged = False;
    stats = False;

    for x in sys.argv[1:]:
        if x == "--csv":
            csv = True;
        elif x == "--unmerged":
            unmerged = True;
        elif x == "--skip-merged":
            merged = False;
        elif x == "--stats":
            stats = True;
        elif x == "--help":
            show_help()
            return
        else:
            print("Invalid parameter: %s" % x)
            print("")
            show_help()
            return

    if csv:
        print("branch name,status,date,last commit(mail),last commit(name)")

    branch_list = branch_list_get(not csv)

#   Uncomment this to print out also merged branches
#    branch_print(branch_list, False, True, False)

    branch_print(branch_list, csv, merged, unmerged, stats)

if __name__ == '__main__':
   main()