#!/bin/bash

# The directory where this programm is installed will be added to PATH and
# to the search path of BASH libraries.
declare -r  mydir=$(dirname "$0")


declare -r  libpbuild='libpbuild.bash'
declare -r  libstd='libstd.bash'
declare -r  pmodule_environment='environment.bash'
declare -ra bash_libpath=("${mydir}" "${mydir}/../lib")

##############################################################################
#
# set an error handler. If a function _exit() exists, it will be called
# with the passed exit code.
#
# $1	exit code
#
set -o errexit

_exit() {
	:
}

error_handler() {
	local -i ec=$?

	_exit ${ec}
	exit ${ec}
}

trap "error_handler" ERR

# disable auto-echo feature of 'cd'
unset CDPATH

##############################################################################
#
usage() {
	std::error "
Usage: $0 [OPTIONS..] [BUILD_BLOCK] [VERSION]

VERSION
        Version of module to compile.

-? | -h | --help
        Print usage

-v | --verbose )
        Verbose output

-j N | --jobs=N
        Run N parallel make jobs

-f | --force-rebuild
        Force rebuild of module.

--dry-run
	Dry run.

--enable-cleanup-build
	Cleanup files in the build directory (default).

--enable-cleanup-src
	Cleanup files in the source directory.

--disable-cleanup
	Keep files in build and source directory

--disable-cleanup-build
	Keep files in build directory.

--disable-cleanup-src
	Keep files in source directory (default).

--variants-file
        Specify which variants file to use

--with=P/V
        Preload module P with version V. To preload multiple modules,
        use this option per module. Order may matter!

--release=stable|unstable|deprecated

--prep
	Unpack sources only.

--configure
	Unpack sources and configure build.

--compile
	Unpack sources, configure build and compile software

--install
	Unpack sources, configure build, compile software and install.

--all
	Do everything, this step includes cleanup files and setting 
	the symbolic link to the modulefile.
"
	exit 1
}

#
# We need GNU versions of the following utilities. This code works
# well on Linux and Mac OS X with MacPorts.
# :FIXME: implement a smarter, portable solution.
#
shopt -s expand_aliases
unalias -a

__path=$(which gsed 2>/dev/null || : )
if [[ $__path ]]; then
	alias sed=$__path
else
	alias sed=$(which sed 2>/dev/null)
fi

##############################################################################
#
# source BASH library with standard functions
declare	    ok=1
for dir in "${bash_libpath[@]}"; do
        if [[ -r ${dir}/${libstd} ]]; then
		source "${dir}/${libstd}"
		ok=0
		break
	fi
done
if (( ok != 0 )); then
	echo "Oops: required BASH library '${libstd}' not found" 1>&2
	exit 1
fi

##############################################################################
#
# parse arguments
#

# number of parallel make jobs
declare -i  JOBS=3

declare debug_on='no'
declare force_rebuild='no'
declare dry_run='no'
declare enable_cleanup_build='yes'
declare enable_cleanup_src='no'
declare target='all'
declare bootstrap='no'
declare variants_file=''

# array collecting all modules specified on the command line via '--with=module'
with_modules=()

# save arguments, we might need later again
declare -r ARGS="$@"

# OS/system default
declare    OS=$(uname -s)

