#!/usr/bin/env bash
#  Copyright (c) 2016 - 2022 by NuTyX team (http://nutyx.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 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.
#
##
usage() {
echo "
Recommended use:

You should mount the '$PROJECT' git as bind option (--bind) in your personal account

Example if your personal account is 'tnut' and
this chroot NuTyX is installed in '/mnt/lfs', proceed as follow

1. clone this project as 'tnut' user:
   cd ~
   git clone git://github.com/NuTyX/$PROJECT.git

2. your git is now in following directory:
   '/home/tnut/$PROJECT'


3. Delete this git in your chroot and create an empty folder
    rm -r /mnt/lfs/root/$PROJECT
    mkdir -p /mnt/lfs/root/$PROJECT

4. Mount your '$PROJECT' git projet as bind option INTO your chroot
    mount -o bind /home/tnut/$PROJECT /mnt/lfs/root/$PROJECT

5. Make your git operation in 'tnut' user

Option: you could add this alias into your chroot root .bashrc
    alias $COLLECTION='_() { cd $GIT; bash scripts/$COLLECTION \$@; cd -; };_ \$@'

It will make your life easier. To build any port from the collection $COLLECTION,
you will just have to type:
    $COLLECTION  <name_of_the_port>
"

}
print_help()
{
	echo "usage: $COLLECTION [option]"
	echo "options:"
	echo "   -a,   --all                 will build all the ports of the '$COLLECTION' collection in the right order"
	echo "   -l,   --list                will list all the ports of the '$COLLECTION' collection in the right order"
	echo "  -ru,   --remove-url          remove the URL part in /etc/cards.conf file for the '$COLLECTION' collection"
	echo "  -cp,   --check-ports         check if new ports are available"
	echo "  -cb,   --check-binaries      check if binaries are uptodate"
	echo "   -d,   --dry                 check if binaries are different then the ports but dont build anything"
	echo "   -s,   --sync                synchronise binaries from rsync server location"
	echo "   -c,   --config              printout the configuration"
	echo "   -h,   --help                print help and exit"
	echo "   -v,   --version             print version and exit"
	echo "   -u,   --usage               print the recommended way of using the '$COLLECTION' script"
}
list_ports() {
	cd $PORT_BASE && find . -name Pkgfile -follow -printf "%h\n" | sed 's|^./||g' | sort
}
check_binaries()
{
	check_location
	check_config_file
	if [ ! -d ${BINARY_BASE} ]; then
		echo "The directory ${BINARY_BASE} doesn't exist"
		echo "Please fix your setting in /etc/cards.conf.d/$COLLECTION.conf file"
		echo "Variable 'BINARY_BASE'"
		exit 1
	fi
	pushd ${BINARY_BASE} > /dev/null
	for DIR in *
	do
		if [ -d $DIR ]; then
			if [ ! -d $PORT_BASE/$DIR ]; then
				echo "'$DIR' should be removed and delete from the .PKGREPO file"
				rm -vr $DIR
				[ -f .PKGREPO ] && sed -i "/#$DIR#/d" .PKGREPO
			else
				rsync -au  --exclude="*cards.tar*" --exclude=".PKGREPO" --delete \
					${PORT_BASE}/$DIR/ ${BINARY_BASE}/$DIR/
			fi
		fi
	done
	cd - > /dev/null
}
check_ports()
{
	check_location
	check_config_file
	if [ ! -d ${PORT_BASE} ]; then
		echo "The directory ${PORT_BASE} doesn't exist"
		echo "Please fix your setting in /etc/cards.conf.d/$COLLECTION.conf file"
		echo "Variable 'PORT_BASE'"
		exit 1
	fi
	sync_pkgmk_conf
	pushd ${PORT_BASE} > /dev/null
	for DIR in *
	do
		if [ ! -d ${BINARY_BASE}/$DIR ] || [ ! -f ${BINARY_BASE}/$DIR/Pkgfile ]; then
			echo "'$DIR' should be added"
			rsync -av --delete ${PORT_BASE}/$DIR/ ${BINARY_BASE}/$DIR/
		else
			rsync -au  --exclude="*cards.tar*" --exclude=".PKGREPO" --delete \
				${PORT_BASE}/$DIR/ ${BINARY_BASE}/$DIR/
		fi
		if [ ! -f ${BINARY_BASE}/$DIR/.PKGREPO ];then
			echo "$DIR should be build"
		fi
	done
	cd - > /dev/null
}
check_diff()
{
	check_location
	check_config_file
	ports_list=$(mktemp) || exit 1
	binaries_list=$(mktemp) || exit 1
	output=$(mktemp) || exit 1
	output_sorted=$(mktemp) || exit 1
	found="no"

	cards list -p|grep $BINARY_BASE|sed "s@$BINARY_BASE/@@" >> $binaries_list
	list_ports >> $ports_list

	for binary_package in $(cat $binaries_list | gawk '{ print $1 }'); do
		binary_package_version=$(cat $binaries_list | grep "^$binary_package " | gawk '{ print $2 }'| cut -d "-" -f1)
		binary_package_release=$(cat $binaries_list | grep "^$binary_package " | gawk '{ print $2 }'| cut -d "-" -f2)
		if [ "$binary_package_version" == "" ]; then
			base_binary_package=$(echo $binary_package | cut -d "-" -f1)
			if [ "$base_binary_package" != "$binary_package" ]; then
				binary_package_version=$(cat $binaries_list | grep "^$base_binary_package " | gawk '{ print $2 }'| cut -d "-" -f1)
				binary_package_release=$(cat $binaries_list | grep "^$base_binary_package " | gawk '{ print $2 }'| cut -d "-" -f2)
			fi
		fi
		binary_version=$(echo $binary_package_version-$binary_package_release)
		package=$binary_package
		if [ -f $PORT_BASE/$package/Pkgfile ]; then
			base_package=$(echo $package | cut -d "-" -f1)
			cd $PORT_BASE/$package
			get_port_version
			port_version=$version-$release
			if [ "$binary_version" != "$port_version" ]; then
				echo "$package $port_version $binary_version" >> $output
				found="yes"
			fi
		fi
	done
	if [ "$found" = "yes" ]; then
		echo "Name Port Compiled" >> $output_sorted
		sort $output >> $output_sorted
		column -t $output_sorted
	fi
}
check_port_name() {
	check_config_file
	if [ ! -d "$PORT_BASE/$1" ]; then
		echo "I dont know the port $1"
		exit 1
	fi
}
check_collection_exist() {
	if [ ! -d "$COLLECTION" ]; then
		echo "I dont know the collection $COLLECTION"
		exit 1
	fi
}
parse_options() {
	if [ $# -lt 1 ]; then
		print_help
		usage
		exit 0
	fi
	while [ "$1" ]; do
		case $1 in
			-l|--list)
				check_ports
				list_binaries
				exit 0
				;;
			-a|--all)
				check_ports
				check_binaries
				build_binaries
				exit 0
				;;
			-cp|--check-ports)
				check_ports
				exit 0
				;;
			-cb|--check-binaries)
				check_binaries
				exit 0
				;;
			-cd|--check-diff|-d|--dry)
				DRY="yes"
				check_ports
				check_binaries
				build_binaries
				exit 0
				;;
			-ru|--remove-url)
				check_root
				check_tools
				check_config_file
				remove_url
				exit 0
				;;
			-s|--sync)
				sync_binaries
				exit 0;;
			-c|--config)
				check_root
				check_tools
				check_config_file
				echo "Your config is:
