#!/usr/bin/env bash

# FireSim initial setup script.

# exit script if any command fails
set -e
set -o pipefail

FDIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
cd "$FDIR"

IS_LIBRARY=false
USE_PINNED_DEPS=true
VERBOSE_FLAG=""

function usage
{
    echo "usage: build-setup.sh [OPTIONS]"
    echo "options:"
    echo "   --library: initializes FireSim as a library submodule"
    echo "   --unpinned-deps: use unpinned conda package dependencies"
    echo "   --verbose: verbose printout"
}

while test $# -gt 0
do
   case "$1" in
        --library)
            IS_LIBRARY=true;
            ;;
        --unpinned-deps)
            USE_PINNED_DEPS=false;
            ;;
        --verbose)
            VERBOSE_FLAG=$1
            set -x
            ;;
        -h | -H | --help)
            usage
            exit 3
            ;;
        --*) echo "ERROR: bad option $1"
            usage
            exit 1
            ;;
        *) echo "ERROR: bad argument $1"
            usage
            exit 2
            ;;
    esac
    shift
done

# Remove and backup the existing env.sh if it exists
# The existing of env.sh implies this script completely correctly
if [ -f env.sh ]; then
    mv -f env.sh env.sh.backup
fi

# This will be flushed out into a complete env.sh which will be written out
# upon completion.
env_string="# This file was generated by $0"
ENV_SH="$FDIR/env.sh"

function env_append {
    env_string+=$(printf "\n$1")
}

# Initially, create a env file that suggests build.sh did not run correctly.
cat >${ENV_SH} <<END_INITIAL_ENV_SH
${env_string}
echo "ERROR: build-setup.sh did not execute correctly or was terminated prematurely."
echo "Please review build-setup-log for more information."
END_INITIAL_ENV_SH

env_append "export FIRESIM_ENV_SOURCED=1"
env_append "export FS_DIR=${FDIR}"

#### Conda setup ####

if [ "$IS_LIBRARY" = true ]; then
    # old code from before (probably redundant w/ other check below)
    if [ -z "$RISCV" ]; then
        echo "ERROR: You must set the RISCV environment variable before running."
        exit 4
    else
        echo "Using existing RISCV toolchain at $RISCV"
    fi

    # the chipyard conda environment should be installed already and have all requirements
    if [ -z "${CONDA_DEFAULT_ENV+x}" ]; then
        echo "ERROR: No conda environment detected. If using Chipyard, did you source 'env.sh'."
        exit 5
    fi
else
    # create conda-lock only environment to be used in this section.
    # done with cloning base then installing conda lock to speed up dependency solving.
    CONDA_LOCK_ENV_PATH=$FDIR/.conda-lock-env
    rm -rf $CONDA_LOCK_ENV_PATH
    conda create -y -p $CONDA_LOCK_ENV_PATH -c conda-forge $(grep "conda-lock" $FDIR/conda-reqs/firesim.yaml | sed 's/^ \+-//')
    source $(conda info --base)/etc/profile.d/conda.sh
    conda activate $CONDA_LOCK_ENV_PATH

    # create the firesim environment with all requirements (chipyard's, firemarshal's, etc)

    # note: lock file must end in .conda-lock.yml - see https://github.com/conda-incubator/conda-lock/issues/154
    if [ "$USE_PINNED_DEPS" = false ]; then
        # auto-gen the lockfile
        ./scripts/generate-conda-lockfile.sh
    fi
    LOCKFILE="$(find $FDIR/conda-reqs/*.conda-lock.yml)"

    # create environment with conda-lock
    conda-lock install --conda $(which conda) -p $FDIR/.conda-env $LOCKFILE

    # activate environment for downstream steps
    source $FDIR/.conda-env/etc/profile.d/conda.sh
    conda activate $FDIR/.conda-env

    # provide a sourceable snippet that can be used in subshells that may not have
    # inhereted conda functions that would be brought in under a login shell that
    # has run conda init (e.g., VSCode, CI)
    read -r -d '\0' CONDA_ACTIVATE_PREAMBLE <<'END_CONDA_ACTIVATE'
if ! type conda >& /dev/null; then
    echo "::ERROR:: you must have conda in your environment first"
    return 1  # don't want to exit here because this file is sourced
fi

