#!/bin/sh -efu
#
# Copyright (C) 2023 Evgeny Sinelnikov <sin@altlinux.org>,
#
# The distro_check utility.
#
# This file 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 2 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#

. distro-check-functions

distro_check_d='/etc/distro_check/check.d'

check_list=
recurse_subdir=
distros=1
license=

# cummulative check
fast_check=
check_work_dir=
run_checks()
{
	local f="$1" && shift || return 1
	local rc=0 check check_var
	local fname=$(basename "$f")
	local check_work_dir=$(mktemp -d --suffix ".$fname" -p "$work_dir")

	for check in $check_list; do
		[ -s "$distro_check_d/$check" ] ||
			Fatal "$f: file not found or empty"

		check_var="no_check_${check#*-check-}"
		eval "[ -z \"\${$check_var-}\" ]" || continue

		[ -d "$check_work_dir" ] ||
			Fatal "$f: failed to create check work directory"

		if ! (. "$distro_check_d/$check" && run_check "$f"); then
			[ -z "$fast_check" ] || return 1
			rc=1
		fi
	done

	return $rc
}

check_distros()
{
	init_check || Fatal 'init_check failed.'

	local f rc=0
	for f; do
		if [ ! -f "$f" ]; then
			FileError 'not a regular file' "$f"
			rc=1
			continue
		fi

		if ! get_distro_type "$f"; then
			FileError 'unexpected file type' "$f"
			rc=1
			continue
		fi

		run_checks "$f" || rc=1
	done

	return $rc
}

check_dirs()
{
	local rc=0

	# quick arg check.
	local d
	for d; do
		[ -d "$d" ] || { FileError "$d: not a directory"; rc=1; continue; }
	done
	[ $rc = 0 ] || return $rc

	for d; do
		[ -d "$d" ] || { FileError "$d: not a directory"; rc=1; continue; }
		local filelist f
		if [ -n "$recurse_subdir" ]; then
			filelist="$(find "$d" -mindepth 1 -not -type d)" || { rc=1; continue; }
		else
			filelist="$(find "$d" -mindepth 1 -maxdepth 1)" || { rc=1; continue; }
		fi

		[ -n "$filelist" ] || continue

		check_distros $filelist || rc=1
	done

	return $rc
}

get_check_list()
{
	find "$distro_check_d" \
		-regextype posix-egrep \
		-mindepth 1 \
		-maxdepth 1 \
		-type f \
		-regex '.*/[0-9]+-check-[[:alpha:]_]+' \
		-printf '%f\n'
}

expand_check_list()
{
	local list="$1"; shift
	if [ -z "${list#[Aa][Ll][Ll]}" ]; then
		printf %s "$check_env" |sed 's/^check-//'
	else
		printf %s "$list" |tr , ' '
	fi
}

show_usage()
{
	[ -z "$*" ] || Info "$*"
	echo "Try \`$PROG --help' for more information." >&2
	exit 1
}

show_checks()
{
	local rc=0 check check_var

	for check in $check_list; do
		check_name="${check#*-check-}"
		if [ -s "$distro_check_d/$check" ]; then
			echo "$check_name"
		else
			Warning "$distro_check_d/$check: file not found or empty for '$check_name'"
			rc=1
		fi
	done

	exit $rc
}

show_help()
{
	cat <<EOF

distro_check - check distribution for acceptability for Sisyphus.

This program is free software, covered by the GNU General Public License.
distro_check comes with ABSOLUTELY NO WARRANTY, see license for details.

Usage: $PROG [options] <target>...

Valid options are:
  --quiet                  try to be more quiet;
  --verbose                print a message for each action;
  --fast-check             stop checking after first error;
  --show-checks            show list of available checks;
  --license                distro license type to check;
  --distros                treat <target> as a distribution.
                           This is default behavior;
  --directories            treat <target> as a directory.
                           Distros in this directory will be checked;
  --recursive              search packages recursively;
  --show-bad-distros       print bad distributions;
  --[no-]check=LIST        change the list of checks;
EOF
	printf %s\\n "$check_env" |sed -n 's/.*/  --[no-]&/pg'
	exit
}

check_list="$(get_check_list)"
check_env="$(printf %s\\n "$check_list" |sed 's/^[0-9]\+-//' |sort -u)"
getopt_check="$(printf %s "$check_env" |tr -s '[:space:]' ',')"
getopt_no_check="$(printf %s "$check_env" |sed 's/.*/no-&/' |tr -s '[:space:]' ',')"
TEMP=`getopt -n $PROG -o h,q,v -l help,quiet,verbose,fast-check,show-checks,distros,license:,directories,show-bad-distros,recursive,check:,no-check:,check-,no-check-,$getopt_check,$getopt_no_check -- "$@"` || show_usage
eval set -- "$TEMP"

while :; do
	case "$1" in
		--check|--no-check)
			mode="$1"
			shift
			check_value=
			[ -n "${mode##--no-check*}" ] || check_value=1
			if [ -n "$(printf %s "$1" |tr -d '[:alpha:],[:space:]')" ]; then
				Info "$mode: invalid argument: $1"
				show_usage
			fi
			for arg in `expand_check_list "$1"`; do
				if ! printf '%s' "$check_env" |grep -qs "^check-$arg\$"; then
					Info "$mode: invalid argument: $arg"
					show_usage
				fi
				eval no_check_$arg=$check_value
			done
			;;
		--check-|--no-check-) show_usage
			;;
		--check-[a-z]*)
			arg="no_check_${1##--check-}"
			eval $arg=
			;;
		--no-check-[a-z]*)
			arg="no_check_${1##--no-check-}"
			eval $arg=1
			;;
		-q|--quiet) quiet=-q
			;;
		-v|--verbose) quiet=
			;;
		--fast-check) fast_check=1
			;;
		--show-checks) show_checks
			;;
		--distros) distros=1
			;;
		--license) shift; license="$1"
			;;
		--directories) distros=
			;;
		--show-bad-distros) show_bad_distros=1
			;;
		--recursive) recurse_subdir=1
			;;
		-h|--help) show_help
			;;
		--) shift; break
			;;
		*) Fatal "unrecognized option: $1"
			;;
	esac
	shift
done

# At least one argument, please.
if ! [ "$#" -ge 1 ]; then
	Info 'Insufficient arguments.'
	show_usage
fi

if [ -z "$license" ]; then
	no_check_license=1
	Warning "skip license check"
fi

if [ -n "$distros" ]; then
	check_distros "$@"
else
	check_dirs "$@"
fi
