#!/usr/bin/env sh

#  helper script: download coreboot
#
#	Copyright (C) 2014,2015,2016,2020,2021,2023 Leah Rowe
#							<info@minifree.org>
#	Copyright (C) 2022 Alper Nebi Yasak <alpernebiyasak@gmail.com>
#	Copyright (C) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com>
#
#	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.
#
#	You should have received a copy of the GNU General Public License
#	along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

[ "x${DEBUG+set}" = 'xset' ] && set -v
set -u -e

_board=""
cbtree=""
cbrevision=""

cbcfgsdir="resources/coreboot"

main()
{
	if [ $# -eq 1 ] && [ "$1" = "--help" ] ; then
		usage
		exit 0
	elif [ $# -eq 1 ] && [ "$1" = "--list-boards" ] ; then
		list_supported_boards
		exit 0
	else
		fetch_coreboot_trees $@
	fi
}

fetch_coreboot_trees()
{
	rm -f ${cbcfgsdir}/*/seen

	printf "Downloading coreboot and (if available) applying patches\n"

	boards=""
	if [ $# -gt 0 ]; then
		boards=$@
	else
		for board in ${cbcfgsdir}/*; do
			[ ! -d "${board}" ] && continue
			boards="${boards} ${board##*/}"
		done
	fi
	for board in ${boards}; do
		rm -f ${cbcfgsdir}/*/seen
		download_coreboot_for_board "${board}"
	done

	rm -f ${cbcfgsdir}/*/seen
}

download_coreboot_for_board()
{
	_board="${1}"
	cbtree="undefined"
	cbrevision="undefined"

	fetch_coreboot_config "${_board}" || exit 1

	rm -f ${cbcfgsdir}/*/seen

	if [ -d "coreboot/${cbtree}" ]; then
		printf "REMARK: download/coreboot %s: exists. Skipping.\n" \
				${cbtree}
		[ "${cbtree}" != "${1}" ] && \
			printf "(for board: '%s}')\n" ${1}
		return 0
	fi

	gitclone_coreboot_from_upstream || exit 1

	prepare_new_coreboot_tree "${1}" "${cbtree}" "${cbrevision}" \
			|| exit 1
}

fetch_coreboot_config()
{
	_board=${1}

	while true; do
		cbrevision="undefined"
		cbtree="undefined"

		check_config_for_board "${_board}" || return 1

		# This is to override $cbrevision and $cbtree
		. "${cbcfgsdir}/${_board}/board.cfg" || exit 1

		if [ "${_board}" != "${cbtree}" ]; then
			_board="${cbtree}"
			continue
		elif [ "${cbtree}" = "undefined" ]; then
			printf "ERROR: download/coreboot:"
			printf " tree name undefined for '%s\n'" \
					${_board}
			return 1
		elif [ "${cbrevision}" = "undefined" ]; then
			printf "ERROR: download/coreboot:"
			printf " commit ID undefined for '%s'\n" \
					${_board}
			return 1
		else
			break
		fi
	done
	return 0
}

check_config_for_board()
{
	_board=${1}

	if [ ! -f "${cbcfgsdir}/${_board}/board.cfg" ]; then
		printf "ERROR: download/coreboot: board.cfg does not"
		printf " exist for '%s'\n" ${_board}
		return 1
	elif [ -f "${cbcfgsdir}/${_board}/seen" ]; then
		printf "ERROR: download/coreboot: logical loop:"
		printf " '%s' board.cfg refers to another tree," ${_board}
		printf " which ultimately refers back to '%s'." ${_board}
		return 1
	fi
	touch "${cbcfgsdir}/${_board}/seen"
	return 0
}

gitclone_coreboot_from_upstream()
{
	[ ! -d coreboot ] && \
		mkdir -p coreboot
	[ ! -d coreboot ] && \
		return 1
	[ -d coreboot/coreboot ] && \
		rm -Rf coreboot/coreboot
	[ -d coreboot/coreboot ] && \
		return 1
	./gitclone coreboot || \
		return 1
	return 0
}

prepare_new_coreboot_tree()
{
	target=${1}
	cbtree=${2}
	cbrevision=${3}

	printf "Preparing coreboot tree: %s\n" ${cbtree}
	[ "${cbtree}" != "${target}" ] && \
		printf "(for board: %s)\n" "${target}"

	cp -R coreboot/coreboot "coreboot/${cbtree}" || exit 1
	(
	cd "coreboot/${cbtree}" || exit 1
	git reset --hard ${cbrevision} || exit 1
	git submodule update --init --checkout || exit 1

	for patch in ../../${cbcfgsdir}/${cbtree}/patches/*.patch; do
		[ ! -f "${patch}" ] && \
			continue
		if ! git am "${patch}"; then
			git am --abort
			exit 1
		fi
	done

	# extra.sh can be used for anything
	# but should *only* be a last resort
	if [ -f "../../${cbcfgsdir}/${cbtree}/extra.sh" ]; then
		"../../${cbcfgsdir}/${cbtree}/extra.sh" || \
			exit 1
	fi
	)
}

usage()
{
	progname="./download coreboot"
	printf "Usage:\n"
	printf "\t%s\t\t\t# Clone coreboot for all boards\n" "${progname}"
	printf "\t%s [board [board] ...] # Clone coreboot for given boards\n" \
			${progname}
	printf "\t%s --list-boards\t# Prints this help\n" ${progname}
	printf "\t%s --help\t\t# List supported boards\n" ${progname}
	printf "\t%s --help\t\t# Prints this help\n" ${progname}
}

list_supported_boards()
{
	for _board in ${cbcfgsdir}/*; do
		echo ${_board} | sed 's#${cbcfgsdir}/##'
	done
}

main $@