#!/bin/bash

# pythonhax - a shim to do magical things
#   * find the python path automatically
#       - for those hairy distros with no /usr/bin/python
#       - for those extra-hairy distros with no /usr/bin/python(2|3) either
#   * strace the python execution
#       - when you need to figure out what the module is doing at the system level
#   * explode & python -m trace --trace the module
#       - when you need to figure out how the module is working
#
# INSTALL
#   1. copy this script to /usr/bin/pythonhax on the remote host
#   2. chmod +x /usr/bin/pythonhax on the remote host
#   3. set ansible_python_interpreter=/usr/bin/pythonhax in inventory
#   4. set PTRACE or STRACE to 1 so that either will trigger
#
# NOTES
#   * it can be placed in ~/bin/pythonhax on the remote but
#     this may cause issues with sudo+su access
#   * python or python2 will be preferred for now
#   * strace has to be installed for the stracing to work
#   * the strace and trace files can be tailed on the remote
#     if the module is long-running


PYTHON_BASENAMES="python:python2:python3:platform-python"
LOGFILE=/tmp/pyhax.log
PTRACE=1
PTRACE_DIR=/tmp/ptrace.out
STRACE=0
STRACE_DIR=/tmp/strace.out



######################################
#   AUTO-INTERPRETER
######################################

function FIND_PYTHON () {
    FOUND_PYTHON=$(which python 2>/dev/null)
    CHECKPATH=$PATH:/usr/libexec

    if [ -z "$FOUND_PYTHON" ]; then
        IFS=:
        for BN in $PYTHON_BASENAMES; do
            for CPATH in $CHECKPATH; do
                echo "$(date) check $CPATH/$BN" >> $LOGFILE
                test -x $CPATH/$BN
                RC=$?
                if [[ $RC == 0 ]]; then
                    FOUND_PYTHON=$CPATH/$BN
                    echo "$(date) found $CPATH/$BN" >> $LOGFILE
                    break
                fi
            done
            if [ ! -z "$FOUND_PYTHON" ];  then
                break
            fi
        done
    fi
    echo $FOUND_PYTHON
}

PYTHON=$(FIND_PYTHON)
echo "$(date) using $PYTHON" >> $LOGFILE
if [ -z "$PYTHON" ]; then
    echo "no python found in path"
    exit 1
fi


######################################
#   FIX ZIPFILE INTERPRETER
######################################

ARGN="${@: -1}"
if [ ${ARGN: -3} == ".py" ]; then
    ZIPFILE="${@: -1}"
    ZIPDIR="$(dirname $ZIPFILE)"

    # The zipfile injects the pythonhax interpreter we need to fix
    echo "$(date) sed -i.bak \"s|/usr/bin/pythonhax|$PYTHON|g\" $ZIPFILE" >> $LOGFILE
    sed -i.bak "s|/usr/bin/pythonhax|$PYTHON|g" $ZIPFILE
fi


######################################
#   EXECUTE
######################################

if [[ "$STRACE" == "1" ]]; then

    #
    # strace the whole thing
    #

    echo "$(date) STRACE:$STRACE" >> $LOGFILE
    THIS_STRACE_DIR=$STRACE_DIR/$$
    mkdir -p $THIS_STRACE_DIR
    echo "$(date) $$ $THIS_STRACE_DIR" >> $LOGFILE
    echo "$(date) $PYTHON $@" >> $LOGFILE
    strace -ffttv -s 100000 -o $THIS_STRACE_DIR/pid $PYTHON $@

elif [[ "$PTRACE" == "1" ]] && [ ${ARGN: -3} == ".py" ]; then

    #
    # python -m trace --trace
    #

    ZIPFILE="${@: -1}"
    ZIPDIR="$(dirname $ZIPFILE)"

    # Explode it so that we're not stuck in subprocess hell
    echo "$(date) $PYTHON $ZIPFILE explode" >> $LOGFILE
    $PYTHON $ZIPFILE explode 2>&1 >> $LOGFILE

    # Define a temporary holding file for output
    RESFILE=$PTRACE_DIR/$$.out
    RESDIR=$(dirname $RESFILE)
    if [ ! -d $RESDIR ]; then
        mkdir -p $RESDIR
    fi

    # Pass in the args file as the first argument and then execute to invoke
    echo "$(date) $PYTHON -m trace --trace $ZIPDIR/debug_dir/*.py $ZIPDIR/debug_dir/args execute > $RESFILE" >> $LOGFILE
    $PYTHON -m trace --trace $ZIPDIR/debug_dir/*.py $ZIPDIR/debug_dir/args execute > $RESFILE

    # Assume the first dict/json style line is the module output
    egrep -m1 ^\{ $RESFILE

else

    #
    # vanilla execution with the located interpreter
    #

    echo "$(date) $PYTHON $@" >> $LOGFILE
    $PYTHON $@
fi
