#!/bin/bash -e
# setup/update system ready for building appliances

fatal() { echo "FATAL [$(basename $0)]: $@" 1>&2; exit 1; }
warning() { echo "WARNING [$(basename $0)]: $@"; }
info() { echo "INFO [$(basename $0)]: $@"; }

usage() {
    exit_code=0
    if [[ $# -ge 1 ]]; then
        echo "FATAL: $@"
        exit_code=1
    fi
    cat <<EOF
$(basename $0): [-h|--help] [APP] [... APP]

Tool to initialize and maintain TKLDev

Options:
    -f|--force      If the branch to be updated is not already checked out,
                    rather than skip, it will be checked out (no updates if
                    repo dirty)*
    -n|--full-clone Full clone (rather than default shallow clone)*
    -h|--help       Show this help and exit

*- only applies to git repos listed below

The default action is to download the bootstrap (if it doesn't already exist)
and clone (or update) the following repos (to the corresponding paths):

    turnkeylinux/buildtasks $BT_PATH (\$BT_PATH - branch:$BRANCH)
    turnkeylinux/tklbam-profiles /turnkey/tklbam-profiles (branch:master)
    turnkeylinux/common $FAB_PATH/common (\$FAB_PATH/common) (branch:$BRANCH)
    turnkeylinux-apps/APP $FAB_PATH/products/APP (branch:master)
    turnkeylinux/cdroots $FAB_PATH/cdroots (amd64 only - branch:$BRANCH)

The 'fab' apt package will be updated when possible (to the latest available).

If the repos are dirty (uncommited files) they are skipped, if they have an
alternate branch checked out, they will be skipped (unless -f|--force used).

Env vars:

    FAB_PATH    Fab PATH (default: $FAB_PATH)
    BT_PATH     Buildtasks PATH (default: $BT_PATH)
    RELEASE     Release to target - e.g. debian/bookworm (default: $RELEASE)
    ARCH        Arch to target (default: $ARCH)
    BRANCH      Branch to checkout (default: $BRANCH)
    GIT_DEPTH   Depth to clone (default: $GIT_DEPTH) - setting to 'full' gives
                same behavior as -n|--full-clone
    DEBUG       Verbose output (useful for debugging)

EOF
    exit $exit_code
}

[[ -z "$DEBUG" ]] || set -x
[[ $(id -u) -eq 0 ]] || fatal "Root user required."

GIT_DEPTH=${GIT_DEPTH:-1}
APP="${@}"
[[ -n "$APP" ]] || APP="core"

distro="$(lsb_release -si)"
if [[ "${distro,,}" == "turnkey" ]] || [[ "${distro,,}" == "debian" ]]; then
   distro="debian"
fi
tkl_ver=$(turnkey-version -t)
unset FORCE

export RELEASE="${RELEASE:-${distro}/$(lsb_release -s -c)}"
export CODENAME="$(basename $RELEASE)"
export ARCH="${ARCH:-$(dpkg --print-architecture)}"
export BRANCH="${tkl_ver::2}.x"
IMAGES="http://mirror.turnkeylinux.org/turnkeylinux/images"
FAB_PATH="${FAB_PATH:-/turnkey/fab}"
BOOTSTRAP_NAME="bootstrap-${CODENAME}-${ARCH}"
BOOTSTRAP_PATH="$FAB_PATH/bootstraps/${CODENAME}"
BT_PATH="${BT_PATH:-/turnkey/buildtasks}"
BT_VERIFY="$BT_PATH/bin/signature-verify"

update_repo() {
    dst=$1
    git_dir=$dst/.git
    repo=$2
    branch=$3
    _git="git --git-dir=$git_dir --work-tree=$dst"
    remote="$($_git remote -v | grep -m1 "$repo" | cut -f1)"
    if [[ -n "$($_git status -s)" ]]; then
        warning "$dst has uncommitted files, skipping."
        return
    fi
    current_branch=$($_git branch --show-current)
    if ! $_git fetch $remote; then
        warning "($dst) Fetching remote: $remote failed, skipping."
        return
    fi
    if [[ "$current_branch" != "$branch" ]]; then
        if [[ -n "$FORCE" ]]; then
            warning "Force used - attempting to checkout $branch"
            if ! $_git checkout $branch && ! $_git checkout $branch-dev; then
                warning "($dst) Checking out '$branch' failed, skipping."
                return
            fi
        elif [[ "${current_branch}" =~ [0-9]\.x ]]; then
            if [[ "${current_branch::4}" == "$branch" ]]; then
                warning "($dst) current checked out branch is $current_branch"\
                        " attempting to checkout $branch"
                if ! $_git checkout $branch; then
                    warning "($dst) checkout failed - skipping"
                    return
                fi
            fi
        else
            warning "($dst) current checked out branch is $current_branch"\
                    " (not $branch) so skipping"
            return
        fi
    fi
    if ! $_git pull $remote $branch; then
        warning "($dst) Updating '$branch' failed, skipping."
        return
    fi
}

clone_or_update() {
    repo=$1
    src=https://github.com/$repo
    dst=$2
    branch=$3
    git_depth=""
    branch_arg=""
    [[ "$GIT_DEPTH" == "full" ]] || git_depth="--depth $GIT_DEPTH"
    mkdir -p $(dirname $dst)
    if [[ -n "$branch" ]]; then
        branch_arg="--branch $branch"
        branch_dev_arg="--branch $branch-dev"
    else
        branch='master'
    fi
    if [[ -d "$dst" ]]; then
        if [[ -d "$dst/.git" ]]; then
            info "$dst exists and is a git repo, attempting update."
            update_repo $dst $repo $branch
        else
            warning "$dst exists, but is not a git repo - skipping."
            return
        fi
    else
        info "Attempting to clone $src into $dst."
        if ! git clone $branch_arg $git_depth $src $dst; then
           warning "Cloning $branch failed, trying $branch-dev"
           if ! git clone $branch_dev_arg $git_depth $src $dst; then
                warning "Cloning $dst failed, skipping."
                return
           fi
        fi
    fi
}

APPS=''
while [[ "$#" -gt 0 ]]; do
    case $1 in
        -h|--help)
            usage
            ;;
        -f|--force)
            FORCE=y
            shift
            ;;
        -n|--full-clone)
            GIT_DEPTH='full'
            shift
            ;;
        *)
            APPS="$APPS $1"
            shift
            ;;
    esac
