#!/bin/bash

# tahoe-i2p-install - Install self-contained I2P mod of Tahoe-LAFS
#
# Author:  smeghead <smeghead@mail.i2p> <smeghead@i2pmail.org>
# License: public domain
#
# Requirements:
#
# - *BSD/Linux/Mac OS X/Solaris:
#     Bash or Zsh, GCC, Python 2.5 or 2.6 (not 3.x), Wget
#
# - Windows:
#     Unsupported, but same as above plus MinGW or Cygwin and probably lots of
#     spit, glue, duct tape and virgin sacrifices. If you make it work please
#     contribute your changes to this script's maintainer (by doing so you
#     agree to release the work into the public domain) and if they're sane
#     enough they'll be included in the next release.
#
# If the --fetch-patches-i2p option is used then I2P must be installed and
# running locally with its HTTP Proxy enabled, and the base directory of your
# I2P installation must be in the PATH environment variable.


# Release-specific metadata

INSTALLER_VERSION="1.0"

FOOLSCAP_VERSION="0.5.0"
FOOLSCAP_PATCH_REVISION="r0"
FOOLSCAP_PATCH_SHA256="c5427043495cc115ac5663082e74ca293ce12c0479f1c1f1ac1113fa5df30afd"
FOOLSCAP_SHA256="27521127a80e13ec97f58b1531b4740029ba3a4b5f0fea3c4af428d2b6e7db5c"

TAHOE_DEPS_VERSION="10"
TAHOE_DEPS_SHA256="dc3eb7a7786b53e6740a30521b8e96eedff7a59e2f004e997714bd6a3145f731"

TAHOE_LAFS_VERSION="1.6.1"
TAHOE_LAFS_PATCH_REVISION="r0"
TAHOE_LAFS_PATCH_SHA256="7796fcad13a0db7cc20edeeb0141bc4af1c64c40e9aa2c94c6ff8bcc4229a988"
TAHOE_LAFS_SHA256="ea184eb8e60fb7adcac5fd7547267a296f5bbc520e3d204f28f79d61bc42e008"

# Fetch locations

PATCH_HOME_I2P="http://duck.i2p/tahoe-lafs/patches"
PATCH_HOME_WWW="http://duck.i2p.to/tahoe-lafs/patches"

FOOLSCAP_PKG="foolscap-${FOOLSCAP_VERSION}"
FOOLSCAP_PKG_EXTENSION=".tar.gz"
FOOLSCAP_PATCH="foolscap-i2p-${FOOLSCAP_VERSION}-${FOOLSCAP_PATCH_REVISION}.patch"
FOOLSCAP_HOME="http://foolscap.lothar.com/releases"

TAHOE_DEPS_PKG="tahoe-deps-v${TAHOE_DEPS_VERSION}"
TAHOE_DEPS_PKG_EXTENSION=".tar.gz"
TAHOE_DEPS_HOME="http://tahoe-lafs.org/source/tahoe-lafs/deps"

TAHOE_LAFS_PKG="allmydata-tahoe-${TAHOE_LAFS_VERSION}"
TAHOE_LAFS_PKG_EXTENSION=".tar.gz"
TAHOE_LAFS_PATCH="tahoe-lafs-i2p-${TAHOE_LAFS_VERSION}-${TAHOE_LAFS_PATCH_REVISION}.patch"
TAHOE_LAFS_HOME="http://tahoe-lafs.org/source/tahoe-lafs/releases"

# Don't mess with these or you might end up with a deleted WORKING_DIR

WORKING_DIR="$(pwd)"
INSTALL_DIR="${WORKING_DIR}/tahoe-lafs-i2p"
FOOLSCAP_DIR="${WORKING_DIR}/${FOOLSCAP_PKG:-foolscap-src}"
TAHOE_DEPS_DIR="${WORKING_DIR}/tahoe-deps"
TAHOE_LAFS_DIR="${WORKING_DIR}/${TAHOE_LAFS_PKG:-tahoe-lafs-src}"

PYTHON_VERSION=$(python --version 2>&1 | cut -d ' ' -f2 | cut -c 1-3)

apply_patches() {
    echo
    echo ">>> Patching sources"
    echo

    set "${FOOLSCAP_DIR}" "${FOOLSCAP_PATCH}" \
        "${TAHOE_LAFS_DIR}" "${TAHOE_LAFS_PATCH}"

    while [[ -n "$@" ]] ; do

        pushd "${1}" &> /dev/null

        patch -p0 < "${WORKING_DIR}/${2}"

        if [[ $? -gt 0 ]] ; then
            echo
            echo "Error: Failed to apply patch. Aborting." >&2
            echo
            exit 1
        fi

        popd &> /dev/null

        shift 2
    done
}

