#!/bin/sh
export LC_ALL=C

# Finds from which repo a package comes from
# it can return multiple values if it finds multiple matches
find_repo() {
	[ -z "$1" ] || [ -z "$2" ] && return 0

	local pkgname="$1"
	# Repo the package we are linting currently is. We want it
	# for avoiding checks on repos we don't want
	local targetrepo="$2"

	# Unmaintained is the top of the ladder, it can depend on any
	# of the steps below
	if [ "$targetrepo" = "unmaintained" ]; then
		return 0
	fi

	# Perform some transformations that can be done easily and cheaply
	# and are common.
	#
	# This is a hack until apk has something like xpkg -m or aports adopt
	# the xbps-src symlinks
	pkgname="${pkgname%-dev}"
	pkgname="${pkgname%-doc}"
	pkgname="${pkgname%-openrc}"
	pkgname="${pkgname%-bash-completion}"
	pkgname="${pkgname%-zsh-completion}"
	pkgname="${pkgname%-fish-completion}"
	# Disabled because it can cause conflicts with -dev packages, there is glade and libglade
	# which are separate packages but end up causing false-postiives
	# pkgname="${pkgname#lib}"
	pkgname="${pkgname%-static}"
	pkgname="${pkgname%-lang}"

	check_in_repo() { test -d "$1"/"$2" && echo "$1" ; }

	case "$targetrepo" in
		testing) 
			check_in_repo unmaintained "$pkgname"
			;;
		community)
			check_in_repo unmaintained "$pkgname"
			check_in_repo testing "$pkgname"
			;;
		main)
			check_in_repo unmaintained "$pkgname"
			check_in_repo testing "$pkgname"
			check_in_repo community "$pkgname"
			;;
	esac
}

find_dupe() {
	local pkgname="$1" repo="$2" r=

	check_in_repo() { test -d "$1"/"$2" && echo "$1" ; }

	for r in unmaintained testing community main; do
		[ "$r" = "$repo" ] && continue
		check_in_repo "$r" "$pkgname"
	done
}

upper_repo_depends() {
	[ "$SKIP_UPPER_REPO_DEPENDS" ] && return 0
	[ "$SKIP_AL16" ] && return 0
	printf "%s\n" "$depends" | tr " " "\n" | tr -d "\t" | sort -u | while read -r pkg; do
		for p in $(find_repo "$pkg" "$_repo"); do
			printf "SC:[AL17]:$apkbuild::depends '$pkg' is in upper repo '$p'\n"
		done
	done
}

duplicate_depends() {
	[ "$SKIP_DUPLICATE_DEPENDS" ] && return 0
	[ "$SKIP_AL17" ] && return 0
	printf "%s\n" "$depends" | tr " " "\n" | tr -d "\t" | sort | uniq -d | while read -r dup; do
		[ -z "$dup" ] && continue
		printf "MC:[AL17]:$apkbuild::duplicate '$dup' in depends\n"
	done
}

upper_repo_makedepends() {
	[ "$SKIP_UPPER_REPO_MAKEDEPENDS" ] && return 0
	[ "$SKIP_AL18" ] && return 0
	printf "%s\n" "$makedepends" | tr " " "\n" | tr -d "\t" | sort -u | while read -r pkg; do
		for p in $(find_repo "$pkg" "$_repo"); do
			printf "SC:[AL18]:$apkbuild::makedepends '$pkg' is in upper repo '$p'\n"
		done
	done
}

duplicate_makedepends() {
	[ "$SKIP_DUPLICATE_MAKEDEPENDS" ] && return 0
	[ "$SKIP_AL19" ] && return 0
	printf "%s\n" "$makedepends" | tr " " "\n" | tr -d "\t" | sort | uniq -d | while read -r dup; do
		[ -z "$dup" ] && continue
		printf "MC:[AL19]:$apkbuild::duplicate '$dup' in makedepends\n"
	done
}

upper_repo_checkdepends() {
	[ "$SKIP_UPPER_REPO_CHECKDEPENDS" ] && return 0
	[ "$SKIP_AL20" ] && return 0
	printf "%s\n" "$checkdepends" | tr " " "\n" | tr -d "\t" | sort -u | while read -r pkg; do
		for p in $(find_repo "$pkg" "$_repo"); do
			printf "SC:[AL20]:$apkbuild::checkdepends '$pkg' is in upper repo '$p'\n"
		done
	done
}

