#!/usr/bin/env bash

cd "$(dirname "$0")"

# turn on verbose debugging output for parabuild logs.
exec 4>&1; export BASH_XTRACEFD=4; set -x
# make errors fatal
set -e
# complain about unreferenced environment variables
set -u

if [ -z "$AUTOBUILD" ] ; then
    exit 1
fi

if [ "$OSTYPE" = "cygwin" ] ; then
    autobuild="$(cygpath -u $AUTOBUILD)"
else
    autobuild="$AUTOBUILD"
fi

# Restore all .sos
restore_sos ()
{
    for solib in "${stage}"/packages/lib/{debug,release}/*.so*.disable; do
        if [ -f "$solib" ]; then
            mv -f "$solib" "${solib%.disable}"
        fi
    done
}


# Restore all .dylibs
restore_dylibs ()
{
    for dylib in "$stage/packages/lib"/{debug,release}/*.dylib.disable; do
        if [ -f "$dylib" ]; then
            mv "$dylib" "${dylib%.disable}"
        fi
    done
}

top="$(pwd)"
stage="$top/stage"

[ -f "$stage"/packages/include/zlib/zlib.h ] || \
{ echo "You haven't yet run 'autobuild install'." 1>&2; exit 1; }

# load autobuild provided shell functions and variables
source_environment_tempfile="$stage/source_environment.sh"
"$autobuild" source_environment > "$source_environment_tempfile"
. "$source_environment_tempfile"

OPENSSL_SOURCE_DIR="openssl"
# Look in crypto/opensslv.h instead of the more obvious
# include/openssl/opensslv.h because the latter is (supposed to be) a symlink
# to the former. That works on Mac and Linux but not Windows: on Windows we
# get a plain text file containing the relative path to crypto/opensslv.h, and
# a very strange "version number" because perl can't find
# OPENSSL_VERSION_NUMBER. (Sigh.)
raw_version=$(perl -ne 's/#\s*define\s+OPENSSL_VERSION_NUMBER\s+([\d]+)/$1/ && print' "${OPENSSL_SOURCE_DIR}/include/openssl/opensslv.h")

major_version=$(echo ${raw_version:2:1})
minor_version=$((10#$(echo ${raw_version:3:2})))
build_version=$((10#$(echo ${raw_version:5:2})))

patch_level_hex=$(echo $raw_version | cut -c 8-9)
patch_level_dec=$((16#$patch_level_hex))
str="abcdefghijklmnopqrstuvwxyz"
patch_level_version=$(echo ${str:patch_level_dec-1:1})

version_str=${major_version}.${minor_version}.${build_version}${patch_level_version}

build=${AUTOBUILD_BUILD_ID:=0}
echo "${version_str}.${build}" > "${stage}/VERSION.txt"

pushd "$OPENSSL_SOURCE_DIR"
    case "$AUTOBUILD_PLATFORM" in

        windows*)
            load_vsvars
            mkdir -p "$stage/lib/debug"
            mkdir -p "$stage/lib/release"

            if [ "$AUTOBUILD_ADDRSIZE" = 32 ]
            then
                targetname_debug="debug-VC-WIN32"
                targetname_release="VC-WIN32"
                target_flags=""
                libsuffix=""
            else
                targetname_debug="debug-VC-WIN64A"
                targetname_release="VC-WIN64A"
                target_flags="-arch:AVX"
                libsuffix="-x64"
            fi

            # Debug build:
            perl Configure "$targetname_debug" $target_flags zlib threads \
                --with-zlib-include="$(cygpath -w "$stage/packages/include/zlib")" \
                --with-zlib-lib="$(cygpath -w "$stage/packages/lib/debug/zlibd.lib")"

            nmake

            # conditionally run unit tests
            if [ "${DISABLE_UNIT_TESTS:-0}" = "0" ]; then
                nmake test
            fi

            cp -a {libcrypto,libssl}.lib "$stage/lib/debug"
            cp -a {libcrypto-1_1"${libsuffix}",libssl-1_1"${libsuffix}"}.dll "$stage/lib/debug"
            cp -a {libcrypto-1_1"${libsuffix}",libssl-1_1"${libsuffix}"}.pdb "$stage/lib/debug"

            # Clean
            nmake distclean

            # Release build:
            perl Configure "$targetname_release" $target_flags zlib threads \
                --with-zlib-include="$(cygpath -w "$stage/packages/include/zlib")" \
                --with-zlib-lib="$(cygpath -w "$stage/packages/lib/release/zlib.lib")"

            nmake

            # conditionally run unit tests
            if [ "${DISABLE_UNIT_TESTS:-0}" = "0" ]; then
                nmake test
            fi

            cp -a {libcrypto,libssl}.lib "$stage/lib/release"
            cp -a {libcrypto-1_1"${libsuffix}",libssl-1_1"${libsuffix}"}.dll "$stage/lib/release"
            cp -a {libcrypto-1_1"${libsuffix}",libssl-1_1"${libsuffix}"}.pdb "$stage/lib/release"

            # Publish headers
            mkdir -p "$stage/include/openssl"
            cp -a include/openssl/*.h "$stage/include/openssl"

            # Clean
            nmake distclean
        ;;

        darwin*)
            # Install name for dylibs based on major version number
            # Not clear exactly why Configure/make generates lib*.1.0.0.dylib
            # for ${major_version}.${minor_version}.${build_version} == 1.0.1,
            # but obviously we must correctly predict the dylib filenames.
            crypto_target_name="libcrypto.${major_version}.${minor_version}.dylib"
            crypto_install_name="@executable_path/../Resources/${crypto_target_name}"
            ssl_target_name="libssl.${major_version}.${minor_version}.dylib"
            ssl_install_name="@executable_path/../Resources/${ssl_target_name}"

            # Force static linkage by moving .dylibs out of the way
            trap restore_dylibs EXIT
            for dylib in "$stage/packages/lib"/{debug,release}/*.dylib; do
                if [ -f "$dylib" ]; then
                    mv "$dylib" "$dylib".disable
                fi
            done

            opts="-arch x86_64 -iwithsysroot macosx10.15 -mmacosx-version-min=10.13 -fno-strict-aliasing -mavx -mprefer-vector-width=128 -g"
            ldopts="-Wl,-headerpad_max_install_names"

            targetname="darwin64-x86_64-cc"
            targetname_debug="debug-darwin64-x86_64-cc"

            # Debug
            ./Configure zlib threads shared $targetname_debug "-Og $opts" $ldopts \
                --prefix="$stage" --libdir="lib/debug" --openssldir="share" \
                --with-zlib-include="$stage/packages/include/zlib" \
                --with-zlib-lib="$stage/packages/lib/debug/libz.a" \
                -L"$stage/packages/lib/debug/"
            make depend
            make
            make install_sw

            # conditionally run unit tests
            if [ "${DISABLE_UNIT_TESTS:-0}" = "0" ]; then
                make test
            fi

            make distclean

            # Release
            ./Configure zlib threads shared $targetname "-O3 $opts" $ldopts \
                --prefix="$stage" --libdir="lib/release" --openssldir="share" \
                --with-zlib-include="$stage/packages/include/zlib" \
                --with-zlib-lib="$stage/packages/lib/release/libz.a" \
                -L"$stage/packages/lib/release/"
            make depend
            make
            make install_sw

            # conditionally run unit tests
            if [ "${DISABLE_UNIT_TESTS:-0}" = "0" ]; then
                make test
            fi

            make distclean

            # Modify .dylib path information.  Do this after install
            # to the copies rather than built or the dylib's will be
            # linked again wiping out the install_name.
            debug_crypto_stage_name="${stage}/lib/debug/${crypto_target_name}"
            debug_ssl_stage_name="${stage}/lib/debug/${ssl_target_name}"
            release_crypto_stage_name="${stage}/lib/release/${crypto_target_name}"
            release_ssl_stage_name="${stage}/lib/release/${ssl_target_name}"
            chmod u+w "${debug_crypto_stage_name}" "${debug_ssl_stage_name}" "${release_crypto_stage_name}" "${release_ssl_stage_name}"
            install_name_tool -id "${ssl_install_name}" "${debug_ssl_stage_name}"
            install_name_tool -id "${crypto_install_name}" "${debug_crypto_stage_name}"
            install_name_tool -change "${debug_crypto_stage_name}" "${crypto_install_name}" "${debug_ssl_stage_name}"
            install_name_tool -id "${ssl_install_name}" "${release_ssl_stage_name}"
            install_name_tool -id "${crypto_install_name}" "${release_crypto_stage_name}"
            install_name_tool -change "${release_crypto_stage_name}" "${crypto_install_name}" "${release_ssl_stage_name}"

        ;;

        linux*)
            # Linux build environment at Linden comes pre-polluted with stuff that can
            # seriously damage 3rd-party builds.  Environmental garbage you can expect
            # includes:
            #
            #    DISTCC_POTENTIAL_HOSTS     arch           root        CXXFLAGS
            #    DISTCC_LOCATION            top            branch      CC
            #    DISTCC_HOSTS               build_name     suffix      CXX
            #    LSDISTCC_ARGS              repo           prefix      CFLAGS
            #    cxx_version                AUTOBUILD      SIGN        CPPFLAGS
            #
            # So, clear out bits that shouldn't affect our configure-directed build
            # but which do nonetheless.
            #
            # unset DISTCC_HOSTS CC CXX CFLAGS CPPFLAGS CXXFLAGS

            # Default target per AUTOBUILD_ADDRSIZE
            opts="${TARGET_OPTS:--m$AUTOBUILD_ADDRSIZE -fPIC -DPIC}"

            # Handle any deliberate platform targeting
            if [ -z "${TARGET_CPPFLAGS:-}" ]; then
                # Remove sysroot contamination from build environment
                unset CPPFLAGS
            else
                # Incorporate special pre-processing flags
                export CPPFLAGS="${TARGET_CPPFLAGS:-}"
            fi

            # Force static linkage to libz by moving .sos out of the way
            trap restore_sos EXIT
            for solib in "${stage}"/packages/lib/debug/*.so* "${stage}"/packages/lib/release/*.so*; do
                if [ -f "$solib" ]; then
                    mv -f "$solib" "$solib".disable
                fi
            done

            if [ "$AUTOBUILD_ADDRSIZE" = 32 ]
            then
                targetname='linux-x86'
                targetname_debug='debug-linux-x86'
            else
                targetname='linux-x86_64'
                targetname_debug='debug-linux-x86_64'
            fi

            # '--libdir' functions a bit different than usual.  Here it names
            # a part of a directory path, not the entire thing.  Same with
            # '--openssldir' as well.
            # "shared" means build shared and static, instead of just static.
            ./Configure zlib threads shared "$targetname_debug" "$opts -Og -g" \
                --prefix="$stage" --libdir="lib/debug" --openssldir="share" \
                --with-zlib-include="$stage/packages/include/zlib" \
                --with-zlib-lib="$stage/packages/lib/debug/libz" \
                -L"$stage/packages/lib/debug/"
            make depend
            make
            make install_sw

            # conditionally run unit tests
            if [ "${DISABLE_UNIT_TESTS:-0}" = "0" ]; then
                make test
            fi

            make distclean

            ./Configure zlib threads shared "$targetname" "$opts -O3 -g -fstack-protector-strong -D_FORTIFY_SOURCE=2" \
                --prefix="$stage" --libdir="lib/release" --openssldir="share" \
                --with-zlib-include="$stage/packages/include/zlib" \
                --with-zlib-lib="$stage/packages/lib/release/libz" \
                -L"$stage/packages/lib/release/"
            make depend
            make
            make install_sw

            # conditionally run unit tests
            if [ "${DISABLE_UNIT_TESTS:-0}" = "0" ]; then
                make test
            fi

            make distclean

            # By default, 'make install' leaves even the user write bit off.
            # This causes trouble for us down the road, along about the time
            # the consuming build tries to strip libraries.  It's easier to
            # make writable here than fix the viewer packaging.
            chmod u+w "$stage"/lib/debug/lib{crypto,ssl}.so*
            chmod u+w "$stage"/lib/release/lib{crypto,ssl}.so*
        ;;
    esac
    mkdir -p "$stage/LICENSES"
    cp -a LICENSE "$stage/LICENSES/openssl.txt"
popd

mkdir -p "$stage"/docs/openssl/
cp -a README.Linden "$stage"/docs/openssl/
