#!/bin/bash
#
# The following build specific variables are set and used in libpbuild.bash:
#       ARGS
#       BUILD_SCRIPT
#       BUILDBLOCK_DIR
#
#.............................................................................
# get absolute path of script
declare	    mydir=$(dirname "$0")
declare -r  mydir=$(cd ${mydir} && pwd -P)

PATH="/usr/bin:/bin:/usr/sbin:/sbin"

# add pathes where files we have to source are installed
PATH+=":${mydir}:${mydir}/../lib:${mydir}/../config"

source libstd.bash    || { echo "Oops: library '$_' cannot be loaded!" 1>&2; exit 3; }

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

##############################################################################
#
usage() {
	std::error "
USAGE:
        $0 [options..] [build_script] version

MANDATORY ARGUMENTS:

version
        Variant of module to build.

SELECT VARIANT TO BUILD:

--system
        Specify the system for selecting a variants. Defaults to the
	output of 'uname -s'.

--with=P/V
        Select variant to compile. Use multiple '--with' arguments
	to make the selected variant unique.

BUILD-STEPS OPTIONS:

--prep
	Prepare sources: unpack sources and apply patches only.

--configure
	Prepare and configure sources.

--compile
	Prepare, configure and compile everything.

--install
	Prepare, configure and compile everything. Finally run install
	step. Do not cleanup build and source directory.

--all
	Run throu all steps including cleanup.

--update-modulefiles
	Only install the modulefile and set the release.

MISCELLANEOUS OPTIONS:

-? | -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.

--all-variants
        Build build all variants

--disable-cleanup-build
--enable-cleanup-build
	Cleanup files in the build directory. Default is to remove.
      	all files in the build-directory.

--disable-cleanup-src
--enable-cleanup-src
	Cleanup files in the source directory. Default is to
	remove all files in the source directory.

--disable-cleanup
--enable-cleanup
	Cleanup all files in temporyry directory. Default is to
	remove all files created during building.

--distdir
	Directory wwhere to store and lookup downloaded files.

--tmpdir
        Directory used for building a module.

"
	exit 1
}

##############################################################################
#
# parse options and arguments
#

# multiple version can be passed via comand line
declare -a      versions=()
declare         opt_all_variants='no'
declare         opt_bootstrap='no'
# array collecting all modules specified on the command line via '--with=module'
declare -a      opt_with_modules=()
declare 	build_config='modbuild.conf'
declare         system="$(uname -s)"