Grat-OS name    : $RSYNC_GRATOS_NAME
Grat-OS version : $RSYNC_GRATOS_VERSION
BINARY_BASE     : $BINARY_BASE
PORT_BASE       : $PORT_BASE
"
				exit 0;;

			-h|--help)
				print_help
				exit 0;;

			-v|--version)
				echo "$COLLECTION $BUILD_PORT_VERSION"
                                exit 0 ;;

			-u|--usage)
				usage
				exit 0;;

			*)
				check_port_name $1
				;;

		esac
		shift
	done
}
check_tools () {
	if ! ( $(which cards > /dev/null) ); then
		echo "'cards' not available"
		exit 1
	fi
	if ! ( $(which pkgmk > /dev/null) ); then
		echo "'cards.devel' not available"
		exit 1
	fi
	if ! ( $(which rsync > /dev/null) ); then
		echo "'rsync' not available"
		exit 1
	fi
	if ! ( $(which gawk > /dev/null) ); then
		echo "'gawk' not available"
		exit 1
	fi
}
check_root () {
	if [ ! "$UID" == "0" ]; then
		echo "You are not 'root'"
		exit 1
	fi
}
check_location () {
if [ ! -d .git ] && [ ! -d scripts ]; then
	echo "Make shure you are at the root of the git"
	echo "Your are in: $GIT"
	exit 1
fi
}
check_user () {
if [ "$UID" == "0" ] && [ -O scripts ] ; then
	echo "your are 'root' account
Means you are not suppose to 'git pull' this git project"
	usage
	echo "I quit for now

"
	exit 1
fi
}
get_binary_directory() {
	local DIR
	DIR=$(cards config|grep Directory| cut -d " " -f3|grep ${COLLECTION}$|sed "s/\/${COLLECTION}$//"|head -1)
	if [ ! -z ${DIR} ]; then
		BINARY_DIR=${DIR}
	else
		BINARY_DIR=${RSYNC_GRATOS_VERSION}
	fi
}
get_binary_version() {
	local version release
	cd $BINARY_BASE/$package
	version=$(head -1 .PKGREPO|cut -d "#" -f3)
	release=$(head -1 .PKGREPO|cut -d "#" -f4)
	binary_version=$version-$release
}
get_port_version() {
	local port base_port PORTS_DIR tmprel
	port=/$PORT_BASE/$package
	PORTS_DIR=$PORT_BASE
	base_port=$(echo $package | cut -d "-" -f1)
	cd $port
	unset version
	release=1
	. Pkgfile
	[ ! -z $release ] && tmprel=$release
	if [ -z $version ] && [ "$base_port" != "$package" ] ; then
		if [ -f $PORTS_DIR/$base_port/Pkgfile ]; then
			cd $PORTS_DIR/$base_port
			. Pkgfile
		fi
	fi
	[ ! -z $tmprel ] && release=$tmprel
	port_version="$version-$release"
}
check_config_file () {
	get_binary_directory
	if [ ! -f /etc/cards.conf.d/$COLLECTION.conf ] ; then
		echo "Create $COLLECTION.conf file"
		[ ! -d /etc/cards.conf.d ] && mkdir -p /etc/cards.conf.d
		echo "PORT_BASE=$GIT/$COLLECTION
BINARY_BASE=${BINARY_DIR}/$COLLECTION" > /etc/cards.conf.d/$COLLECTION.conf
	fi

	. /etc/cards.conf.d/$COLLECTION.conf || exit 1

	[ ! -d $BINARY_BASE ] && mkdir -p $BINARY_BASE
	if [  "$BINARY_BASE" == "$PORT_BASE" ]; then
		echo "Correct your $COLLECTION.conf file
BINARY_BASE and PORT_BASE should NEVER be equal
BINARY_BASE=$BINARY_BASE
PORT_BASE=$PORT_BASE
I quit for now
"
		exit 1
	fi
	if [ -f /var/lib/pkg/grat-os-version ]; then
		RSYNC_GRATOS_VERSION=$(cat /var/lib/pkg/grat-os-version|grep version|sed "s/version //"| sed "s/ //g")
		RSYNC_GRATOS_NAME=$(cat /var/lib/pkg/grat-os-version|grep name|sed "s/name //"| sed "s/ //g")
	else
		echo "/var/lib/pkg/grat-os-version file not exist
I quit for now
"
		exit 1
	fi
	if [ -z $RSYNC_GRATOS_VERSION ]; then
		echo "Dont know the version you want to rsync
Check the /var/lib/pkg/grat-os-version, should have a
line like:

name EternalRolling
version stable

"
		exit 1
	fi
}
sync_binaries () {
	check_tools
	check_config_file
	check_collection_exist
	remove_url
	rsync -av --delete ${RSYNC_SERVER}/${ARCH}/${RSYNC_GRATOS_VERSION}/$COLLECTION/ \
	$BINARY_BASE/
}
sync_pkgmk_conf() {
	if [ -f ${PORT_BASE}/${PKGMK_CONFFILE} ]; then
		rsync -a ${PORT_BASE}/${PKGMK_CONFFILE} \
		${BINARY_BASE}/${PKGMK_CONFFILE}
	else
		rm -f ${BINARY_BASE}/${PKGMK_CONFFILE}
	fi

}
remove_url () {
	local URL
	URL="$(cat /etc/cards.conf|grep \"^dir[ ]*${BINARY_BASE}|\"| cut -d '|' -s -f2)"
	if [ ! -z "$URL" ]; then
		sed -i "s@${BINARY_BASE}|${URL}@${BINARY_BASE}@" /etc/cards.conf
	fi
}
install_cards_binaries() {
	local deps
	deps=($1)
	if [[ -n $deps ]]; then
		if ! cards install ${deps[@]}; then
			echo -e "A dependency listed in makedepends=() or run=() is unknown"
			exit 1
		fi
	fi
}
build_binaries () {
	local package port_version binary_version currentdir i deps
	currentdir=$PWD
	sync_pkgmk_conf
  mkdir -p /usr/local/include
	if [ -n "$(cards level|grep WARNING|head -1)" ]; then
		cards level
		exit 1;
	fi
	sync_pkgmk_conf
	for group in ${PKGMK_GROUPS[@]}; do
		if ! grep -q "group $group" $ETC_CARDS_CONFFILE; then
			echo "group $group" >> $ETC_CARDS_CONFFILE
			UPDATE_CARDS_CONFIG="yes"
		fi
	done
	if [[ $UPDATE_CARDS_CONFIG = "yes" ]]; then
		cards upgrade
	fi
	for i in $(cards level | grep ${BINARY_BASE}/|cut -d " " -f2)
	do
		package=$(basename $i)
		source "${PORT_BASE}/$package/Pkgfile"
		deps="${makedepends[@]}"
		deps+=" ${run[@]}"
		rsync -avq --exclude '.*.swp'  --exclude '*~' \
		--exclude '*cards.tar*' --exclude '.PKGREPO' \
		--delete-after ${PORT_BASE}/$package/ \
		${BINARY_BASE}/$package/

		chown -R 0:0 ${BINARY_BASE}/$package/

		if [  -z "$(ls ${BINARY_BASE}/$package/*$ARCH.cards.tar.xz 2>/dev/null )" ];then
			cd $BINARY_BASE/$package
			[ "$DRY" == "yes" ] && continue
			install_cards_binaries "$deps"
			pkgmk -d || manual_fix $package
			cards base -r
		fi

		if [ ! -f ${BINARY_BASE}/$package/.PKGREPO ]; then
			cd $BINARY_BASE/$package
			[ "$DRY" == "yes" ] && continue
			install_cards_binaries "$deps"
			pkgmk -d || manual_fix $package
			cards base -r
		fi

		if [ ! -z "$(diff ${BINARY_BASE}/$package/Pkgfile ${PORT_BASE}/$package/Pkgfile)" ]; then
			echo " ${BINARY_BASE}/$package/Pkgfile AND ${PORT_BASE}/$package/Pkgfile are different ...WILL BUILD NEW.."
			cd $BINARY_BASE/$package
			[ "$DRY" == "yes" ] && continue
			install_cards_binaries "$deps"
			pkgmk -d || manual_fix $package
			cards base -r
		fi

		get_port_version
		get_binary_version

		if [ "$port_version" != "$binary_version" ]; then
			echo "$package: Port: $port_version, Binary: $binary_version"
			cd $BINARY_BASE/$package
			[ "$DRY" == "yes" ] && continue
			install_cards_binaries "$deps"
			pkgmk -d || manual_fix $package
			cards base -r
		fi

		[ "$DRY" == "yes" ] || echo "WILL NOT BUILD '$package' AGAIN.."
		unset deps
	done
}
list_binaries () {
	cards level -I |grep ${BINARY_BASE}

}
manual_fix() {
	cd $BINARY_BASE/$1
	cards install nano
	if ! bash; then
	  exit 1
	fi
	pkgmk -d || exit 1
}
main() {
	check_tools
	check_location
	check_user
	check_config_file
	check_collection_exist
	if [[ -f $ETC_PKGMK_CONFFILE ]]; then
		source $ETC_PKGMK_CONFFILE
	fi
	parse_options "$@"
	
}

UPDATE_CARDS_CONFIG="no"
BUILD_PORT_VERSION=2.6.4
DRY="no"
ARCH=$(uname -m)
RSYNC_SERVER="rsync://downloads.nutyx.org/nutyx"
COLLECTION="$(basename $0)"
GIT="$PWD"
PROJECT="$(basename $GIT)"
PKGMK_CONFFILE=".pkgmk.conf"
ETC_PKGMK_CONFFILE="/etc/pkgmk.conf"
ETC_CARDS_CONFFILE="/etc/cards.conf"
main "$@"
