#!/usr/bin/env bash
# check that go vet passes

echo running "$0"

#ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"	# dir!
ROOT=$(dirname "${BASH_SOURCE}")/..
cd "${ROOT}"
. test/util.sh

make --quiet -C test	# run make in test directory to prepare any needed tools

failures=''
function run-test()
{
	$@ || failures=$( [ -n "$failures" ] && echo "$failures\\n$@" || echo "$@" )
}

GO_VERSION=($(go version))

function typos() {
	if grep -i 'reversable' "$1"; then	# the word is "reversible"
		return 1
	fi
	return 0
}

function simplify-gocase() {
	if grep 'case _ = <-' "$1"; then
		return 1	# 'case _ = <- can be simplified to: case <-'
	fi
	return 0
}

function token-coloncheck() {
	# add quotes to avoid matching three X's
	#if grep -Ei "[\/]+[\/]+[ ]*(T"'O''D'"O[^:]|F"'I''X''M'"E[^:]|X"'X'"X[^:])" "$1"; then
	if grep -Ei "[\/]+[\/]+[\ 0-9a-zA-Z_@\*\?\'\(\)\{\}-]*(T"'O''D'"O[^:]|F"'I''X''M'"E[^:]|X"'X'"X[^:])" "$1"; then # not perfect
		return 1	# tokens must end with a colon
	fi
	# tokens must be upper case
	if grep -E "[t][Oo][Dd][Oo]|[Tt][o][Dd][Oo]|[Tt][Oo][d][Oo]|[Tt][Oo][Dd][o]|[f][Ii][Xx][Mm][Ee]|[Ff][i][Xx][Mm][Ee]|[Ff][Ii][x][Mm][Ee]|[Ff][Ii][Xx][m][Ee]|[Ff][Ii][Xx][Mm][e]|[x][Xx][Xx]|[Xx][x][Xx]|[Xx][Xx][x]" "$1"; then
		return 1
	fi
	return 0
}

function naked-error() {
	# the $ before the \t magically makes grep match the tab somehow...
	if grep $'\terrors.New(' "$1"; then	# missing a leading return
		return 1
	fi
	if grep $'\tfmt.Errorf(' "$1"; then	# missing a leading return
		return 1
	fi
	if grep $'\terrwrap.Wrap' "$1"; then	# missing a leading return
		return 1
	fi
	return 0
}

# catch errors that start with a capital
function lowercase-errors() {
	if grep -E 'errors\.New\("[A-Z]' "$1"; then
		return 1
	fi
	if grep -E 't\.Error\("[A-Z]' "$1"; then # t.Error
		return 1
	fi
	if grep -E 't\.Errorf\("[A-Z]' "$1"; then # t.Errorf or fmt.Errorf
		return 1
	fi
	if grep -E 't\.Fatal\("[A-Z]' "$1"; then # t.Fatal
		return 1
	fi
	if grep -E 't\.Fatalf\("[A-Z]' "$1"; then # t.Fatalf
		return 1
	fi
	# TODO: add errwrap.Wrap* related matching
	return 0
}

function consistent-imports() {
	if [ "$1" = './util/errwrap/errwrap.go' ]; then
		return 0
	fi

	# import as github.com/purpleidea/mgmt/util/errwrap
	if grep $'\t"github.com/pkg/errors"' "$1"; then
		return 1
	fi
	# import as github.com/purpleidea/mgmt/util/errwrap
	if grep $'\t"github.com/hashicorp/go-multierror"' "$1"; then
		return 1
	fi
	# import as *Util (should be fooUtil) with util capitalized
	if grep $'util "github.com/purpleidea/mgmt"' "$1"; then
		return 1
	fi
	# import as langUtil
	if grep $'\t"github.com/purpleidea/mgmt/lang/util"' "$1"; then
		return 1
	fi
	# import as engineUtil
	if grep $'\t"github.com/purpleidea/mgmt/engine/util"' "$1"; then
		return 1
	fi
	# import as cliUtil
	if grep $'\t"github.com/purpleidea/mgmt/cli/util"' "$1"; then
		return 1
	fi
	if grep '"golang.org/x/net/context"' "$1"; then	# use built-in context
		return 1
	fi

	# deprecated import
	if grep $'\t"io/ioutil"' "$1"; then # use the documented replacements
		return 1
	fi
}

function reflowed-comments() {
	if [ "$1" = './lang/core/generated_funcs.go' ]; then
		return 0
	fi

	if [ "$1" = './lang/parser/y.go' ]; then
		return 0
	fi

	if [ "$1" = './lang/parser/lexer.nn.go' ]; then
		return 0
	fi

	if [ "$1" = './lang/interpolate/parse.generated.go' ]; then
		return 0
	fi

	# Name this to match the function so it's easy to run this by itself.
	./test/reflowed-comments "$1"
}

function receiver-check() {
	if [ "$1" = './lang/core/generated_funcs.go' ]; then
		return 0
	fi

	if [ "$1" = './lang/parser/y.go' ]; then
		return 0
	fi

	if [ "$1" = './lang/parser/lexer.nn.go' ]; then
		return 0
	fi

	if [ "$1" = './lang/interpolate/parse.generated.go' ]; then
		return 0
	fi

	./test/receiver-check "$1"
}

# run go vet on the package list in one invocation
base=$(go list .)
packages=()
for pkg in `go list -e ./... | grep -v "^${base}/vendor/" | grep -v "^${base}/examples/" | grep -v "^${base}/test/" | grep -v "^${base}/old" | grep -v "^${base}/old/" | grep -v "^${base}/tmp" | grep -v "^${base}/tmp/"`; do

	if [ "$pkg" = "${base}/engine/resources/http_server_ui" ]; then
		continue # skip this special main package
	fi

	packages+=("$pkg")

done
if [ "${#packages[@]}" -gt 0 ]; then
	echo -e "\tgo vet: ${#packages[@]} packages"
	go vet -source "${packages[@]}" || failures=$( [ -n "$failures" ] && echo "$failures\\ngo vet -source (${#packages[@]} packages)" || echo "go vet -source (${#packages[@]} packages)" )
fi

# loop through individual *.go files
for file in `find . -maxdepth 9 \( -type f -o -type l \) -name '*.go' -not -path './old/*' -not -path './tmp/*' -not -path './vendor/*' -not -path './sites/*'`; do
	#if [[ $file == "./vendor/"* ]]; then # skip files that start with...
	#	continue
	#fi
	run-test grep 'log.Print' "$file" | grep '\\n"' && fail_test 'no newline needed in log.Print*()'	# no \n needed in log.Printf or log.Println
	run-test typos "$file"
	run-test simplify-gocase "$file"
	run-test token-coloncheck "$file"
	run-test naked-error "$file"
	run-test lowercase-errors "$file"
	run-test consistent-imports "$file"
	run-test reflowed-comments "$file"
	run-test receiver-check "$file"
done

if [[ -n "$failures" ]]; then
	echo 'FAIL'
	echo 'The following tests have failed:'
	echo -e "$failures"
	echo
	exit 1
fi
echo 'PASS'
