#!/bin/bash
#
# Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
#     1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
#     2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014,
#     2015, 2016, 2017, 2018, 2019, 2020 Massachusetts Institute of
#     Technology
#
# This file is part of MIT/GNU Scheme.
#
# MIT/GNU Scheme 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 2 of the
# License, or (at your option) any later version.
#
# MIT/GNU Scheme 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 MIT/GNU Scheme; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
# 02110-1301, USA.

# Script to run a three-stage build.  Must be run from the top-level
# directory of an MIT/GNU clone.  By default, starts the build using
# the current binaries in the "linux" or "macosx" subdirectory,
# depending on the system.  Can be overridden by unpacking a binary
# dist into a "stage0" subdirectory.
#
# Creates new "stage1", "stage2", and "stage3" directories, compiling
# from one to the next.  If all three stages build correctly, then the
# compiler is reasonably functional.
#
# This script requires bash; don't try it with other shells.

set -e
shopt -s extglob

if ! [[ -d .git && -d src && -d etc ]]; then
    echo "This doesn't appear to be an MIT/GNU Scheme top-level directory." >&2
    exit 1
fi

if [[ ${1} = -n ]]; then
    declare -r NORUN=t
    shift
else
    declare -r NORUN=nil
fi

if [[ ${1} =~ ^-?([[:digit:]]+)$ ]]; then
    declare -ri MAX_STAGE=${BASH_REMATCH[1]}
    shift
else
    declare -ri MAX_STAGE=3
fi

CONFIG_ARGS=("${@}")

echo "NORUN = " "${NORUN}"
echo "MAX_STAGE =" "${MAX_STAGE}"
echo "CONFIG_ARGS =" "${CONFIG_ARGS[@]}"

# Hack for cph
if which cpx > /dev/null; then
    : ${COPY:="cpx -sqE"}
fi

run_stage ()
{
    local N=${1}
    local STAGE=stage${N}

    echo "**************** ${STAGE} ****************"
    find_stage stage$((N-1))
    echo "MIT_SCHEME_EXE =" "${MIT_SCHEME_EXE}"
    echo "MITSCHEME_LIBRARY_PATH =" "${MITSCHEME_LIBRARY_PATH}"
    [[ ${NORUN} = t ]] && return 0
    rm -rf ${STAGE}
    ${COPY} src ${STAGE}
    (set -e; cd ${STAGE}; ./Setup.sh && ./configure "${CONFIG_ARGS[@]}" && make)
    if ! [[ -f ${STAGE}/lib/all.com ]]; then
	echo "${STAGE} failed"
	exit 1
    fi
}

find_stage ()
{
    if [[ ${1} == stage0 ]]; then
        if [[ -n ${STAGE0} ]]; then
            find_build_stage "${STAGE0}" && return 0
        fi
        find_build_stage stage0 && return 0
	find_dist_stage $(pwd)/stage0 && return 0
        find_build_stage build && return 0
	find_dist_stage /usr/local && return 0
    else
        find_build_stage "${1}" && return 0
    fi
    echo "Unable to find ${1} executable" >&2
    exit 1
}

find_build_stage ()
{
    local STAGE=$(pwd)/${1}
    if [[ -x ${STAGE}/microcode/scheme && -f ${STAGE}/lib/all.com ]]; then
	export MIT_SCHEME_EXE=${STAGE}/microcode/scheme
	export MITSCHEME_LIBRARY_PATH=${STAGE}/lib
	return 0
    else
	return 1
    fi
}

find_dist_stage ()
{
    local STAGE=${1}
    local LIBDIRS=(${STAGE}/lib/mit-scheme*)
    if (( ${#LIBDIRS[@]} < 1 )); then
        return 1
    fi
    local LIBDIR=${LIBDIRS[0]}
    if [[ -x ${STAGE}/bin/mit-scheme && -f ${LIBDIR}/all.com ]]; then
	export MIT_SCHEME_EXE=${STAGE}/bin/mit-scheme
	export MITSCHEME_LIBRARY_PATH=${LIBDIR}
	return 0
    else
	return 1
    fi
}

find_stage0_default ()
{
    local root
    local suffix
    local candidate
    for root in "${@}"; do
        for suffix in "" -64 64 -32 32; do
            candidate=${root}${suffix}
            if [[ -d ${candidate} ]]; then
                echo "${candidate}"
                return
            fi
        done
    done
    for candidate in build svm1 svm; do
        if [[ -d ${candidate} ]]; then
            echo "${candidate}"
            return
        fi
    done
}

case $(uname -s) in
    Linux)
	: ${COPY:="cp -a"}
        if [[ -z ${STAGE0} ]]; then
            STAGE0=$(find_stage0_default gnu-linux linux debian ubuntu)
        fi
	;;
    Darwin)
	: ${COPY:="cp -pR"}
        if [[ -z ${STAGE0} ]]; then
            STAGE0=$(find_stage0_default macos macosx darwin)
        fi
	;;
    *)
	echo "Unknown system type: $(uname -s)" >&2
	exit 1
	;;
esac

rm -rf stage[123]
declare -i stage_number
for (( stage_number=1 ; stage_number <= MAX_STAGE ; stage_number++ )); do
    run_stage ${stage_number}
done
