#!/bin/bash

# Copyright (C) 2018, Xavier <yadd@debian.org>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# On Debian systems, the complete text of the GNU General Public License
# version 3 can be found in the /usr/share/common-licenses/GPL-3 file.

set -u
#set -x

TESTTYPE=Git
. ./lib_test_uscan

COMMAND="chronic_sh uscan --no-conf --compression=xz --dehs"

# prevent the local from messing with this test
export GIT_CONFIG_NOGLOBAL=1
export HOME=""
export XDG_CONFIG_HOME=""

# comment out for debug
#COMMAND="$COMMAND --verbose"
#COMMAND="$COMMAND --debug"

cleanup(){
    rm -rf "$TEMP_PKG_DIR"
}

spawnGitDaemon() {
    [ -n "$TEMP_PKG_DIR" ] || fail "unexpected testsuite error"
    (
        local srv=${1:-srv}
        mkdir -p "$TEMP_PKG_DIR/$srv" || exit 1
        chronic_sh git daemon --base-path="$TEMP_PKG_DIR/$srv" \
            --reuseaddr --detach \
            --pid-file="$TEMP_PKG_DIR/$srv/pid"
        local t=0
        while [ ! -s "$TEMP_PKG_DIR/$srv/pid" ]; do
            sleep 1s
            if [ $t -gt 5 ]; then
                echo "git daemon failed to start"
                exit 1
            fi
            t=$((t+1))
        done
    )
}

killGitDaemon() {
    local srv=${1:-srv}
    if [ -n "$TEMP_PKG_DIR" ] && [ -s "$TEMP_PKG_DIR/$srv/pid" ]; then
        local pid=$(< "$TEMP_PKG_DIR/$srv/pid")
        kill -9 "$pid"
    fi
}

spawnGitRepo() {
    local repo=${1:-repo}
    mkdir -p "$TEMP_PKG_DIR/$repo"
    (cd "$TEMP_PKG_DIR/$repo" || exit 1
    chronic_sh git init
    git config user.name "Joe Developer"
    git config user.email "none@debian.org"
    touch changelog file.c extra.c
    echo 'extra.c export-ignore' >.gitattributes
    chronic_sh git add changelog file.c extra.c .gitattributes
    chronic_sh git commit -a -m 'Init'
    for version in 1.0 2.0; do
        echo "# Version $version" >> file.c
        cat >> changelog <<END
Version $version

END
        chronic_sh git commit -a -m "Releasing $version"
        chronic_sh git tag -s -u 72543FAF -m "Version $version" "v$version"
    done)
}

cleanup () {
    killGitDaemon
    rm -rf "$TEMP_PKG_DIR"
}

trap cleanup EXIT

containsName(){
  echo "$1" | grep -F -q "$2"
  echo $?
}

# shellcheck source=shunit2-helper-functions.sh
. "${0%/*}/shunit2-helper-functions.sh"

PKG=foo

writeDebianWatch() {
    local watchargs="$1"
    local gitref=${2:-"refs/tags/v([\\d\\.]+)"}
    cat <<END > "$TEMP_PKG_DIR/$PKG/debian/watch"
version=4
opts="mode=git, $watchargs" \
file:///$TEMP_PKG_DIR/repo $gitref debian
END
}

makeDebianDir() {
    TEMP_PKG_DIR=$(mktemp -d --tmpdir="$SHUNIT_TMPDIR" uscan_git.XXXXXX)
    if [ -z "$TEMP_PKG_DIR" ]; then
        echo "Failed to create temporary directory" >&2
        exit 1
    fi
    mkdir -p "$TEMP_PKG_DIR"/$PKG/debian/upstream
    mkdir -p "$TEMP_PKG_DIR"/$PKG/debian/source

    writeDebianWatch "$1" "${2:-}"

    cat <<END > "$TEMP_PKG_DIR/$PKG/debian/changelog"
$PKG (0-1) unstable; urgency=low

  * Initial release

 -- Joe Developer <jd@debian.org>  Mon, 02 Nov 2013 22:21:31 -0100
END
    echo '3.0 (quilt)' > "$TEMP_PKG_DIR/$PKG/debian/source/format"
    cp -f "$test_dir/uscan/PUBLIC_KEY.asc" "$TEMP_PKG_DIR/$PKG/debian/upstream/signing-key.asc"
}

makeDebianDirWithUpstream() {
    makeDebianDir "$1"
    spawnGitRepo
    cd "$TEMP_PKG_DIR/$PKG" || exit 1
    chronic_sh git init
    chronic_sh git remote add upstream "file:///$TEMP_PKG_DIR/repo"
    chronic_sh git fetch upstream
    cd - > /dev/null || exit 1
}

