#!/bin/bash -e
: "${dbuser:="geekotest"}"
: "${dbgroup:="nogroup"}"

: "${dist_name:=${dist:-"openSUSE"}}" # the display name, for the help message
: "${dist:="opensuse"}"
: "${giturl:="https://github.com/os-autoinst/os-autoinst-distri-opensuse.git"}"
: "${branch:=""}"
: "${email:="openqa@$HOST"}"
: "${username:="openQA web UI"}"
: "${product:="$dist"}"

: "${git_lfs:="0"}"
: "${needles_separate:="1"}"
: "${needles_giturl:="https://github.com/os-autoinst/os-autoinst-needles-opensuse.git"}"
: "${needles_branch:=""}"

: "${updateall:="0"}"
: "${force:="0"}"

if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
    printf "Get %s tests and needles from:\n\t\t%s\n" "${dist_name}" "${giturl}"
    if [ "$needles_separate" = 1 ]; then
        printf "\tand\t%s\n" "${needles_giturl}"
    fi
    printf "\n(environment variables mentioned in '%s' can be set to change these values)\n" "$0"
    exit
fi

dir="${OPENQA_BASEDIR:-/var/lib}/openqa/share/tests"
if [ -w / ]; then
    if [ ! -e "$dir/$dist" ]; then
        mkdir -p "$dir/$dist"
        chown "$dbuser:$dbgroup" "$dir/$dist"
    fi
    echo "running as root, re-exec as $dbuser ..."
    exec sudo -u "$dbuser" env \
        dist="$dist" \
        giturl="$giturl" \
        branch="$branch" \
        email="$email" \
        username="$username" \
        needles_separate="$needles_separate" \
        needles_giturl="$needles_giturl" \
        needles_branch="$needles_branch" \
        updateall="$updateall" \
        force="$force" \
        "$0" "$@"
    exit 1
fi

fail() {
    echo "$*" >&2
    exit 1
}

needlesdir() {
    # new layout since
    # https://github.com/os-autoinst/os-autoinst-distri-opensuse/pull/920
    if [ -d "$dir/$dist/products" ]; then
        echo "$dir/$dist/products/$product/needles"
    else
        echo "needles"
    fi
}

deal_with_stale_lockfile() {
    lock_path=.git/index.lock
    if [ -e "$lock_path" ] && ! fuser --silent "$lock_path"; then # fuser returns 0 if one or more processes hold the lock
        echo "removing stale lock $PWD/$lock_path"
        rm "$lock_path"
    fi
}

# Determine the "main branch" for the remote origin unless a branch has been specified explicitly
# note: This relies on a file called `refs/remotes/origin/HEAD` with contents like `ref: refs/remotes/origin/master` being
#       present under the `.git` directory. This should be the case for all recently cloned Git repositories. Otherwise
#       one can just create the file making it point to the desired branch.
get_git_base() {
    branch=$1
    if [ "$branch" ]; then
        echo "origin/$branch"
    else
        git rev-parse --abbrev-ref refs/remotes/origin/HEAD
    fi
}

git_update() {
    deal_with_stale_lockfile
    git gc --auto --quiet
    git fetch -q origin

    # Clear any uncommitted changes that would prevent a rebase
    [ "$force" = 1 ] && git reset -q --hard HEAD
    base=$(get_git_base "$1")
    git rebase -q "$base" || fail 'Use force=1 to discard uncommitted changes before rebasing'
}

# For needles repos because of needle saving we might end up in conflict, i.e.
# detached HEAD so we need to repair this
git_update_needles() {
    git_update "$needles_branch"
    if [ "$(git rev-parse --abbrev-ref --symbolic-full-name HEAD)" = "HEAD" ]; then
        base=$(get_git_base "$needles_branch")
        needles_branch=${base#origin/}
        git branch -D "$needles_branch"
        git checkout -b "$needles_branch"
        git branch "--set-upstream-to=$base" "$needles_branch"
        git push origin "HEAD:$needles_branch"
    fi
}

do_fetch() {
    target=$1
    git_update "$branch"
    [ "$needles_separate" = 1 ] || return 0
    if test -d products; then
        for nd in products/*/needles; do
            [ -h "$target/$nd" ] && continue
            (cd "$target/$nd" && git_update_needles)
        done
    else
        (cd "$target/needles" && git_update_needles)
    fi
}

if [ "$updateall" = 1 ]; then
    cd "$dir"
    fail=0
    for repo in *; do
        target="$dir/$repo"
        [ -h "$target" ] && continue
        [ -d "$target/.git" ] || continue
        (cd "$target" && do_fetch "$target") || fail=1
    done
    exit "$fail"
else
    target="$dir/$dist"
    mkdir -p "$target"
    cd "$target"
    if [ ! -d .git ]; then
        echo "cloning $giturl shallow. Call 'git fetch --unshallow' for full history"
        [[ $branch ]] && branch_args=(-b "$branch")
        git clone --depth 1 "${branch_args[@]}" "$giturl" .
        git config user.email "$email"
        git config user.name "$username"
        if [ "$needles_separate" = 1 ]; then
            needlesdir=$(needlesdir)
            [ -d "$needlesdir" ] || mkdir "$needlesdir"
            [[ $needles_branch ]] && needles_branch_args=(-b "$needles_branch")
            cd "$needlesdir"
            git clone --depth 1 "${needles_branch_args[@]}" "$needles_giturl" .
            git config user.email "$email"
            git config user.name "$username"
        fi
        if [ "$git_lfs" = 1 ]; then
            git lfs install --local
        fi
    else
        do_fetch "$target"
    fi
fi
