#!/usr/bin/env bash

#++
#++ create_packages.sh - builds Repository packages for checkit_tiff using an intermediary Docker container
#++ 
#++ USAGE:
#++
#++   create_packages.sh ARGS
#++ 
#++ ARGS:
#++
#++   -h | --help
#++     show this help message
#++
#++   -k | --keep
#++     keep existing container. This is the Default.
#++
#++   -r | --replace
#++     replace existing container by a fresh build. The opposite of --keep.
#++
#++   -s | --static-link
#++     build checkit_tiff binaries with static link. Default is static linking if this flag isn't used.
#++
#++   -w|--warn|--warnings
#++     show cmake warnings during the build process. By default, warnings are OFF.
#++
#++   -l|--dynamic-link)
#++     build checkit_tiff binaries with dynamic link. Default is static linking if this flag isn't used.
#++
#++   -c | --current <VERSION>
#++     pass release version for checkit_tiff_current. This is usually a Git Tag.
#++
#++   -u | --upcoming <VERSION>
#++     pass release version for checkit_tiff_upcoming. This is usually a Git Tag.
#++
#++   --enable-icc-lino
#++     allow embedded ICC profiles that have their CMM type set to "Lino". This is the default.
#++
#++   --enable-icc-outdated
#++     allow embedded ICC profiles with outdated version 2.4. This is the default.
#++
#++   --enable-icc-strict
#++     enable a strict check of ICC versions. Normally, correct major version is sufficient, but this will check for the minor version as well to warn about outdated ICC profile versions.
#++
#++   --disable-icc-lino
#++     disallow embedded ICC profiles that have their CMM type set to "Lino"
#++
#++   --disable-icc-outdated
#++     disallow embedded ICC profiles with outdated version 2.4
#++
#++   --disable-icc-strict
#++     enable a strict check of ICC versions. Normally, correct major version is sufficient, but this will check for the minor version as well to warn about outdated ICC profile versions. This is the default.
#++
#++
#++ GENERAL:
#++
#++   Defaults are set in the code. Parameters cat set in the config file and on the CLI.
#++   The precedence is:
#++     - Defaults are overwritten by both config file options and CLI parameters.
#++     - Config file options are only overwritten by CLI parameters.
#++   If you use both an "enable" and a "disable" parameter on the CLI, then the "disable" will win. This behaviour is designed to avoid any undefined behaviour due to contradictions.
#++




### START SET CONFIG DEFAULTS
replace_container="false"
container_name="cit_build"
config_file="./create_packages.cfg"
cit_repo='https://git.fsfe.org/art1pirat/checkit_tiff.git'
declare -A cit_versions
cit_versions[current]="v"
cit_versions[upcoming]="v"
# Use empty strings to disable options
cmake_flag_icc_lino="-DALLOW_CMMTYPE_LINO"	# allow preferred CMM type "LINO"
cmake_flag_icc_outdated="-DALLOW_ICC1_2001_04"	# allow outdated ICC.1:2001-04 version (2.4.0)
cmake_flag_icc_strict=""			# enable strict ICC version check, Default: disabled
cmake_flag_static="-DSTATIC=1"			# compile a statically linked binary, Default: static link
cmake_static_compile="-s"			# compile a statically linked binary, Default: static link
### END SET CONFIG DEFAULTS

# override default configs with custom values from config file
# shellcheck source=/dev/null
source "${config_file}"

# Cmake flags to configure the build process.
cmake_flags="-ansi -O3 -flto -fstack-check -fstack-protector-strong"
cmake_flag_warnings=""
script_fullpath="$( dirname "$( realpath "${0}")" )/"

# Call getopt to validate the provided input. 
cli_args=$( getopt \
            --longoptions help,keep,replace,static-link,warn,warnings,dynamic-link,enable-icc-lino,enable-icc-outdated,enable-icc-strict,disable-icc-lino,disable-icc-outdated,disable-icc-strict,current:,upcoming: \
            --options hkrswlc:u: \
	    -- "$@" \
          )
# Assign any remaining arguments to the positional parameters. If there are no remaining arguments, the positional parameters are unset.
eval set -- "$cli_args"

