#!/bin/bash
#
# Copyright (c) 2021 The Flatcar Maintainers.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

set -eu

force_tag="false"
force_branch="false"

update_strategy="fast-forward"

name=""

usage() {
    echo "  Usage:"
    echo "  $0 [-t|-b] [-n] [-u <strategy>] <tag-or-branch>"
    echo "       Check our a tag or branch and synchronise git submodules"
    echo "          coreos-overlay and portage-stable."
    echo "       By default, $0 tries to auto-detect whether to handle a tag or a branch,"
    echo "         with tags being prioritised over branches of the same name."
    echo
    echo "       <tag-or-branch> Name of the tag or branch to check out."
    echo "                       BRANCH: Check out the branch in scripts, coreos-overlay"
    echo "                                and portage-stable, and fast-forward to the"
    echo "                                latest changes by default (but see '-u' below)."
    echo "                       TAG:    Check out the tag in scripts, and update submodules."
    echo
    echo "       -t            force TAG mode. Branches of the given name are ignored."
    echo "                      Mutually exclusive with '-b'."
    echo "       -b            force BRANCH mode. Tags of the given name are ignored."
    echo "                      Mutually exclusive with '-t'."
    echo
    echo "       -u <strategy> Only applies to BRANCH checkouts."
    echo "                      When checking out submodule branches, use <strategy>."
    echo "                      instead of fast-forward. Strategy is one of:"
    echo "                      'fast-forward' - fast-forward to upstream branch tip. Default."
    echo "                      'rebase' - rebase local changes on upstream changes."
    echo "                                 Useful for keepling local changes in submodules."
    echo "                      'omit'   - check out branches, but do not update."
    echo "                      Defaults to '$update_strategy'"
    echo
    echo "       -h            Print this help."
    echo
}
# --

while [ 0 -lt $# ] ; do
    case "$1" in
    -h) usage; exit 0;;
    -t) force_tag="true";     shift;;
    -b) force_branch="true";  shift;;
    -u) update_strategy="$2"; shift; shift;;
    *) if [ -n "$name" ] ; then
            echo
            echo "ERROR: only ONE tag-or-branch can be specified."
            echo
            usage
            exit 1
       fi
       name="$1";      shift;;
    esac
done

if [ -z "$name" ] ; then
    usage
    exit 0
fi

if $force_branch && $force_tag; then
    echo
    echo "ERROR: '-t' and '-b' are mutually exclusive. Please make up your mind."
    echo
    usage
    exit 1
fi

case "$update_strategy" in
    fast-forward) update_strategy="--ff-only";;
    rebase)       update_strategy="--rebase";;
    omit)         update_strategy="";;
    *)  echo
        echo "ERROR: unsupported branch update strategy '$update_strategy'."
        echo
        usage
        exit 1;;
esac
# --

# make sure submodules are initialised
git submodule init
for dir in sdk_container/src/third_party/coreos-overlay \
           sdk_container/src/third_party/portage-stable ; do
    if [ ! -f "$dir"/.git ] ; then
        git submodule update -N "$dir"
    fi
done

function check_all() {
    local gitcmd="$1"
    local name="$2"

    local scripts="$(git $gitcmd \
                        | sed -e 's/^[[:space:]]*//' -e 's:remotes/[^/]\+/::' \
                        | grep -m1 -E "^$name\$")"

    # tag has submodules pinned, no need to check
    if [[ "${gitcmd}" =~ ^tag\ .* ]] ; then
        echo "${scripts}"
        return
    fi

    local overlay="$(git -C sdk_container/src/third_party/coreos-overlay $gitcmd \
                        | sed -e 's/^[[:space:]]*//' -e 's:remotes/[^/]\+/::' \
                        | grep -m1 -E "^$name\$")"
    local portage="$(git -C sdk_container/src/third_party/portage-stable $gitcmd \
                        | sed -e 's/^[[:space:]]*//' -e 's:remotes/[^/]\+/::' \
                        | grep -m1 -E "^$name\$")"

    if [ -n "$scripts" -a -n "$overlay" -a -n "$portage" ] ; then
        echo "$scripts"
    fi
}
# --

#
# TAG
#
if ! $force_branch; then
    for dir in . \
        sdk_container/src/third_party/coreos-overlay \
        sdk_container/src/third_party/portage-stable ; do
        git -C "$dir" fetch --tags --force --prune --prune-tags
    done
    tag="$(check_all 'tag -l' "$name")"

    if [ -n "$tag" ] ; then
        echo
        echo "Checking out TAG '$tag'"
        echo "----------------------------------"
        git checkout "$tag"
        git submodule update
        exit
    fi
fi

echo "No tag by name '$name' in repo + submodules."

if $force_tag; then
    echo "Tag-only mode forced, exiting."
    exit 1
fi

#
# BRANCH
#

branch="$(check_all "branch -a -l" "$name")"
if [ -z "$branch" ]; then
    echo "No branch by name '$name' in repo + submodules."
    exit 1
fi

echo
echo "Checking out BRANCH '$branch'"
echo "----------------------------------"
for dir in . \
    sdk_container/src/third_party/coreos-overlay \
    sdk_container/src/third_party/portage-stable ; do

    git -C "$dir" checkout "$branch"
    if [ -n "$update_strategy" ] ; then
        echo "updating branch in '$dir' /'$update_strategy')"
        git -C "$dir" pull "$update_strategy"
    fi
done

