#!/usr/bin/env python3
from gitz import git_functions
from gitz import reference_branch
from gitz.program import PROGRAM
from gitz.program import git
from gitz.program import quiet_git

SUMMARY = 'Update branches from the reference branch'
USAGE = 'git-update [branch ...branch]'
DANGER = 'Rewrites history!'
HELP = """
``git-update`` goes to each branch in turn, then tries to update it
the reference branch by pulling with --rebase.

If the rebase fails with a conflict, then ``git-update``aborts the
rebase and returns that branch to its previous condition.

If the rebase succeeds, ``git-update`` force-pushes the result.
"""
EXAMPLES = """
git-update
    Updates all branches

git-update foo bar
    Only updates branches foo and bar
"""


def git_update():
    git_functions.check_clean_workspace()
    ref_branch = reference_branch.reference_branch()
    args = PROGRAM.args
    branches = git_functions.branches()
    missing = set(args.branches).difference(branches)
    if missing:
        PROGRAM.exit('Missing:', *missing)

    starting_branch = git_functions.branch_name()
    branch_to_upstream = {}

    for branch in args.branches or branches:
        git.checkout(branch)
        branch_to_upstream[branch] = git_functions.upstream_branch()

    for upstream in set(v[0] for v in branch_to_upstream.values()):
        quiet_git.fetch(upstream)

    failed, succeeded = [], []
    for branch, upstream in branch_to_upstream.items():
        quiet_git.checkout(branch)
        if not args.force:
            branch_commit_id = git_functions.commit_id()
            upstream = '/'.join(upstream)
            remote_commit_id = git_functions.commit_id(upstream)
            if branch_commit_id != remote_commit_id:
                try:
                    quiet_git.push()
                except Exception:
                    failed.append(branch)
                    PROGRAM.error(
                        'Skipping', branch, 'which differed from', upstream
                    )
                    continue
        try:
            quiet_git.pull('--rebase', *ref_branch)
        except Exception:
            failed.append(branch)
            quiet_git.rebase('--abort')
        else:
            succeeded.append(branch)
            git.push('--force-with-lease')

    quiet_git.checkout(starting_branch)

    if succeeded:
        PROGRAM.message('Updated', *sorted(succeeded))

    if failed:
        PROGRAM.error('Failed', *sorted(failed))

    if False and PROGRAM.called['error']:
        PROGRAM.exit()


def add_arguments(parser):
    parser.add_argument('branches', nargs='?', default='', help=_HELP_BRANCHES)
    parser.add_argument('-f', '--force', action='store_true', help=_HELP_FORCE)
    reference_branch.add_arguments(parser)


_HELP_FORCE = 'Force push over non-matching remote branches'
_HELP_BRANCHES = 'A list of branches to update - default is all branches'


if __name__ == '__main__':
    PROGRAM.start(**globals())