runTest() {
    local cmd_arg="${1:-}"
    ( cd "$TEMP_PKG_DIR/$PKG" || exit 1 ; $COMMAND $cmd_arg --watchfile=debian/watch )
    assertEquals "uscan: exit_code!=0 but exit_code=0" "$?" "0"
}

testGit() {
    makeDebianDir "gitmode=shallow, pgpmode=none"
    spawnGitRepo
    runTest
    local tarball=${PKG}_2.0.orig.tar.xz
    assertTrue 'downloaded tarfile not present' "[ -f '$TEMP_PKG_DIR/${PKG}-2.0.tar.xz' ]"
    assertTrue 'pristine tarball not created' "[ -f '$TEMP_PKG_DIR/$tarball' ]"
    assertTrue 'pristine tarball should be a symlink' "[ -L '$TEMP_PKG_DIR/$tarball' ]"
    cleanup
}

testGitHead() {
    makeDebianDir "pgpmode=none, pretty=0.0+git%cd.%h" "HEAD"
    spawnGitRepo
    runTest
    local orig=$(find "$TEMP_PKG_DIR" | perl -ne 'print if/\/foo.*\.orig\.tar\.xz$/')
    local upstream=$(find "$TEMP_PKG_DIR" | perl -ne 'print if/\/foo.*(?<!orig)\.tar\.xz$/')
    assertTrue 'downloaded tarfile not present' "[ -f '$upstream' ]"
    assertTrue 'pristine tarball not created' "[ -f '$orig' ]"
    assertTrue 'pristine tarball should be a symlink' "[ -L '$orig' ]"
    cleanup
}

testGitIgnoreExclusions() {
    makeDebianDir "gitmode=shallow, gitexport=all"
    spawnGitRepo
    runTest
    assertTrue 'downloaded tarball is incomplete' \
        "tar tf '$TEMP_PKG_DIR/${PKG}-2.0.tar.xz' '${PKG}-2.0/extra.c'"
    cleanup
}

testGitSignedTag() {
    makeDebianDir "gitmode=shallow, pgpmode=gittag"
    spawnGitRepo
    runTest
    local tarball=${PKG}_2.0.orig.tar.xz
    assertTrue 'downloaded tarfile not present' "[ -f '$TEMP_PKG_DIR/${PKG}-2.0.tar.xz' ]"
    assertTrue 'pristine tarball not created' "[ -f '$TEMP_PKG_DIR/$tarball' ]"
    assertTrue 'pristine tarball should be a symlink' "[ -L '$TEMP_PKG_DIR/$tarball' ]"
    cleanup
}

testGitSignedTagWithDestDir() {
    makeDebianDir "gitmode=shallow, pgpmode=gittag"
    spawnGitRepo
    local destdir=$TEMP_PKG_DIR/destdir
    mkdir -p $destdir
    runTest "--destdir $TEMP_PKG_DIR/destdir"
    local tarball=${PKG}_2.0.orig.tar.xz
    assertTrue 'downloaded tarfile not present' "[ -f '$destdir/${PKG}-2.0.tar.xz' ]"
    assertTrue 'pristine tarball not created' "[ -f '$destdir/$tarball' ]"
    assertTrue 'pristine tarball should be a symlink' "[ -L '$destdir/$tarball' ]"
    cleanup
}

testGitUncompressed() {
    makeDebianDir "gitmode=shallow, pgpmode=none"
    spawnGitRepo
    runTest "--vcs-export-uncompressed"
    local tarball=${PKG}_2.0.orig.tar.xz
    assertTrue 'downloaded tarfile not present' "[ -f '$TEMP_PKG_DIR/${PKG}-2.0.tar' ]"
    assertTrue 'pristine tarball not created' "[ -f '$TEMP_PKG_DIR/$tarball' ]"
    assertTrue 'pristine tarball should not be a symlink' "[ ! -L '$TEMP_PKG_DIR/$tarball' ]"
    cleanup
}

testGitUpstream() {
    makeDebianDirWithUpstream "gitmode=shallow, pgpmode=none"
    runTest
    local tarball=${PKG}_2.0.orig.tar.xz
    assertTrue 'downloaded tarfile not present' "[ -f '$TEMP_PKG_DIR/${PKG}-2.0.tar.xz' ]"
    assertTrue 'pristine tarball not created' "[ -f '$TEMP_PKG_DIR/$tarball' ]"
    assertTrue 'pristine tarball should be a symlink' "[ -L '$TEMP_PKG_DIR/$tarball' ]"
    cleanup
}