parse_args() {
	while (( $# > 0 )); do
		case $1 in
		-j )
			pbuild.jobs "$2"
			shift
			;;
		--jobs=[0-9]* )
			pbuild.jobs "${1/--jobs=}"
			;;
		-v | --verbose )
			trap 'echo "$BASH_COMMAND"' DEBUG
			;;
		--debug )
			set -x
			;;
		-f | --force-rebuild )
			pbuild.force_rebuild 'yes'
			;;
		-\? | -h | --help )
			usage
			;;
		--dry-run )
			pbuild.dry_run 'yes'
			;;
                --all-variants )
                        opt_all_variants='yes'
                        ;;
		--config )
			build_config="$2"
			shift 1
			;;
		--config=* )
			build_config="${1#*=}"
			;;
		--disable-cleanup )
			pbuild.enable_cleanup_build 'no'
			pbuild.enable_cleanup_src 'no'
			;;
		--enable-cleanup-build )
			pbuild.enable_cleanup_build 'yes'
			;;
		--disable-cleanup-build )
			pbuild.enable_cleanup_build 'no'
			;;
		--enable-cleanup-src )
			pbuild.enable_cleanup_src 'yes'
			;;
		--disable-cleanup-src )
			pbuild.enable_cleanup_src 'no'
			;;
		--distdir )
			pbuild.pmodules_distfilesdir "$2"
			shift
			;;
		--distdir=* )
			pbuild.pmodules_distfilesdir "${1/--distdir=}"
			;;
		--tmpdir )
			pbuild.temp_dir "$2"
			shift
			;;
		--tmpdir=* )
			pbuilf.temp_dir "${1/--tmpdir=}"
			;;
		--system )
			system=".$2"
                        pbuild.system "${system}"
			shift
			;;
		--system=* )
			system=".${1/*=}"
                        pbuild.system "${system}"
			;;
		--with )
			opt_with_modules+=( "$2" )
			shift
			;;
		--with=*/* )
			m="${1/--with=}"
			opt_with_modules+=( ${m} )
			;;
		--prep | --configure | --compile | --install | --all )
			pbuild.build_target ${1:2}
			;;
		--bootstrap )
			opt_bootstrap='yes'
			;;
		--update-modulefiles )
			pbuild.update_modulefiles 'yes'
			;;
		-* )
			std::die 1 "Invalid option -- '$1'"
			;;
		[0-9]* )
			versions+=( "$1" )
			;;
		'')	
			:
			;;
		* )
			[[ -z "${BUILD_SCRIPT}" ]] || \
				std::die 1 "%s "\
					 "Build script already set to" \
					 "'${BUILD_SCRIPT}' -- '$1'"
		        BUILD_SCRIPT=$(std::get_abspath "$1")
			test -r ${BUILD_SCRIPT} || \
				std::die 1 "%s " \
					 "Build script does not exist" \
					 "or is not readable -- '$_'"
			BUILDBLOCK_DIR=$(dirname "${BUILD_SCRIPT}")
			;;
		esac
		shift
	done	
	[[ -n ${BUILD_SCRIPT} ]] || std::die 1 "No build-block specified!"
	(( ${#versions[@]} > 0)) || std::die 1 "Module version not specified!"
}

find_variants_files(){
        shopt -q nullglob || :
        local -i nullglob_set=$?
        shopt -s nullglob
	local files=( "${BUILDBLOCK_DIR}"/*/variants.${system} )
        local f
	for f in "${BUILDBLOCK_DIR}"/*/variants; do
		[[ -e "${f}.${system}" ]] || files+=( "$f" )
	done
        (( nullglob_set == 1 )) && shopt -u nullglob
	std::upvar "$1" "${files[@]}"
}

build_modules() {
        local name="$1"
        local version="$2"
        local exact_match='no'
        if [[ "${version:0:1}" == "=" ]]; then
                exact_match='yes'
                version="${version:1}"
        fi
        shift 2
        local with_modules=( $* )
        local files
        find_variants_files files
        local m
	local pattern="/^${name}\/${version}[[:blank:]]/"
	for m in "${with_modules[@]}"; do 
		pattern+=" && /${m//\//\\/}/"
	done
        local variants=()
        local variants_files=()
        local line=''
        local lines=()
        for f in "${files[@]}"; do
                while read line; do
                        lines+=( "${line}" )
                done < <(awk "${pattern}" "${f}")
                variants+=( "${lines[@]}" )
                local i
                for ((i=0; i<${#lines[@]}; i++)); do
                        variants_files+=( "$f" )
                done
                # here we should add a check, whether the version of the
                # found variants are in the right variants files. Example:
                # a variant for hdf5/1.10.4 is not allowed in a variants file
                # for version 1.8
        done
        if (( ${#variants[@]} == 0 )); then
		std::info "%s " \
			 "${name}/${version}:" \
			 "no suitable variant found!"
                std::die 10 "Aborting..."
        elif (( ${#variants[@]} > 1 )) && [[ ${exact_match} == 'yes' ]]; then
		std::info "%s " \
			 "Multiple variants found:"
                for variant in "${variants[@]}"; do
                        std::info "${variant}"
                done
                std::die 10 "Aborting..."
        fi
        local -i i=0
        local -i num_variants=${#variants[@]}
        for ((i = 0; i < num_variants; i++)); do
                local tokens=( ${variants[i]} )
                local name="${tokens[0]%/*}"
                version="${tokens[0]#*/}"
                release="${tokens[1]}"
                with_modules=( "${tokens[@]:2}" )
                pbuild.build_module \
                        "${name}" "${version}" \
                        "${release}" "${with_modules[@]}"
        done
}

#.............................................................................
# main
source libpbuild.bash || std::die 3 "Oops: library '$_' cannot be loaded!"

parse_args "$@"

declare -r BUILD_SCRIPT
declare -r BUILDBLOCK_DIR

IFS=/ read -r -a fname <<< "${BUILD_SCRIPT:1}"
module_name=${fname[${#fname[@]}-2]}

#
# are we bootstrapping? If yes, go for it...
#
if [[ "${opt_bootstrap}" == 'yes' ]]; then
        test -d ":${BUILDBLOCK_DIR}/../../${PMODULES_CONFIG_DIR}" && PATH+=":$_"
        source "${build_config}" || std::die 3 "Cannot source build configuration file."
	pbuild.bootstrap "${module_name}"  "${versions[0]}" 'stable'
        exit $?
fi

#
# we are NOT bootstrapping!
#

# source Pmodule environment configuration
test -d "${PMODULES_ROOT}/${PMODULES_CONFIG_DIR}" && PATH+=":$_"
source "${build_config}" || std::die 3 "Cannot source build configuration file."

# if option '--all-variants' is set, we loop over all variants matching the given
# versions
for version in "${versions[@]}"; do
        if [[ "${opt_all_variants}" == "no" ]]; then
                version="=${version}"
        fi
        build_modules "${module_name}" "${version}" "${opt_with_modules[@]}"
done

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