source $(conda info --base)/etc/profile.d/conda.sh
\0
END_CONDA_ACTIVATE
    env_append "$CONDA_ACTIVATE_PREAMBLE"
    env_append "conda activate $FDIR/.conda-env"
fi


# init all submodules except for chipyard
git config submodule.target-design/chipyard.update none
git submodule update --init --recursive


if [ "$IS_LIBRARY" = true ]; then
    #### Chipyard setup ####

    # TODO: need a better way to remove chipyard references
    CHIPYARD_DIR="$FDIR/../.."

    # chipyard env.sh should be sourced in library mode.
    env_append "source $CHIPYARD_DIR/env.sh"
fi

cd "$FDIR"

#### EC2-only setup ####

# see if the instance info page exists. if not, we are not on ec2.
# this is one of the few methods that works without sudo
if wget -T 1 -t 3 -O /dev/null http://169.254.169.254/latest/; then

    (
        # ensure that we're using the system toolchain to build the kernel modules
        # newer gcc has --enable-default-pie and older kernels think the compiler
        # is broken unless you pass -fno-pie but then I was encountering a weird
        # error about string.h not being found
        export PATH=/usr/bin:$PATH

        cd "$FDIR/platforms/f1/aws-fpga/sdk/linux_kernel_drivers/xdma"
        make

        # since we are on ec2 and it uses centos7 (which is EOL), we need to use the vault yum repos
        # taken from: https://serverfault.com/questions/904304/could-not-resolve-host-mirrorlist-centos-org-centos-7
        sudo sh -c "cat >/etc/yum.repos.d/CentOS-Base.repo" <<-EOF
[base]
name=CentOS-\$releasever - Base
baseurl=http://vault.centos.org/7.9.2009/os/\$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

[updates]
name=CentOS-\$releasever - Updates
baseurl=http://vault.centos.org/7.9.2009/updates/\$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

[extras]
name=CentOS-\$releasever - Extras
baseurl=http://vault.centos.org/7.9.2009/extras/\$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

[centosplus]
name=CentOS-\$releasever - Plus
baseurl=http://vault.centos.org/7.9.2009/centosplus/\$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
EOF
        sudo yum clean all

        # the only ones missing are libguestfs-tools
        sudo yum install -y libguestfs-tools bc

        # Setup for using qcow2 images
        cd "$FDIR"
        ./scripts/install-nbd-kmod.sh
    )

    (
        if [[ "${CPPFLAGS:-zzz}" != "zzz" ]]; then
            # don't set it if it isn't already set but strip out -DNDEBUG because
            # the sdk software has assertion-only variable usage that will end up erroring
            # under NDEBUG with -Wall and -Werror
            export CPPFLAGS="${CPPFLAGS/-DNDEBUG/}"
        fi


        # Source {sdk,hdk}_setup.sh once on this machine to build aws libraries and
        # pull down some IP, so we don't have to waste time doing it each time on
        # worker instances
        AWSFPGA="$FDIR/platforms/f1/aws-fpga"
        cd "$AWSFPGA"
        bash -c "source ./sdk_setup.sh"
        bash -c "source ./hdk_setup.sh"
    )

fi

cd "$FDIR"
set +e
./gen-tags.sh
set -e

read -r -d '\0' NDEBUG_CHECK <<'END_NDEBUG'
# Ensure that we don't have -DNDEBUG anywhere in our environment

# check and fixup the known place where conda will put it
if [[ "$CPPFLAGS" == *"-DNDEBUG"* ]]; then
    echo "::INFO:: removing '-DNDEBUG' from CPPFLAGS as we prefer to leave assertions in place"
    export CPPFLAGS="${CPPFLAGS/-DNDEBUG/}"
fi

# check for any other occurances and warn the user
env | grep -v 'CONDA_.*_BACKUP' | grep -- -DNDEBUG && echo "::WARNING:: you still seem to have -DNDEBUG in your environment. This is known to cause problems."
true # ensure ${ENV_SH} exits 0
\0
END_NDEBUG
env_append "$NDEBUG_CHECK"

# Write out the generated env.sh indicating successful completion.
echo "$env_string" > ${ENV_SH}

echo "Setup complete!"
echo "To get started, source sourceme-manager.sh to setup your environment."
echo "For more information, see docs at https://docs.fires.im/."