done

clone_or_update turnkeylinux/buildtasks $BT_PATH $BRANCH
clone_or_update turnkeylinux/tklbam-profiles /turnkey/tklbam-profiles
clone_or_update turnkeylinux/common $FAB_PATH/common $BRANCH
for app in $APPS; do
    clone_or_update turnkeylinux-apps/$app $FAB_PATH/products/$app
done

if [[ "${ARCH}" == "amd64" ]]; then
    clone_or_update turnkeylinux/cdroots $FAB_PATH/cdroots $BRANCH
fi

if [[ ! -d "$BT_PATH/config" ]]; then
    cp -r "$BT_PATH/config.example" "$BT_PATH/config"
fi
if [[ -f "$BT_PATH/config/common.cfg" ]]; then
    . $BT_PATH/config/common.cfg
else
    fatal "$BT_PATH config not found, unable to determine GPG key ID (BT_GPGKEY)."
fi

info "Updating apt database"
apt-get update -qq
info "Installing newer fab version (if available)"
DEBIAN_FRONTEND=noninteractive apt-get install -y fab

if [[ -d "$BOOTSTRAP_PATH" ]]; then
    info "$BOOTSTRAP_PATH exists, skipping download."
else
    errmsg=''
    info "Downloading $BOOTSTRAP_NAME"
    mkdir -p $(dirname $BOOTSTRAP_PATH)
    cd $(dirname $BOOTSTRAP_PATH)
    bootstrap_file=$BOOTSTRAP_PATH
    wget -nc -nv $IMAGES/bootstrap/$BOOTSTRAP_NAME.tar.gz \
        || fatal "Downloading $BOOTSTRAP_NAME failed."
    wget -nc -nv $IMAGES/bootstrap/$BOOTSTRAP_NAME.tar.gz.hash \
        || fatal "Downloading $BOOTSTRAP_NAME hash file failed."
    if [[ -f "$BT_VERIFY" ]]; then
        bootstrap_file=$(dirname $BOOTSTRAP_PATH)/$BOOTSTRAP_NAME.tar.gz
        BT_DEBUG=$DEBUG $BT_VERIFY --force-gpg $bootstrap_file $bootstrap_file.hash
    else
        fatal "$BT_VERIFY script not found, unable to verify downloaded files."
    fi
    info "Unpacking $BOOTSTRAP_NAME"
    mkdir $BOOTSTRAP_PATH
    tar -zxf $BOOTSTRAP_NAME.tar.gz -C $BOOTSTRAP_PATH
fi
info "$(basename $0) complete."
