#!/usr/bin/env python3
# git-local-tags -- list Git tags which only exist locally
import argparse
import os

def get_local_tags():
    tags = set()
    with os.popen("git tag") as proc:
        for line in proc:
            tags.add(line.strip())
    return tags

def get_remotes():
    remotes = set()
    with os.popen("git remote") as proc:
        for line in proc:
            remotes.add(line.strip())
    return remotes

def get_remote_tagopt(remote="origin"):
    with os.popen("git config remote.%s.tagopt" % remote) as proc:
        line = proc.read().strip()
    return (line != "--no-tags")

def get_remote_tags(remote="origin"):
    tags = set()
    prefix = "refs/tags/"
    with os.popen("git ls-remote %s" % remote) as proc:
        for line in proc:
            sha, ref = line.strip().split()
            if ref.endswith("^{}"):
                continue
            if ref.startswith(prefix):
                tags.add(ref[len(prefix):])
    return tags

parser = argparse.ArgumentParser()
parser.add_argument("-d", "--delete", action="store_true",
                    help="automatically clean up all local-only tags")
parser.add_argument("remote", nargs="*")
args = parser.parse_args()

remotes = args.remote or get_remotes()

local_tags = get_local_tags()
remote_tags = set()
tag_remotes = dict()

for remote in remotes:
    if get_remote_tagopt(remote):
        tags = get_remote_tags(remote)
        remote_tags |= tags
        for tag in tags:
            tag_remotes.setdefault(tag, set()).add(remote)

if args.delete:
    diff = local_tags - remote_tags
    for tag in diff:
        os.system("git tag -d '%s'" % tag)
else:
    diff = local_tags - remote_tags
    if diff:
        print("# Local only:")
        for tag in sorted(diff):
            print("+ %s" % tag)

    diff = remote_tags - local_tags
    if diff:
        print("# Remote only:")
        for tag in sorted(diff):
            remotes = ", ".join(sorted(tag_remotes[tag]))
            print("- %s (%s)" % (tag, remotes))