# 
while (( $# > 0 )); do
	case $1 in
	-j )
		JOBS=$2
		shift
		;;
	--jobs=[0-9]* )
		JOBS=${1/--jobs=}
		;;
	-v | --verbose )
		debug_on='yes'
		;;
	--debug )
		set -x
		;;
	-f | --force-rebuild )
		force_rebuild='yes'
		;;
	-\? | -h | --help )
		usage
		;;
	--dry-run )
		dry_run='yes'
		;;
	--disable-cleanup )
		enable_cleanup_build='no'
		enable_cleanup_src='no'
		;;
	--enable-cleanup-build )
		enable_cleanup_build='yes'
		;;
	--disable-cleanup-build )
		enable_cleanup_build='no'
		;;
	--enable-cleanup-src )
		enable_cleanup_src='yes'
		;;
	--disable-cleanup-src )
		enable_cleanup_src='no'
		;;
	--distdir )
		PMODULES_DISTFILESDIR=$2
		shift
		;;
	--distdir=* )
		PMODULES_DISTFILESDIR=${1/--distdir=}
		;;
	--tmpdir )
		PMODULES_TMPDIR=$2
		shift
		;;
	--tmpdir=* )
		PMODULES_TMPDIR=${1/--tmpdir=}
		;;
	--variants-file )
		variants_file="$2"
		shift
		;;
	--variants-file=* )
		variants_file="${1/--variants-file=}"
		;;
	--with )
		with_modules+=( "$2" )
		shift
		;;
	--with=*/* )
		m="${1/--with=}"
		with_modules+=( ${m} )
		;;
	--prep | --configure | --compile | --install | --all )
		target=$1
		;;
	--system )
		OS="$2"
		shift
		;;
	--system=* )
		OS="${1/--system=}"
		;;
	--version | -V )
		V=$2
		shift
		;;
	--version= )
		V=${1/--version=}
		;;
	--bootstrap )
		bootstrap='yes'
		;;
	[0-9]* )
		V=$1
		;;
	* )
	        declare -r BUILD_BLOCK=$(std::get_abspath "$1")
		declare -r BUILD_BLOCK_DIR=$(dirname "${BUILD_BLOCK}")
		;;
	esac
	shift
done

if [[ ${debug_on} == yes ]]; then
	trap 'echo "$BASH_COMMAND"' DEBUG
fi

[[ -n ${BUILD_BLOCK} ]] || std::die 1 "No build-block specified!"
[[ -r ${BUILD_BLOCK} ]] || std::die 1 "${BUILD_BLOCK}: no such file!"

declare -r OS


# source Pmodule environment configuration
if [[ "${bootstrap}" == "yes" ]]; then
	[[ -r ${BUILD_BLOCK_DIR}/../config/${pmodule_environment} ]] || \
		std::die 1 "Cannot read configuration file!"
        source "${BUILD_BLOCK_DIR}/../config/${pmodule_environment}"
	declare -r BUILD_BASEDIR=$(std::get_abspath "${BUILD_BLOCK_DIR}/..")
	
	if [[ -r "${BUILD_BLOCK_DIR}/../config/modbuild.conf" ]]; then
		source "${BUILD_BLOCK_DIR}/../config/modbuild.conf"
	fi
elif [[ -n ${PMODULES_ROOT} ]] && [[ -n ${PMODULES_CONFIG_DIR} ]] && \
     [[ -r ${PMODULES_ROOT}/${PMODULES_CONFIG_DIR}/${pmodule_environment} ]]; then
	source ${PMODULES_ROOT}/${PMODULES_CONFIG_DIR}/${pmodule_environment}
	declare -r BUILD_BASEDIR=$(std::get_abspath "${BUILD_BLOCK_DIR}/../..")
	if [[ -r "${PMODULES_ROOT}/config/modbuild.conf" ]]; then
		source "${PMODULES_ROOT}/config/modbuild.conf"
	fi

else
	std::die 3 "Build environment not setup properbly!"
fi

: ${PMODULES_TMPDIR:="${BUILD_BASEDIR}/tmp"}
: ${PMODULES_DISTFILESDIR:="${BUILD_BASEDIR}/Downloads"}

declare -x  PMODULES_TMPDIR
declare -x  PMODULES_DISTFILESDIR

declare -r BUILD_SCRIPTSDIR="${BUILD_BASEDIR}/scripts"
declare -r BUILD_VERSIONSFILE="${BUILD_BASEDIR}/config/versions.conf"

# source BASH library with standard functions
((ok=1))
for dir in "${bash_libpath[@]}"; do
        if [[ -r ${dir}/${libpbuild} ]]; then
		source "${dir}/${libpbuild}"
		ok=0
		break
	fi
done
(( ok == 0 )) || std::die 3 "Oops: required BASH library '${libpbuild}' not found"


if [[ ${bootstrap} == no ]]; then
	if [[ -n "${variants_file}" ]]; then
		if [[ ! -r "${variants_file}" ]]; then
			std::die 1 "${variants_file}: variants file does not exist or is not readable!"
		fi
	else
		search_variants_file || std::die 2 "No usable variants file found!"
	fi

        # initialize module environment
        source	"${PMODULES_ROOT}/${PMODULES_CONFIG_DIR}/profile.bash"
	MODULECMD="${PMODULES_HOME}/bin/modulecmd"
	[[ -x ${MODULECMD} ]] || std::die 1 "${MODULECMD}: no such executable"

	eval $( "${MODULECMD}" bash purge )
	eval $( "${MODULECMD}" bash use unstable )
	eval $( "${MODULECMD}" bash use deprecated )

	# :FIXME: this is a hack!!!
	eval $( "${MODULECMD}" bash use Libraries )

	# if version is not specified, use version from last line of variants file
	if [[ -z "$V" ]]; then
		local tmp=$(awk 'END{print $1}' "${variants_file}")
		V="${tmp#*/}"
	fi
else
	unset PMODULES_HOME
	unset PMODULES_VERSION
	std::read_versions "${BUILD_BASEDIR}/config/versions.conf"
	if [[ -z ${V} ]]; then
		_P=$(echo $P | tr [:lower:] [:upper:])
		_P=${_P//-/_}
		_V=${_P}_VERSION
		V=${!_V}
	fi
fi

declare V_MAJOR=${V%%.*}
declare tmp=${V#*.}
declare V_MINOR=${tmp%%.*}
tmp=${tmp#*.}
declare V_PATCHLVL=${tmp%%-*}
declare V_RELEASE=${tmp#*-}

P=$(basename $(dirname "${BUILD_BLOCK}"))

[[ -z ${V} ]] && std::die 1 "Module version must be specified on command line!"

#
# run build
#
source "${BUILD_BLOCK}"

std::info "${P}/${V}: Done ..."

# Local Variables:
# mode: sh
# sh-basic-offset: 8
# tab-width: 8
# End:
