#!/usr/bin/env vpython3
# Copyright 2020 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Migrate local repository onto new default branch."""

import fix_encoding
import gerrit_util
import git_common
import metrics
import scm
import sys
import logging
import urllib.parse


def GetGerritProject(remote_url):
    """Returns Gerrit project name based on remote git URL."""
    if remote_url is None:
        raise RuntimeError('can\'t detect Gerrit project.')
    project = urllib.parse.urlparse(remote_url).path.strip('/')
    if project.endswith('.git'):
        project = project[:-len('.git')]
    # *.googlesource.com hosts ensure that Git/Gerrit projects don't start with
    # 'a/' prefix, because 'a/' prefix is used to force authentication in
    # gitiles/git-over-https protocol. E.g.,
    # https://chromium.googlesource.com/a/v8/v8 refers to the same repo/project
    # as
    # https://chromium.googlesource.com/v8/v8
    if project.startswith('a/'):
        project = project[len('a/'):]
    return project


def GetGerritHost(git_host):
    parts = git_host.split('.')
    parts[0] = parts[0] + '-review'
    return '.'.join(parts)


def main():
    remote = git_common.run('remote')
    # Use first remote as source of truth
    remote = remote.split("\n")[0]
    if not remote:
        raise RuntimeError('Could not find any remote')
    url = scm.GIT.GetConfig(git_common.repo_root(), 'remote.%s.url' % remote)
    host = urllib.parse.urlparse(url).netloc
    if not host:
        raise RuntimeError('Could not find remote host')

    project_head = gerrit_util.GetProjectHead(GetGerritHost(host),
                                              GetGerritProject(url))
    if project_head != 'refs/heads/main':
        raise RuntimeError("The repository is not migrated yet.")

    # User may have set to fetch only old default branch. Ensure fetch is
    # tracking main too.
    git_common.run('config', '--unset-all', 'remote.origin.fetch',
                   'refs/heads/*')
    git_common.run('config', '--add', 'remote.origin.fetch',
                   '+refs/heads/*:refs/remotes/origin/*')
    logging.info("Running fetch...")
    git_common.run('fetch', remote)
    logging.info("Updating remote HEAD...")
    git_common.run('remote', 'set-head', '-a', remote)

    branches = git_common.get_branches_info(True)

    if 'master' in branches:
        logging.info("Migrating master branch...")
        if 'main' in branches:
            logging.info(
                'You already have master and main branch, consider removing '
                'master manually:\n'
                ' $ git branch -d master\n')
        else:
            git_common.run('branch', '-m', 'master', 'main')
        branches = git_common.get_branches_info(True)

    for name in branches:
        branch = branches[name]
        if not branch:
            continue

        if 'master' in branch.upstream:
            logging.info("Migrating %s branch..." % name)
            new_upstream = branch.upstream.replace('master', 'main')
            git_common.run('branch', '--set-upstream-to', new_upstream, name)
            git_common.remove_merge_base(name)


if __name__ == '__main__':
    fix_encoding.fix_encoding()
    logging.basicConfig(level=logging.INFO)
    with metrics.collector.print_notice_and_exit():
        try:
            logging.info("Starting migration")
            main()
            logging.info("Migration completed")
        except RuntimeError as e:
            logging.error("Error %s" % str(e))
            sys.exit(1)
