#!/usr/bin/env bash
#
# Create a new temporary (throw-away) virtual environment, install requirements
# specified, run the SCRIPT, and destroy the environment when the script finishes.
#
# Usage from the command line:
#
#   envie-tmp SCRIPT
#
# Usage in hashbang, inspired by PEP 263:
#
#   #!/usr/bin/env envie-tmp
#   # -*- requirements: auto -*-
#
# If requirements specified as "auto", the closest "requirements.txt" is searched for.
# Alternatively, you can specify a different, or a specific pip requirements, like:
#
#   # -*- requirements: ../base-requirements.txt ./dev-requirements.txt -*-
#
# Paths to requirements files are relative to the SCRIPT's dir.
#
# ``envie-tmp`` is part of the ``envie`` package, ``https://github.com/randomir/envie``.


usage() {
    echo "Create a new temporary (throw-away) virtual environment, install requirements"
    echo "specified, run the SCRIPT, and destroy the environment afterwards."
    echo
    echo "Usage:"
    echo "    envie-tmp SCRIPT"
    echo
    echo "Hashbang examples:"
    echo
    echo " 1) no requirements (mkenv -t)"
    echo
    echo "    #!/usr/bin/env envie-tmp"
    echo
    echo ' 2) installs reqs from the closest "requirements.txt" (mkenv -ta):'
    echo
    echo "    #!/usr/bin/env envie-tmp"
    echo "    # -*- requirements: auto -*-"
    echo
    echo " 3) installs reqs from the specific Pip requirements files (relative to SCRIPT's dir)"
    echo "    (mkenv -t -r REQ ...):"
    echo
    echo "    #!/usr/bin/env envie-tmp"
    echo "    # -*- requirements: ../base-requirements.txt ./dev-requirements.txt -*-"
    echo
    echo " 4) specify the Python version to use, and install some Pip packages"
    echo "    (mkenv -t -e PYTHON -p PKG ...):"
    echo
    echo "    #!/usr/bin/env envie-tmp"
    echo "    # -*- python-version: python3 -*-"
    echo "    # -*- packages: plucky requests>=2.0 flask==0.12 -e/path/to/pkg -e. -*-"
    echo
}


mkenv_based_on_script_reqs() {
    # assert: started in script_dir (reqs are relative to script!)
    local path="$1"
    local pyname=$(sed -nre "s/^[ \t\v]*#.*?python-version[:=][ \t]*(.+) -\*-[ \t\v]*$/\1/p" "$path" | paste -sd' ' -)
    local reqs=$(sed -nre "s/^[ \t\v]*#.*?requirements[:=][ \t]*(.+) -\*-[ \t\v]*$/\1/p" "$path" | paste -sd' ' -)
    local pkgs=$(sed -nre "s/^[ \t\v]*#.*?packages[:=][ \t]*(.+) -\*-[ \t\v]*$/\1/p" "$path" | paste -sd' ' -)
    local req opts=(-t)
    if [ "$pyname" ]; then
        opts+=(-e "$pyname")
    fi
    for req in $reqs; do
        if [ "$req" == "auto" ]; then
            opts+=(-a)
        else
            if [ ! -f "$req" ]; then
                echo "ERROR: requirement file not found: $req"
                exit 3
            fi
            opts+=(-r "$req")
        fi
    done
    for pkg in $pkgs; do
        opts+=(-p "$pkg")
    done
    mkenv "${opts[@]}"
}


if ! command -v envie &>/dev/null; then
    echo "ERROR: Envie not found. Install with: 'sudo pip install envie'."
    exit 1
fi

if [ ! "$1" ] || [ "$1" == "--help" ] || [ "$1" == "-h" ]; then
    usage
    exit 255
fi
script_path="$1"

# source envie (we need _find_closest later on), don't pass-through our args
set --
. envie

if [ ! -r "$script_path" ]; then
    echo "ERROR: script not found or not readable: '$script_path'."
    exit 2
fi
script_dir=$(_readlink "$(dirname "$script_path")")

(
    cd "$script_dir"
    mkenv_based_on_script_reqs "$script_path" && created=1
    (( created )) && python "$script_path"
    (( created )) && rmenv -fv
)