duplicate_checkdepends() {
	[ "$SKIP_DUPLICATE_CHECKDEPENDS" ] && return 0
	[ "$SKIP_AL21" ] && return 0
	printf "%s\n" "$checkdepends" | tr " " "\n" | tr -d "\t" | sort | uniq -d | while read -r dup; do
		[ -z "$dup" ] && continue
		printf "MC:[AL21]:$apkbuild::duplicate '$dup' in checkdepends\n"
	done
}

duplicate_package() {
	[ "$SKIP_DUPLICATE_PACKAGE" ] && return 0
	[ "$SKIP_AL22" ] && return 0
	for _r in $(find_dupe "$pkgname" "$_repo"); do
		printf "SC:[AL22]:$apkbuild::package is already present in $_r\n"
	done
}

pkgname_dirname_mismatch() {
	[ "$SKIP_PKGNAME_DIRNAME_MISMATCH" ] && return 0
	[ "$SKIP_AL23" ] && return 0
	local _dirname=
	case "${apkbuild%%/*}" in
		main|community|testing|unmaintained|non-free)
			_dirname="${apkbuild%/*}"
			_dirname="${_dirname##*/}"
			;;
		*) return 0 ;;
	esac
	if [ "$pkgname" != "$_dirname" ]; then
		printf "IC:[AL23]:$apkbuild::pkgname is '$pkgname' but is in directory '$_dirname'\n"
	fi
}

depends_makedepends_checkdepends_overlap() {
	[ "$SKIP_DEPENDS_MAKEDEPENDS_CHECKDEPENDS_OVERLAP" ] && return 0
	[ "$SKIP_AL24" ] && return 0
	local _mkdeps _ckdeps d
	_mkdeps="$(echo $makedepends | tr " " "\\n" | tr -d "\t" | sort -u)"
	_ckdeps="$(echo $checkdepends | tr " " "\\n" | tr -d "\t" | sort -u)"
	[ -z "$_mkdeps" ] && [ -z "$_ckdeps" ] && return 0
	for d in $depends; do
		if printf "%s\\n" "$_mkdeps" | grep -q "^$d$"; then
			printf "IC:[AL24]:%s::dependency '%s' is in depends and makedepends\n" "$apkbuild" "$d"
		fi

		# Don't check against checkdepends if it is empty
		[ -z "$checkdepends" ] && continue
		if printf "%s\\n" "$_ckdeps" | grep -q "^$d$"; then
			printf "IC:[AL24]:%s::dependency '%s' is in depends and checkdepends\n" "$apkbuild" "$d"
		fi
	done

	# Don't check against checkdepends if it is empty, no need to check for
	# makedepends because the loop just won't run if it is empty.
	[ -z "$checkdepends" ] && return 0
	for d in $makedepends; do
		if printf "%s\\n" "$_ckdeps" | grep -q "^$d$"; then
			printf "IC:[AL24]:%s::dependency '%s' is in makedepends and checkdepends\n" "$apkbuild" "$d"
		fi
	done
}

for apkbuild; do
	if [ -f "$apkbuild" ]; then

	# Try to guess the repo, first see if our working directory is where
	# the repo is located
	_repo="${PWD%/*}"
	_repo="${_repo%/*}"
	_repo="${_repo##*/}"
	case "$_repo" in
		main|community|testing|unmaintained) ;;
		# Then have the path given to use be used
		*)
			_repo="${apkbuild%/*}"
			_repo="${_repo%/*}"
			_repo="${_repo##*/}"
			;;
	esac

	# Source apkbuild, we need some nice values
	srcdir="" . "$apkbuild" || {
		echo "Failed to source APKBUILD in '$apkbuild'" ;
		continue
	}

	if [ ! -z "$depends" ]; then
		upper_repo_depends &
		duplicate_depends &
	fi
	
	# This can be run if either 2 of the 3 are not empty
	# depends makedepends checkdepends
	depends_makedepends_checkdepends_overlap &

	if [ ! -z "$makedepends" ]; then
		upper_repo_makedepends &
		duplicate_makedepends &
	fi

	if [ ! -z "$checkdepends" ]; then
		if [ -z "$options" ] || [ ! -z "${options##*!check*}" ]; then
			upper_repo_checkdepends &
		fi
		duplicate_checkdepends &
	fi

	if [ -z "$SKIP_DUPLICATE_PACKAGE" ]; then
		duplicate_package &
	fi

	pkgname_dirname_mismatch &

	wait

	else
	echo no such apkbuild "$apkbuild" 1>&2
	fi | sort -t: -n -k2 | grep . && ret=1
done
exit $ret
