#!/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).

--with=P/V
        Preload module P with version V. To preload multiple modules,
        use this option per module. Nete that 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 gdate 2>/dev/null || : )
if [[ $__path ]]; then
	alias date=$__path
else
	alias date=$(which date 2>/dev/null)
fi

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

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

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


declare	    ok=1

##############################################################################
#
# source BASH library with standard functions
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

# :FIXME: move to library?
declare -r OS=$(uname -s)

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

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

debug_on='no'
force_rebuild='no'
dry_run='no'
enable_cleanup_build='yes'
enable_cleanup_src='no'
target='all'
module_release=''

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

# save arguments for building dependencies
declare -rx ARGS="$@"

# 
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=}
		;;
	--release )
		module_release=$2
		shift
		;;
	--release=* )
		module_release=${1/--release=}
		;;
	--with )
		with_modules+=( "$2" )
		shift
		;;
	--with=*/* )
		with_modules+=( ${1/--with=} )
		;;
	--prep | --configure | --compile | --install | --all )
		target=$1
		;;
	[0-9]* )
		V=$1
		;;
	* )
	        declare -rx BUILD_BLOCK=$(std::get_abspath "$1")
		declare -rx 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!"



# source Pmodule environment configuration
if [[ -r ${BUILD_BLOCK_DIR}/../config/${pmodule_environment} ]]; then
	# we are bootstrapping
        source "${BUILD_BLOCK_DIR}/../config/${pmodule_environment}"
	declare -rx BUILD_BASEDIR=$(std::get_abspath "${BUILD_BLOCK_DIR}/..")
	bootstrap='yes'
	
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 -rx BUILD_BASEDIR=$(std::get_abspath "${BUILD_BLOCK_DIR}/../..")
	bootstrap='no'

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 -xr BUILD_SCRIPTSDIR="${BUILD_BASEDIR}/scripts"
declare -xr 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"

# load all modules passed with the '--with' argument
if [[ ${bootstrap} == no ]]; then
	# we aren't bootstraping
	if [[ -r "${BUILD_BLOCK_DIR}/with_modules-$V" ]]; then
		with_modules+=( $(cat "${BUILD_BLOCK_DIR}/with_modules-$V") )
	elif [[ -r "${BUILD_BLOCK_DIR}/with_modules" ]]; then
		with_modules+=( $(cat "${BUILD_BLOCK_DIR}/with_modules") )
	fi

        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 )
	
	# Unset all PATH's and FLAGS's which might be used by a compiler.
	# This includes C_INCLUDE_PATH, CFLAGS etc.
	pbuild::cleanup_env
	pbuild::set_initial_path
	PATH+="${mydir}"

	eval $( "${MODULECMD}" bash use unstable )
	# :FIXME: this is a hack!!!
	module use Libraries
	for m in "${with_modules[@]}"; do
		if pbuild::module_is_available "$m"; then
			echo "Loading module: ${m}"
			module load "${m}"
		else
			std::die 44 "$m: module not available!"
		fi
	done
else
	#  the module command is not yet available...
	pbuild::cleanup_env
	pbuild::set_initial_path
	PATH+="${mydir}"
	unset PMODULES_HOME
	unset PMODULES_VERSION
	std::read_versions "${BUILD_BASEDIR}/config/versions.conf"
fi

P=$(basename $(dirname "${BUILD_BLOCK}"))
P=${P%.*}

if [[ -z ${V} ]]; then
	_P=$(echo $P | tr [:lower:] [:upper:])
	_P=${_P//-/_}
	_V=${_P}_VERSION
	V=${!_V}
fi

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


# :FIXME: do we need this? Can we get rid of 'releases'?
if [[ -n ${PMODULES_DEFINED_RELEASES} ]]; then
        declare -r releases="${PMODULES_DEFINED_RELEASES}"
else
	# set defaults
	declare -r releases=":unstable:stable:deprecated:"
fi

[[ -n ${module_release} ]] && pbuild::set_release "${module_release}"

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

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

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