#!/bin/bash

if [ x"$WARPDRIVE_DEBUG" != x"" ]; then
    set -x
fi

# This script will run the Python web server.

# Setup the environment if not already done.

if [ x"$WARPDRIVE_ACTION" = x"" ]; then
    eval "$(warpdrive env)"
fi

WARPDRIVE_ACTION=start
export WARPDRIVE_ACTION

# Make sure we are in the top level directory of the source code for
# when performing the deploy steps. When later starting the application
# we will use the home directory for the application, but not here.

cd $WARPDRIVE_SRC_ROOT

# Run any user supplied script to be run to update configuration files
# based on environment variables available at deployment time.

if [ ! -f $WARPDRIVE_APP_ROOT/markers/deploy-cfg ]; then
    # Create the marker file so we know if we have been run already.

    mkdir -p $WARPDRIVE_APP_ROOT/markers
    date > $WARPDRIVE_APP_ROOT/markers/deploy-cfg

    if [ -f $WARPDRIVE_SRC_ROOT/.warpdrive/action_hooks/deploy-cfg ]; then
        if [ ! -x $WARPDRIVE_SRC_ROOT/.warpdrive/action_hooks/deploy-cfg ]; then
            echo "# WARNING: Script $WARPDRIVE_SRC_ROOT/.warpdrive/action_hooks/deploy-cfg not executable."
        fi
    fi

    if [ -x $WARPDRIVE_SRC_ROOT/.warpdrive/action_hooks/deploy-cfg ]; then
        echo "# INFO: Running script $WARPDRIVE_SRC_ROOT/.warpdrive/action_hooks/deploy-cfg"
        $WARPDRIVE_SRC_ROOT/.warpdrive/action_hooks/deploy-cfg
    fi
fi

# Run any user supplied script to be run prior to starting the
# application in the actual container. The script must be executable in
# order to be run. It is not possible for this script to change the
# permissions so it is executable and then run it, due to some docker
# bug which results in the text file being busy. For more details see:
#
#   https://github.com/docker/docker/issues/9547

if [ -f $WARPDRIVE_SRC_ROOT/.warpdrive/action_hooks/deploy ]; then
    if [ ! -x $WARPDRIVE_SRC_ROOT/.warpdrive/action_hooks/deploy ]; then
        echo "WARNING: Script $WARPDRIVE_SRC_ROOT/.warpdrive/action_hooks/deploy not executable."
    fi
fi

if [ -x $WARPDRIVE_SRC_ROOT/.warpdrive/action_hooks/deploy ]; then
    echo " -----> Running $WARPDRIVE_SRC_ROOT/.warpdrive/action_hooks/deploy"
    $WARPDRIVE_SRC_ROOT/.warpdrive/action_hooks/deploy
fi

# Now change directory to the application home directory. All checks are
# from this point done relative to this directory.

cd $WARPDRIVE_APP_HOME

# Determine the type of deployment, falling back to 'auto' if none is
# defined. If 'auto', we will try and automatically determine how the
# web application should be started or which WSGI server to use.

if [ -f ${WARPDRIVE_SRC_ROOT}/.warpdrive/deploy_mode ]; then
    WARPDRIVE_DEPLOY_MODE="`cat ${WARPDRIVE_SRC_ROOT}/.warpdrive/deploy_mode`"
else
    WARPDRIVE_DEPLOY_MODE=${WARPDRIVE_DEPLOY_MODE:-auto}
fi

# Determine which WSGI server should be used if hosting a WSGI application
# directly, or if hosting a Django based web application.

if [ -f ${WARPDRIVE_SRC_ROOT}/.warpdrive/server_type ]; then
    WARPDRIVE_SERVER_TYPE="`cat ${WARPDRIVE_SRC_ROOT}/.warpdrive/server_type`"
else
    WARPDRIVE_SERVER_TYPE=${WARPDRIVE_SERVER_TYPE:-mod_wsgi}
fi