testGitUpstreamSignedTag() {
    makeDebianDirWithUpstream "gitmode=shallow, pgpmode=gittag"
    runTest
    local tarball=${PKG}_2.0.orig.tar.xz
    assertTrue 'downloaded tarfile not present' "[ -f '$TEMP_PKG_DIR/${PKG}-2.0.tar.xz' ]"
    assertTrue 'pristine tarball not created' "[ -f '$TEMP_PKG_DIR/$tarball' ]"
    assertTrue 'pristine tarball should be a symlink' "[ -L '$TEMP_PKG_DIR/$tarball' ]"
    cleanup
}

testGitUpstreamIgnoreExclusions() {
    makeDebianDirWithUpstream "gitmode=shallow, gitexport=all"
    runTest
    assertTrue 'downloaded tarball is incomplete' \
        "tar tf '$TEMP_PKG_DIR/${PKG}-2.0.tar.xz' '${PKG}-2.0/extra.c'"
    cleanup
}

testGitSubmodules() {
    makeDebianDir "gitmodules"
    spawnGitRepo
    local subrepo="subrepo"
    spawnGitRepo "srv/${subrepo}.git"
    touch "$TEMP_PKG_DIR/srv/${subrepo}.git/.git/git-daemon-export-ok"
    spawnGitDaemon
    cd "$TEMP_PKG_DIR/repo" || exit 1
    chronic_sh git submodule add "git://localhost/${subrepo}.git"
    chronic_sh git commit -a -m "Add $subrepo module"
    local version="3.0"
    cat >> changelog <<END
Version $version

END
    chronic_sh git commit -a -m "Releasing $version"
    chronic_sh git tag -s -u 72543FAF -m "Version $version" "v$version"
    cd - > /dev/null || exit 1

    local tarball="${PKG}_${version}.orig.tar.xz"
    runTest
    assertTrue "downloaded tarfile not present" \
        "[ -f '$TEMP_PKG_DIR/${PKG}-${version}.tar.xz' ]"
    assertTrue "pristine tarball not created" \
        "[ -f '$TEMP_PKG_DIR/$tarball' ]"
    assertTrue "pristine tarball should be a symlink" \
        "[ -L '$TEMP_PKG_DIR/$tarball' ]"
    assertTrue "downloaded tarball is incomplete" \
        "tar -tf '$TEMP_PKG_DIR/$tarball' '${PKG}-${version}/file.c'"
    assertTrue "downloaded tarball is incomplete; ${subrepo} missing" \
        "tar -tf '$TEMP_PKG_DIR/$tarball' '${PKG}-${version}/${subrepo}/file.c'"
    assertFalse "${PKG}-${version}/extra.c should not be present" \
        "tar -tf '$TEMP_PKG_DIR/$tarball' '${PKG}-${version}/extra.c'"
    assertFalse "${PKG}-${version}/${subrepo}/extra.c should not be present" \
        "tar -tf '$TEMP_PKG_DIR/$tarball' '${PKG}-${version}/${subrepo}/extra.c'"
    # killGitDaemon() and cleanup() omitted intentionally
    rm -f "$TEMP_PKG_DIR/$tarball" "$TEMP_PKG_DIR/${PKG}-${version}.tar.xz"
}

testGitSubmodulesIgnoreExclusions() {
    writeDebianWatch "gitexport=all, gitmodules"
    runTest
    local version="3.0"
    local tarball="${PKG}_${version}.orig.tar.xz"
    local subrepo="subrepo"
    assertTrue "downloaded tarfile not present" \
        "[ -f '$TEMP_PKG_DIR/${PKG}-${version}.tar.xz' ]"
    assertTrue "pristine tarball not created" \
        "[ -f '$TEMP_PKG_DIR/$tarball' ]"
    assertTrue "pristine tarball should be a symlink" \
        "[ -L '$TEMP_PKG_DIR/$tarball' ]"
    assertTrue "downloaded tarball is incomplete" \
        "tar -tf '$TEMP_PKG_DIR/$tarball' '${PKG}-${version}/file.c' \
        '${PKG}-${version}/extra.c'"
    assertTrue "downloaded tarball is incomplete; ${subrepo} missing" \
        "tar -tf '$TEMP_PKG_DIR/$tarball' '${PKG}-${version}/${subrepo}/file.c' \
         '${PKG}-${version}/${subrepo}/extra.c'"
    killGitDaemon
    cleanup
}

# shellcheck disable=SC1091
. shunit2
