#!/bin/sh -e
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.

# next steps:
# try running this, figure out what to do with the vars in the generated files
# in the bottom

# cd into this script’s directory
rootdir="$(cd "${0%/*}" 2>/dev/null; echo "$PWD")"
basename=`basename $0`

PACKAGE_AUTHOR_NAME="The Apache Software Foundation"

REBAR3_BRANCH="main"

# TEST=0
WITH_PROPER="true"
WITH_FAUXTON=1
WITH_DOCS=1
ERLANG_MD5="false"
SKIP_DEPS=0

run_erlang() {
    erl -noshell -eval "$1" -eval "halt()."
}

COUCHDB_USER="$(whoami 2>/dev/null || echo couchdb)"
SM_VSN=${SM_VSN:-"1.8.5"}
ARCH="$(uname -m)"
ERLANG_VER="$(run_erlang 'io:put_chars(erlang:system_info(otp_release)).')"
ERLANG_OS="$(run_erlang 'case os:type() of {OS, _} -> io:format("~s~n", [OS]) end.')"

. ${rootdir}/version.mk
COUCHDB_VERSION=${vsn_major}.${vsn_minor}.${vsn_patch}

display_help () {
    cat << EOF
Usage: $basename [OPTION]

The $basename command is responsible for generating the build
system for Apache CouchDB.

Options:

  -h | --help                 display a short help message and exit
  -u | --user USER            set the username to run as (defaults to $COUCHDB_USER)
  --disable-fauxton           do not build Fauxton
  --disable-docs              do not build any documentation or manpages
  --erlang-md5                use erlang for md5 hash operations
  --dev                       alias for --disable-docs --disable-fauxton
  --spidermonkey-version VSN  specify the version of SpiderMonkey to use (defaults to $SM_VSN)
  --skip-deps                 do not update erlang dependencies
  --rebar=PATH                use rebar by specified path (version >=2.6.0 && <3.0 required)
  --generate-tls-dev-cert     generate a cert for TLS distribution (To enable TLS, change the vm.args file.)
  --rebar3=PATH               use rebar3 by specified path
  --erlfmt=PATH               use erlfmt by specified path
EOF
}

# This is just an example to generate a certfile for TLS distribution.
# This is not an endorsement of specific expiration limits, key sizes, or algorithms.
generate_tls_dev_cert() {
    if [ ! -e "${rootdir}/dev/erlserver.pem" ]; then
        openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
        cat key.pem cert.pem > dev/erlserver.pem && rm key.pem cert.pem
    fi

    if [ ! -e "${rootdir}/dev/couch_ssl_dist.conf" ]; then
        cat > "${rootdir}/dev/couch_ssl_dist.conf" << EOF
[{server,
  [{certfile, "${rootdir}/dev/erlserver.pem"},
   {secure_renegotiate, true}]},
 {client,
  [{secure_renegotiate, true}]}].
EOF
    fi
}

parse_opts() {
    while :; do
        case $1 in
            -h|--help)
                display_help
                exit
                ;;

            --without-proper)
                WITH_PROPER="false"
                shift
                continue
                ;;

            --disable-fauxton)
                WITH_FAUXTON=0
                shift
                continue
                ;;

            --disable-docs)
                WITH_DOCS=0
                shift
                continue
                ;;

            --erlang-md5)
                ERLANG_MD5="true"
                shift
                continue
                ;;

            --dev)
                WITH_DOCS=0
                WITH_FAUXTON=0
                shift
                continue
                ;;

            --skip-deps)
                SKIP_DEPS=1
                shift
                continue
                ;;

            --rebar)
                if [ -x "$2" ]; then
                    version=`$2 --version 2> /dev/null | grep -o "2\.[6-9]\.[0-9]"`
                    if [ $? -ne 0 ]; then
                        printf 'Rebar >=2.6.0 and <3.0.0 required' >&2
                        exit 1
                    fi
                    eval REBAR=$2
                    shift 2
                    continue
                else
                    printf 'ERROR: "--rebar" requires valid path to executable.\n' >&2
                    exit 1
                fi
                ;;

            --rebar3)
                if [ -x "$2" ]; then
                    eval REBAR3=$2
                    shift 2
                    continue
                else
                    printf 'ERROR: "--rebar3" requires valid path to executable.\n' >&2
                    exit 1
                fi
                ;;

            --erlfmt)
                if [ -x "$2" ]; then
                    eval ERLFMT=$2
                    shift 2
                    continue
                else
                    printf 'ERROR: "--erlfmt" requires valid path to executable.\n' >&2
                    exit 1
                fi
                ;;

            --user|-u)
                if [ -n "$2" ]; then
                    eval COUCHDB_USER=$2
                    shift 2
                    continue
                else
                    printf 'ERROR: "--user" requires a non-empty argument.\n' >&2
                    exit 1
                fi
                ;;
            --user=?*)
                eval COUCHDB_USER=${1#*=}
                ;;
            --user=)
                printf 'ERROR: "--user" requires a non-empty argument.\n' >&2
                exit 1
                ;;

            --spidermonkey-version)
                if [ -n "$2" ]; then
                    eval SM_VSN=$2
                    shift 2
                    continue
                else
                    printf 'ERROR: "--spidermonkey-version" requires a non-empty argument.\n' >&2
                    exit 1
                fi
                ;;
            --spidermonkey-version=?*)
                eval SM_VSN=${1#*=}
                ;;
            --spidermonkey-version=)
                printf 'ERROR: "--spidermonkey-version" requires a non-empty argument.\n' >&2
                exit 1
                ;;

            --generate-tls-dev-cert)
                echo "WARNING: To enable TLS distribution, don't forget to customize vm.args file."
                generate_tls_dev_cert
                shift
                continue
                ;;

            --) # End of options
                shift
                break
                ;;
            -?*)
                echo "WARNING: Unknown option '$1', ignoring" >&2
                shift
                ;;
            *) # Done
                break
        esac
        shift
    done
}

parse_opts $@

if [ "${ARCH}" = "aarch64" ] && [ "${SM_VSN}" = "60" ]; then
  echo "ERROR: SpiderMonkey 60 is known broken on ARM 64 (aarch64). Use another version instead."
  exit 1
fi

if [ "${ERLANG_OS}" = "unix" ]; then
    case "${SM_VSN}" in
        1.8.5)
            SM_HEADERS="js"
            ;;
        *)  SM_HEADERS="mozjs-${SM_VSN}"
            ;;
        esac

    # This list is taken from src/couch/rebar.config.script, please keep them in sync.
    if [ ! -d "/usr/include/${SM_HEADERS}" ] && \
        [ ! -d "/usr/local/include/${SM_HEADERS}" ] && \
        [ ! -d "/opt/homebrew/include/${SM_HEADERS}" ]; then
        echo "ERROR: SpiderMonkey ${SM_VSN} is not found. Please specify with --spidermonkey-version."
        exit 1
    fi
fi

# If we're in a release tarball and we don't have proper, then mark it as skipped
if [ ! -d .git ] && [ "$WITH_PROPER" = "true" ] && [ ! -d src/proper ]; then
    WITH_PROPER="false"
fi

echo "==> configuring couchdb in rel/couchdb.config"
cat > rel/couchdb.config << EOF
% Licensed under the Apache License, Version 2.0 (the "License"); you may not
% use this file except in compliance with the License. You may obtain a copy of
% the License at
%
%   http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
% License for the specific language governing permissions and limitations under
% the License.
%
% The contents of this file are auto-generated by configure
%
{package_author_name, "$PACKAGE_AUTHOR_NAME"}.
{prefix, "."}.
{data_dir, "./data"}.
{view_index_dir, "./data"}.
{state_dir, "./data"}.
{log_file, "$LOG_FILE"}.
{fauxton_root, "./share/www"}.
{user, "$COUCHDB_USER"}.
{spidermonkey_version, "$SM_VSN"}.
{node_name, "-name couchdb@127.0.0.1"}.
{cluster_port, 5984}.
{backend_port, 5986}.
{prometheus_port, 17986}.
EOF

cat > install.mk << EOF
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
#
# The contents of this file are auto-generated by configure
#
package_author_name = $PACKAGE_AUTHOR_NAME

with_fauxton = $WITH_FAUXTON
with_docs = $WITH_DOCS

user = $COUCHDB_USER
spidermonkey_version = $SM_VSN
EOF

cat > $rootdir/config.erl << EOF
{with_proper, $WITH_PROPER}.
{erlang_md5, $ERLANG_MD5}.
{spidermonkey_version, "$SM_VSN"}.
EOF

install_local_rebar() {
    if [ ! -x "${rootdir}/bin/rebar" ]; then
        if [ ! -d "${rootdir}/src/rebar" ]; then
            git clone --depth 1 https://github.com/apache/couchdb-rebar.git ${rootdir}/src/rebar
        fi
        make -C ${rootdir}/src/rebar
        mv ${rootdir}/src/rebar/rebar ${rootdir}/bin/rebar
        make -C ${rootdir}/src/rebar clean
    fi
}

install_local_rebar3() {
    if [ ! -x "${rootdir}/bin/rebar3" ]; then
        if [ ! -d "${rootdir}/src/rebar3" ]; then
            git clone --depth 1 --branch ${REBAR3_BRANCH} https://github.com/erlang/rebar3.git ${rootdir}/src/rebar3
        fi
        cd src/rebar3
        ./bootstrap
        mv ${rootdir}/src/rebar3/rebar3 ${rootdir}/bin/rebar3
        cd ../..
    fi
}

install_local_erlfmt() {
    if [ ! -x "${rootdir}/bin/erlfmt" ]; then
        if [ ! -d "${rootdir}/src/erlfmt" ]; then
            git clone --depth 1 https://github.com/WhatsApp/erlfmt.git ${rootdir}/src/erlfmt
        fi
        cd "${rootdir}"/src/erlfmt
        ${REBAR3} as release escriptize
        mv ${rootdir}/src/erlfmt/_build/release/bin/erlfmt ${rootdir}/bin/erlfmt
        ${REBAR3} clean
        cd ../..
    fi
}

if [ -z "${REBAR}" ]; then
    install_local_rebar
    REBAR=${rootdir}/bin/rebar
fi

if [ -z "${REBAR3}" ]; then
    install_local_rebar3
    REBAR3=${rootdir}/bin/rebar3
fi

if [ -z "${ERLFMT}" ]; then
    install_local_erlfmt
    ERLFMT=${rootdir}/bin/erlfmt
fi

# only update dependencies, when we are not in a release tarball
if [ -d .git  -a $SKIP_DEPS -ne 1 ]; then
    echo "==> updating dependencies"
    ${REBAR} get-deps update-deps
fi

# External repos frequently become integrated with the primary repo,
# resulting in obsolete .git directories, and possible confusion.
# It is usually a good idea to delete these .git directories.
for path in $(find src -name .git -type d); do
    git ls-files --error-unmatch $(dirname $path) > /dev/null 2>&1 && \
        echo "WARNING unexpected .git directory $path"
done

echo "You have configured Apache CouchDB, time to relax. Relax."