# evaluate CLI args
while true; do
	case "$1" in
		-h|--help)
			sed -rn 's/^#\+\+ ?//;T;p' "$0"
			exit 0
			;;
		-k|--keep)
			replace_container="false"
			;;
		-r|--replace)
			replace_container="true"
			;;
		-s|--static-link)
			cmake_flag_static="-DSTATIC=1"
			cmake_static_compile="-s"
			replace_container="true"
			;;
		-w|--warn|--warnings)
			cmake_flag_warnings="-W -Wall -Wextra -pedantic -Wno-unused-function -Wformat -Werror=format-security"
			;;
		-l|--dynamic-link)
			cmake_flag_static=""
			cmake_static_compile=""
			replace_container="true"
			;;
		--enable-icc-lino)
			cmake_flag_icc_lino="-DALLOW_CMMTYPE_LINO"
			replace_container="true"
			;;
		--enable-icc-outdated)
			cmake_flag_icc_outdated="-DALLOW_ICC1_2001_04"
			replace_container="true"
			;;
		--enable-icc-strict)
			cmake_flag_icc_strict="-DWITH_STRONG_ICC"
			replace_container="true"
			;;
		--disable-icc-lino)
			cmake_flag_icc_lino=""
			replace_container="true"
			;;
		--disable-icc-outdated)
			cmake_flag_icc_outdated=""
			replace_container="true"
			;;
		--disable-icc-strict)
			cmake_flag_icc_strict=""
			replace_container="true"
			;;
		-c|--current)
			shift
			cit_versions[current]="$1"
			;;
		-u|upcoming)
			shift
			cit_versions[upcoming]="$1"
			;;
		--)
			shift
			break
			;;
		*)
			echo "ERROR: not a valid CLI parameter: '${1}'. Please use '$(basename "${0}") --help' to view the complete list of supported parameters. Exiting."
			exit 1
			;;
	esac
	shift
done

# check if necessary parameters have been set
[[ -z ${cit_versions[current]} ]] && echo "ERROR: Version for checkit_tiff_current not set. Set it in the config file or use the '--current M.M.S' CLI parameter." && exit 1
[[ -z ${cit_versions[upcoming]} ]] && echo "ERROR: Version for checkit_tiff_upcoming not set. Set it in the config file or use the '--upcoming M.M.S' CLI parameter." && exit 1
[[ -z ${cmake_flag_static} || -z ${cmake_static_compile} ]] && echo "WARNING: Compiling a dynamically linked binary will result in packages that don't have IccProfLib2 encoded in their respective dependencies. Make sure to install the latest version of IccProfLib2 in the search path of your system in order to use these packages without any issues."

# check prerequisites
prerequisites="docker id grep"
for req in ${prerequisites}; do
	command -v "${req}" >/dev/null 2>&1 || { echo >&2 "ERROR: ${req} not installed. Aborting."; exit 1; }
done

# check group membership to run docker commands
if [[ ( ${EUID} -ne 0 ) && ( ! $( id -nG "${USER}" | grep "docker" ) ) ]]; then
	echo "ERROR You need to be root user or member of the 'docker' group. Exiting" && exit 1
fi

if [[ ( $( docker container ls --all --no-trunc --filter name="${container_name}" --format '{{.Names}}' ) ) ]]; then
	if [[ "${replace_container}" == "false" ]]; then
		# run container if it doesn't need to be replaced and can be run as-is
		docker restart "${container_name}"
		echo "INFO: The build has been triggered to run in the background. Your build artifacts (packages, binaries, configs) should soon appear in the 'artifacts/' subdirectory. Please have a little patience."
	else	#[[ "${replace_container}" == "true" ) ]]
		# stop & remove existing container
		docker container rm --force --volumes "${container_name}"
		# remove Docker image
		docker image rm --force "${container_name}"
	fi
fi