build_foolscap() {
    pushd "${FOOLSCAP_DIR}" &> /dev/null

    echo
    echo ">>> Building foolscap"
    echo

    python setup.py build || exit 1
    python setup.py sdist || exit 1
    cp -f dist/* "${TAHOE_DEPS_DIR}"

    popd &> /dev/null
}

build_tahoe_lafs() {
    pushd "${TAHOE_LAFS_DIR}" &> /dev/null

    echo
    echo ">>> Building tahoe-lafs"
    echo

    mkdir -p "${TAHOE_LAFS_DIR}/support/lib/python${PYTHON_VERSION}/site-packages"
    export PYTHONPATH="${TAHOE_LAFS_DIR}/support/lib/python${PYTHON_VERSION}/site-packages"

    if [[ -n ${opt_make_dist} ]] ; then
        python setup.py build || exit 1
        python setup.py bdist || exit 1
        cp -f dist/* "${WORKING_DIR}"
    else
        python setup.py build || exit 1
    fi

    popd &> /dev/null
}

clean_build_dirs() {
    pushd "${WORKING_DIR}" &> /dev/null

    echo
    echo ">>> Cleaning previously created build directories"
    echo

    rm -rf "${FOOLSCAP_DIR}" "${TAHOE_DEPS_DIR}" "${TAHOE_LAFS_DIR}"

    popd &> /dev/null
}

fetch_packages() {
    pushd "${WORKING_DIR}" &> /dev/null

    echo
    echo ">>> Fetching patches and packages"
    echo

    for p in "${FOOLSCAP_PATCH}" "${TAHOE_LAFS_PATCH}" ; do

        if [[ -f ${p} ]] ; then
            echo
            echo "${p} exists, skipping."
            echo
            continue
        fi

        if [[ -n ${opt_fetch_patches_i2p} ]] ; then
            eepget ${opt_http_proxy:+-p $opt_http_proxy} \
                -o "${p}" \
                "${PATCH_HOME_I2P}/${p}"
            rm -rf "${WORKING_DIR}/logs"
        else
            wget -O "${p}" "${PATCH_HOME_WWW}/${p}"
        fi

        if [[ $? -gt 0 ]] ; then
            echo
            echo "Error: Failed to download patch. Try fetching it manually and run" >&2
            echo "tahoe-i2p-install again. Aborting." >&2
            echo
            exit 1
        fi

    done

    set "${FOOLSCAP_HOME}" "${FOOLSCAP_PKG}" "${FOOLSCAP_PKG_EXTENSION}" \
        "${TAHOE_DEPS_HOME}" "${TAHOE_DEPS_PKG}" "${TAHOE_DEPS_PKG_EXTENSION}" \
        "${TAHOE_LAFS_HOME}" "${TAHOE_LAFS_PKG}" "${TAHOE_LAFS_PKG_EXTENSION}"

    while [[ -n "$@" ]] ; do

        if [[ -f ${2}${3} ]] ; then
            echo
            echo "${2}${3} exists, skipping."
            echo
            shift 3
            continue
        fi

        wget "${1}/${2}${3}"

        if [[ $? -gt 0 ]] ; then
            echo
            echo "Error: Failed to download package. Try fetching it manually and run" >&2
            echo "tahoe-i2p-install again. Aborting." >&2
            echo
            exit 1
        fi

        shift 3
    done

    popd &> /dev/null
}

unpack_all() {
    local tar_filter_opt

    pushd "${WORKING_DIR}" &> /dev/null

    echo
    echo ">>> Unpacking archives"
    echo

    for pkg in \
        "${FOOLSCAP_PKG}${FOOLSCAP_PKG_EXTENSION}" \
        "${TAHOE_DEPS_PKG}${TAHOE_DEPS_PKG_EXTENSION}" \
        "${TAHOE_LAFS_PKG}${TAHOE_LAFS_PKG_EXTENSION}"
    do
        case "${pkg}" in
            *.7z)
                7z e "${pkg}"
                continue ;;

            *.tar.bz2|*.tbz)
                tar_filter_opt=-j ;;

            *.tar.gz|*.tgz)
                tar_filter_opt=-z ;;

            *.tar.lzma)
                tar_filter_opt=--lzma ;;

            *.tar.xz|*.txz)
                tar_filter_opt=-J ;;

            *.zip)
                unzip -v "${pkg}"
                continue ;;

            *)
                echo "Error: Package has unknown extension: ${pkg}" >&2
                echo "Aborting." >&2
                exit 1 ;;
        esac

        tar -x ${filter_opt} -vf "${pkg}"
    done

    # This foolscap is replaced with our I2P-patched version
    rm -f "${TAHOE_DEPS_DIR}"/foolscap*

    popd &> /dev/null
}

usage() {
    echo "Usage: tahoe-i2p-install [OPTIONS]"
    cat << EOF

Build and install tahoe-lafs-i2p in the current directory.

Options:
  -d, --make-dist            create distributable package
  -h, --help                 show usage information and exit
  -i, --fetch-patches-i2p    fetch patches (but not packages) via I2P HTTP Poxy
  -n, --no-fetch             don't attempt to fetch anything
  -p, --preserve-build-dirs  don't remove build dirs when done
  -v, --version              show version information and exit
  -x, --http-proxy IP:PORT   use nonstandard address:port for I2P HTTP Poxy
EOF
    exit 0
}

verify_hashes() {
    local sha256

    pushd "${WORKING_DIR}" &> /dev/null

    echo
    echo ">>> Verifying SHA-256 sums"
    echo

    set "${FOOLSCAP_PATCH}" "${FOOLSCAP_PATCH_SHA256}" \
        "${TAHOE_LAFS_PATCH}" "${TAHOE_LAFS_PATCH_SHA256}" \
        "${FOOLSCAP_PKG}${FOOLSCAP_PKG_EXTENSION}" "${FOOLSCAP_SHA256}" \
        "${TAHOE_DEPS_PKG}${TAHOE_DEPS_PKG_EXTENSION}" "${TAHOE_DEPS_SHA256}" \
        "${TAHOE_LAFS_PKG}${TAHOE_LAFS_PKG_EXTENSION}" "${TAHOE_LAFS_SHA256}"

    while [[ -n "$@" ]] ; do
        echo -n "${1} ... "

        sha256=$(sha256sum "${1}" | cut -d ' ' -f1)

        if [[ ${sha256} == ${2} ]] ; then
            echo "OK"
        else
            echo "FAILED"
            echo
            echo "Expected hash: ${2}"
            echo "Computed hash: ${sha256}"
            echo
            echo "Error: A package or patch failed its hash check. Aborting." >&2
            echo
            exit 1
        fi

        shift 2
    done

    echo
    popd &> /dev/null
}

while [[ $# > 0 ]] ; do
    case "${1}" in

        -d|--make-dist)
            opt_make_dist=1
            shift ;;

        -h|--help)
            usage ;;

        -i|--fetch-patches-i2p)
            opt_fetch_patches_i2p=1
            shift ;;

        -n|--no-fetch)
            opt_no_fetch=1
            shift ;;

        -p|--preserve-build-dirs)
            opt_preserve_build_dirs=1
            shift ;;

        -v|--version)
            echo "tahoe-i2p-install version ${INSTALLER_VERSION}"
            echo
            echo "This version provides:"
            echo
            echo "  ${TAHOE_LAFS_PKG}"
            echo "  ${TAHOE_DEPS_PKG}"
            echo "  ${FOOLSCAP_PKG}"
            echo
            echo "Patched with:"
            echo
            echo "  ${TAHOE_LAFS_PATCH}"
            echo "  ${FOOLSCAP_PATCH}"
            echo
            exit 0 ;;

        -x|--http-proxy)
            shift
            opt_http_proxy=${1}
            shift ;;

        -*)
            echo "Unknown option: ${1}" >&2
            exit 1 ;;

        *)
            echo "Too many arguments: ${1}" >&2
            exit 1 ;;
    esac
done

# Always start with clean build dirs
clean_build_dirs

[[ -z ${opt_no_fetch} ]] && fetch_packages

verify_hashes
unpack_all
apply_patches
build_foolscap
build_tahoe_lafs

[[ -d ${INSTALL_DIR} ]] && rm -rf "${INSTALL_DIR}"

if [[ -z ${opt_preserve_build_dirs} ]] ; then
    mv -f "${TAHOE_LAFS_DIR}" "${INSTALL_DIR}"
    clean_build_dirs
else
    cp -a "${TAHOE_LAFS_DIR}" "${INSTALL_DIR}"
fi

sed -i -e "s|${TAHOE_LAFS_DIR}/src|${INSTALL_DIR}/src|" \
    "${INSTALL_DIR}/support/lib/python${PYTHON_VERSION}/site-packages/allmydata-tahoe.egg-link" \
    "${INSTALL_DIR}/support/lib/python${PYTHON_VERSION}/site-packages/easy-install.pth"

echo
echo ">>> Finished tahoe-i2p-install"
echo
echo "Be sure to update your environment:"
echo
echo "  export PATH=\"${INSTALL_DIR}/bin:\${PATH}\""
echo "  export PYTHONPATH=\"${INSTALL_DIR}/support/lib/python${PYTHON_VERSION}/site-packages:\${PYTHONPATH}\""
echo