echo " -----> Configuring for deployment mode: of '$WARPDRIVE_DEPLOY_MODE'"
echo " -----> Default WSGI server type is '$WARPDRIVE_SERVER_TYPE'"

# Setup default names of files to check for different server types.

WARPDRIVE_SHELL_FILE="${WARPDRIVE_SHELL_FILE:-app.sh}"
WARPDRIVE_PYTHON_FILE="${WARPDRIVE_PYTHON_FILE:-app.py}"

WARPDRIVE_WSGI_MODULE_NAME="${WARPDRIVE_WSGI_MODULE_NAME:-wsgi}"
WARPDRIVE_WSGI_CALLABLE_OBJECT=${WARPDRIVE_WSGI_CALLABLE_OBJECT:-application}
WARPDRIVE_WSGI_STATIC_URL=${WARPDRIVE_WSGI_STATIC_URL:-}
WARPDRIVE_WSGI_STATIC_ROOT=${WARPDRIVE_WSGI_STATIC_ROOT:-}

# Ensure that path to a shell script file uses absolute path else we
# will not be able to execute it later as isn't going to be in PATH.

case "$WARPDRIVE_SHELL_FILE" in
    /*)
        ;;
    *)
        WARPDRIVE_SHELL_FILE="$WARPDRIVE_SRC_ROOT/$WARPDRIVE_SHELL_FILE"
        ;;
esac

# Utility functions for deducing server args for various cases.

function wsgi_module_path() {
    WARPDRIVE_WSGI_MODULE_FILE="`echo $WARPDRIVE_WSGI_MODULE_NAME | \
        sed -e 's%\.%/%g'`.py"
    WARPDRIVE_WSGI_PACKAGE_FILE="`echo $WARPDRIVE_WSGI_MODULE_NAME | \
        sed -e 's%\.%/%g'`/__init__.py"

    WARPDRIVE_WSGI_FILE=""

    if [ -f $WARPDRIVE_WSGI_MODULE_FILE ]; then
        WARPDRIVE_WSGI_FILE=$WARPDRIVE_WSGI_MODULE_FILE
    fi
    
    if [ -f $WARPDRIVE_WSGI_PACKAGE_FILE ]; then
        WARPDRIVE_WSGI_FILE=$WARPDRIVE_WSGI_PACKAGE_FILE
    fi

    echo $WARPDRIVE_WSGI_FILE
}

function django_start_settings() {
    WARPDRIVE_TMP_SCRIPT="/tmp/django_start_settings_$$.py"
    WARPDRIVE_TMP_VALUES="/tmp/django_start_settings_$$.txt"

    cat > $WARPDRIVE_TMP_SCRIPT << !
from django.conf import settings
with open('$WARPDRIVE_TMP_VALUES', 'w') as fp:
    settings_module = getattr(settings, 'SETTINGS_MODULE')

    wsgi_application = getattr(settings, 'WSGI_APPLICATION')

    entry_point = '.'.join(wsgi_application.split('.')[:-1])
    callable_object = wsgi_application.split('.')[-1]

    static_url = getattr(settings, 'STATIC_URL')

    if not static_url:
        static_url = '/static/'

    static_root = getattr(settings, 'STATIC_ROOT')

    if not static_root:
        static_root = '$WARPDRIVE_APP_ROOT/tmp/django/static'

    variables = [
        'DJANGO_SETTINGS_MODULE="%s"' % settings_module,
        'WARPDRIVE_WSGI_MODULE_NAME=%s' % entry_point,
        'WARPDRIVE_WSGI_CALLABLE_OBJECT=%s' % callable_object]

    if static_url.endswith('/') and not static_root.endswith('/'):
        static_root = static_root + '/'

    variables.append('WARPDRIVE_WSGI_STATIC_URL=%s' % static_url)
    variables.append('WARPDRIVE_WSGI_STATIC_ROOT=%s' % static_root)

    fp.write('\n'.join(variables))
!

    (cat - | python manage.py shell --plain > /dev/null) << !
import runpy
_ = runpy.run_path('$WARPDRIVE_TMP_SCRIPT')
!

    cat $WARPDRIVE_TMP_VALUES

    rm $WARPDRIVE_TMP_VALUES
    rm $WARPDRIVE_TMP_SCRIPT*
}

function server_args() {
    WARPDRIVE_SERVER_ARGS="$WARPDRIVE_SERVER_ARGS $*"
}

function create_whitenoise_wrapper() {
    mkdir -p $WARPDRIVE_APP_ROOT/tmp/modules
    cat > $WARPDRIVE_APP_ROOT/tmp/modules/whitenoise_wrapper.py << !
from whitenoise import WhiteNoise

from $WARPDRIVE_WSGI_MODULE_NAME import $WARPDRIVE_WSGI_CALLABLE_OBJECT as _application

application = WhiteNoise(_application)
application.add_files('$WARPDRIVE_WSGI_STATIC_ROOT', prefix='$WARPDRIVE_WSGI_STATIC_URL')
!
}

# Now check whether server type of 'shell' is selected.

if [ "$WARPDRIVE_DEPLOY_MODE" = "shell" ]; then
    server_args $WARPDRIVE_SHELL_FILE
fi

# Now check whether server of 'python' is selected.

if [ "$WARPDRIVE_DEPLOY_MODE" = "python" ]; then
    server_args $WARPDRIVE_PYTHON_FILE
fi

# Now check whether server of 'wsgi' is selected.

if [ "$WARPDRIVE_DEPLOY_MODE" = "wsgi" ]; then
    if [ "$(wsgi_module_path)" != "" ]; then
        # WARPDRIVE_DEPLOY_MODE="wsgi"
        true
    fi
fi

# Now check whether server of 'django' is selected.

if [ "$WARPDRIVE_DEPLOY_MODE" = "django" -a -f manage.py ]; then
    if grep -q DJANGO_SETTINGS_MODULE manage.py; then
        WARPDRIVE_DEPLOY_MODE="wsgi"
        eval "$(django_start_settings)"
        export DJANGO_SETTINGS_MODULE
    fi
fi

# If instead we are in automatic mode, we are going to try a number of
# different strategies. First up we are going to check whether there
# exists an executable 'app.sh' program in the top level directory of
# the application. If there is, we switch to 'shell' server type.

if [ "$WARPDRIVE_DEPLOY_MODE" = "auto" -a -x $WARPDRIVE_SHELL_FILE ]; then
    WARPDRIVE_DEPLOY_MODE="shell"
    WARPDRIVE_SERVER_ARGS="$WARPDRIVE_SHELL_FILE"
fi

# Now check whether there exists an 'app.py' script file in the top
# level directory. If there is, we switch to 'python' server type.

if [ "$WARPDRIVE_DEPLOY_MODE" = "auto" -a -f $WARPDRIVE_PYTHON_FILE ]; then
    WARPDRIVE_DEPLOY_MODE="python"
    WARPDRIVE_SERVER_ARGS="$WARPDRIVE_PYTHON_FILE"
fi

# Now check whether there exists a 'manage.py' file in the top level
# directory. This can indicate we are running Django. Validate that it
# is probably Django and then use 'manage.py' to determine the WSGI
# application entry point, static files location and mount point.

if [ "$WARPDRIVE_DEPLOY_MODE" = "auto" -a -f manage.py ]; then
    if grep -q DJANGO_SETTINGS_MODULE manage.py; then
        WARPDRIVE_DEPLOY_MODE="wsgi"
        eval $(django_start_settings)
        export DJANGO_SETTINGS_MODULE
    fi
fi

# Now check whether there exists a 'wsgi.py' file in the top level
# directory.

if [ "$WARPDRIVE_DEPLOY_MODE" = "auto" ]; then
    if [ "$(wsgi_module_path)" != "" ]; then
        WARPDRIVE_DEPLOY_MODE="wsgi"
    fi
fi

# Setup server args when WSGI server is to be used.

if [ "$WARPDRIVE_DEPLOY_MODE" = "wsgi" ]; then
    if [ "$WARPDRIVE_SERVER_TYPE" = "gunicorn" ]; then
        WARPDRIVE_WSGI_APPLICATION="$WARPDRIVE_WSGI_MODULE_NAME:$WARPDRIVE_WSGI_CALLABLE_OBJECT"

        if [ "$WARPDRIVE_WSGI_STATIC_URL" != "" ]; then
            if [ "$WARPDRIVE_WSGI_STATIC_ROOT" != "" ]; then
                create_whitenoise_wrapper
                WARPDRIVE_WSGI_APPLICATION="whitenoise_wrapper:application"
                PYTHONPATH="$PYTHONPATH:$WARPDRIVE_APP_ROOT/tmp/modules"
                export PYTHONPATH
            fi
        fi

        server_args $WARPDRIVE_WSGI_APPLICATION
    fi

    if [ "$WARPDRIVE_SERVER_TYPE" = "mod_wsgi" ]; then
        server_args --application-type module
        server_args --entry-point $WARPDRIVE_WSGI_MODULE_NAME
        server_args --callable-object $WARPDRIVE_WSGI_CALLABLE_OBJECT

        if [ "$WARPDRIVE_WSGI_STATIC_URL" != "" ]; then
            if [ "$WARPDRIVE_WSGI_STATIC_ROOT" != "" ]; then
                server_args --url-alias $WARPDRIVE_WSGI_STATIC_URL $WARPDRIVE_WSGI_STATIC_ROOT
            fi
        fi
    fi

    if [ "$WARPDRIVE_SERVER_TYPE" = "uwsgi" ]; then
        server_args --module $WARPDRIVE_WSGI_MODULE_NAME
        server_args --callable $WARPDRIVE_WSGI_CALLABLE_OBJECT

        if [ "$WARPDRIVE_WSGI_STATIC_URL" != "" ]; then
            if [ "$WARPDRIVE_WSGI_STATIC_ROOT" != "" ]; then
                server_args --static-map $WARPDRIVE_WSGI_STATIC_URL=$WARPDRIVE_WSGI_STATIC_ROOT
            fi
        fi
    fi

    if [ "$WARPDRIVE_SERVER_TYPE" = "waitress" ]; then
        WARPDRIVE_WSGI_APPLICATION="$WARPDRIVE_WSGI_MODULE_NAME:$WARPDRIVE_WSGI_CALLABLE_OBJECT"

        if [ "$WARPDRIVE_WSGI_STATIC_URL" != "" ]; then
            if [ "$WARPDRIVE_WSGI_STATIC_ROOT" != "" ]; then
                create_whitenoise_wrapper
                WARPDRIVE_WSGI_APPLICATION="whitenoise_wrapper:application"
                PYTHONPATH="$PYTHONPATH:$WARPDRIVE_APP_ROOT/tmp/modules"
                export PYTHONPATH
            fi
        fi

        server_args $WARPDRIVE_WSGI_APPLICATION
    fi

    WARPDRIVE_DEPLOY_MODE="$WARPDRIVE_SERVER_TYPE"
fi

# If was doing auto detection and couldn't match any possible way to
# host the Python web application, switch to 'mod_wsgi' server type and
# show the default splash page.

if [ "$WARPDRIVE_DEPLOY_MODE" = "auto" ]; then
    WARPDRIVE_DEPLOY_MODE="mod_wsgi"
    WARPDRIVE_SERVER_ARGS=""
fi

# Finally, execute the startup script for the final server type.

WARPDRIVE_START=`which $0`
WARPDRIVE_SCRIPTS=`dirname $WARPDRIVE_START`

echo " -----> Running server script start-$WARPDRIVE_DEPLOY_MODE"

exec $WARPDRIVE_SCRIPTS/start-$WARPDRIVE_DEPLOY_MODE $WARPDRIVE_SERVER_ARGS