if [[ ! $( docker container ls --all --no-trunc --filter name="${container_name}" --format '{{.Names}}' ) ]]; then
	# write entrypoint-script
	cat <<-EOEF > build_cit.sh
		#!/usr/bin/env bash

		# uncomment if you need debug output
		#set -x

		declare -A cit_versions
		cit_versions[current]="${cit_versions[current]}"
		cit_versions[upcoming]="${cit_versions[upcoming]}"
		build_dir="/opt/builddir/"
		artifact_dir="/opt/artifacts/"

		# update packages
		apt-get -y update; apt-get -y upgrade
		
		# cleanup old builddir
		rm -rf "\${build_dir:?}/"; mkdir "\${build_dir}/" || exit 1

		# create shared directory for build artifacts
		[[ ! -d "\${artifact_dir}/" ]] && mkdir "\${artifact_dir}/"

		# compile and install IccProfLib2
		cd "\${build_dir}/" || exit 1
		git clone "https://github.com/InternationalColorConsortium/DemoIccMAX.git"
		cd "\${build_dir}/DemoIccMAX/" || exit 1
		mkdir build && cd build || exit 1
		cmake -DCMAKE_INSTALL_PREFIX=/usr/local/ ../Build/Cmake
		make		# DO NOT USE "-j" FLAG WITH ICCPROFLIB2, IT HANGS DURING THE make RUN!
		make install	# DO NOT USE "-j" FLAG WITH ICCPROFLIB2, IT HANGS DURING THE make RUN!

		# update git repos
		for release in current upcoming; do
			mkdir -p "\${build_dir}/\${release}/" && cd "\${build_dir}/\${release}/" || exit 1
			chmod 0777 "\${build_dir}/"

			# get checkit_tiff
			git clone --branch \${cit_versions[\$release]} ${cit_repo}
			cd "\${build_dir}/\${release}/checkit_tiff/" || exit 1

			# patch CMake config to contain strings for current/upcoming releases in binary and package names
			sed -i s'#project (checkit_tiff)#project (checkit_tiff_'"\${release}"')#' \
				"\${build_dir}/\$release/checkit_tiff/src/CMakeLists.txt"
			sed -i s'#set (CPACK_PACKAGE_NAME "checkit-tiff")#set (CPACK_PACKAGE_NAME "checkit-tiff-'"\${release}"'")#' \
				"\${build_dir}/\$release/checkit_tiff/src/CMakeLists.txt"

			sed -i s'#add_executable(checkit_tiff checkit_tiff.c \${checkit_tiff_SOURCES})#add_executable(checkit_tiff_'"\${release}"' checkit_tiff.c \${checkit_tiff_SOURCES})#' \
				"\${build_dir}/\$release/checkit_tiff/src/CMakeLists.txt"
			sed -i s'#target_link_libraries(checkit_tiff #target_link_libraries(checkit_tiff_'"\${release}"' #' \
				"\${build_dir}/\$release/checkit_tiff/src/CMakeLists.txt"

			sed -i s'#add_executable(checkit_check_config checkit_check_config.c \${checkit_tiff_SOURCES})#add_executable(checkit_check_config_'"\${release}"' checkit_check_config.c \${checkit_tiff_SOURCES})#' \
				"\${build_dir}/\$release/checkit_tiff/src/CMakeLists.txt"
			sed -i s'#target_link_libraries(checkit_check_config #target_link_libraries(checkit_check_config_'"\${release}"' #' \
				"\${build_dir}/\$release/checkit_tiff/src/CMakeLists.txt"

			sed -i s'#add_executable(checkit_tiff_risk checkit_tiff_risk.c \${checkit_tiff_risk_SOURCES})#add_executable(checkit_tiff_risk_'"\${release}"' checkit_tiff_risk.c \${checkit_tiff_risk_SOURCES})#' \
				"\${build_dir}/\$release/checkit_tiff/src/CMakeLists.txt"
			sed -i s'#target_link_libraries(checkit_tiff_risk #target_link_libraries(checkit_tiff_risk_'"\${release}"' #' \
				"\${build_dir}/\$release/checkit_tiff/src/CMakeLists.txt"

			sed -i s'#install( TARGETS checkit_tiff#install( TARGETS checkit_tiff_'"\${release}"'#' \
				"\${build_dir}/\$release/checkit_tiff/src/CMakeLists.txt"
			sed -i s'#DESTINATION share/checkit_tiff/#DESTINATION share/checkit_tiff_'"\${release}"'/#' \
				"\${build_dir}/\$release/checkit_tiff/src/CMakeLists.txt"

			# prepare cross-compiled pcre2
			#wget https://github.com/PhilipHazel/pcre2/releases/download/pcre2-10.40/pcre2-10.40.tar.gz || exit 1
			#tar -xzvf pcre2-10.4ß.tar.gz
			#cd pcre2-10.4ß/ || exit 1
			#./configure --host=x86_64-w64-mingw32 --disable-shared --enable-static
			#make -j
			#cd "\${build_dir}/\${release}/checkit_tiff/" || exit 1

			# build it for Linux!
			rm -rf "./build" && mkdir "build" && cd "build" || exit 1
			PATH="\${PATH}:/usr/lib/x86_64-linux-gnu/:/usr/bin/:/usr/include/"; export PATH;
			cmake ../src/ ${cmake_flag_static} -DCMAKE_C_FLAGS="${cmake_flag_icc_outdated} ${cmake_flag_icc_strict} ${cmake_flag_icc_lino} ${cmake_static_compile} ${cmake_flags} ${cmake_flag_warnings}"
			make -j
			ln -s \$(pwd)/checkit_check_config_\${release} \$(pwd)/checkit_check_config
			ln -s \$(pwd)/checkit_tiff_\${release} \$(pwd)/checkit_tiff
			if ! make -j test; then
        echo "ERROR: Tests didn't run successfully, aborting build." && exit 1
      fi
			make -j package
			cd .. || exit 1

			# build it for Windows! INOPERATIONAL!
			#rm -rf "./build_win" && mkdir "build_win" && cd "build_win" || exit 1
			#cmake ../src/ -DCMAKE_TOOLCHAIN_FILE=../src/toolchain-mingw64.cmake -DPCRE2_POSIX_LIBRARY=\${build_dir}/\${release}/checkit_tiff/pcre2-10.40/.libs/libpcre2-posix.a -DPCRE2_LIBRARY=\${build_dir}/\${release}/checkit_tiff/pcre2-10.4ß/.libs/libpcre2-8.a -DPCRE2_INCLUDE_DIR=\${build_dir}/\${release}/checkit_tiff/pcre2-10.4ß/src/
			#make -j
			#make -j test
			#cd .. || exit 1

			### copy relevant artifacts out of the build directories and into the shared directory before cleaning up
			# Linux
			mv \${build_dir}/\$release/checkit_tiff/build/checkit-tiff-\$release-* \${artifact_dir}/
			mv \${build_dir}/\$release/checkit_tiff/build/checkit_tiff_\$release \${artifact_dir}/
			mv \${build_dir}/\$release/checkit_tiff/build/checkit_check_config_\$release \${artifact_dir}/
			mv \${build_dir}/\$release/checkit_tiff/build/checkit_tiff_risk_\$release \${artifact_dir}/
			# Windows INOPERATIONAL
			#mv \${build_dir}/\$release/checkit_tiff/build_win/checkit-tiff-\$release-* \${artifact_dir}/
			#mv \${build_dir}/\$release/checkit_tiff/build_win/checkit_tiff_\$release \${artifact_dir}/
			#mv \${build_dir}/\$release/checkit_tiff/build_win/checkit_check_config_\$release \${artifact_dir}/
			#mv \${build_dir}/\$release/checkit_tiff/build_win/checkit_tiff_risk_\$release \${artifact_dir}/
			# Configs
			mv \${build_dir}/\$release/checkit_tiff/example_configs/cit_tiff6_baseline_SLUB.cfg \${artifact_dir}/cit_tiff6_baseline_SLUB_\$release.cfg
			mv \${build_dir}/\$release/checkit_tiff/example_configs/cit_tiff6_geotiff_SLUB.cfg \${artifact_dir}/cit_tiff6_geotiff_SLUB_\$release.cfg
			chown -R \${EXTUID} \${build_dir}
			chown -R \${EXTUID} \${artifact_dir}
		done
EOEF
	chmod +x build_cit.sh
	
	# write Dockerfile
	cat <<-EODF > Dockerfile
		FROM --platform=linux/amd64 debian:stable-slim
		LABEL maintainer="Jörg Sachse <joerg.sachse@slub-dresden.de>"
		RUN apt-get -y update && \
		  apt-get -y install git cmake make gcc gpp build-essential \
		    libfile-slurp-perl libdata-printer-perl pkg-config \
        libpcre2-dev file rpm wget libxml2-dev libtiff-dev \
        gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64       && \
		    apt-get autoclean
		WORKDIR /opt/
		ENTRYPOINT ["/build_cit.sh"]
EODF

	# build Docker image
	docker build --pull --tag "${container_name}:latest" ./
	rm Dockerfile
	docker run --hostname "${container_name}" --name "${container_name}" --volume "${script_fullpath}:/opt/" --volume "${script_fullpath}/build_cit.sh:/build_cit.sh" --cpus 3 --env EXTUID=${UID} "${container_name}:latest"
fi
