#!/usr/bin/env bash

print_help() {
    (>&2 cat <<EOF
Autogenerate an .sspt file for a package.
Usage: $0 [-h|-?|--help]
           Print this help text and exit.
     - $0 <package-name>
           Generate the .sspt file for this package.
Supported VCSes: git, hg, svn, cvs, bzr, mtn, darcs
Supported build systems: npm, cargo, setuptools, idris, xbuild, stack,
    cabal, scons, gradle, sbt, bazel, meson, ninja, ant, mvn, cmake,
    qmake, autoconf, makefile
EOF
)
}

autogen_git() {
    cat >> ".sspt" <<EOF
sspt_pull() {
    git pull
}
sspt_version() {
    git rev-parse HEAD
}
sspt_prettyver() {
    git describe --long --tags | sed 's/\([^-]*-g\)/r\1/;s/-/./g'
}
EOF
}
autogen_hg() {
    cat >> ".sspt" <<EOF
sspt_pull() {
    hg pull
}
sspt_version() {
    hg identify -i
}
sspt_prettyver() {
    printf "r%s.%s" "\$(hg identify -n)" "\$(hg identify -i)"
}
EOF
}
autogen_svn() {
    cat >> ".sspt" <<EOF
sspt_pull() {
    svn up
}
sspt_version() {
    svnversion
}
sspt_prettyver() {
    local ver="\$(svnversion)"
    printf "r%s" "\${ver//[[:alpha:]]}"
}
EOF
}
autogen_cvs() {
    # CVS doesn't have 'global' commits...
    cat >> ".sspt" <<EOF
sspt_pull() {
    cvs update
}
sspt_version() {
    date +%Y%m%d
}
sspt_prettyver() {
    date +%Y%m%d
}
EOF
}
autogen_bzr() {
    cat >> ".sspt" <<EOF
sspt_pull() {
    bzr update
}
sspt_version() {
    bzr revno
}
sspt_prettyver() {
    printf "r%s" "\$(bzr revno)"
}
EOF
}
autogen_mtn() {
    cat >> ".sspt" <<EOF
sspt_pull() {
    mtn pull
    mtn update
}
sspt_version() {
    mtn log --last=1 --no-graph | grep "Revision" | egrep -o "[A-Za-z0-9]$"
}
sspt_prettyver() {
    mtn log --last=1 --no-graph | grep "Revision" | egrep -o "[A-Za-z0-9]$"
}
EOF
}
autogen_darcs() {
    cat >> ".sspt" <<EOF
sspt_pull() {
    darcs pull
}
sspt_version() {
    darcs log -n 1 | head -1 | egrep -o "[A-Za-z0-9]$"
}
sspt_prettyver() {
    darcs log -n 1 | head -1 | egrep -o "[A-Za-z0-9]$"
}
EOF
}
autogen_vcs() {
    if [ -d ".git/" ]; then
        autogen_git
    elif [ -d ".hg/" ]; then
        autogen_hg
    elif [ -d ".svn/" ]; then
        autogen_svn
    elif [ -d "CVSROOT/" ]; then
        autogen_cvs
    elif [ -d ".bzr/" ]; then
        autogen_bzr
    elif [ -d "_MTN/" ]; then
        autogen_mtn
    elif [ -d "_darcs/" ]; then
        autogen_darcs
    else
        (>&2 echo "NOTE: could not detect repository type, add the .sspt" \
            "file to make updating this pacakge possible.")
        # no upstream?
        cat >> ".sspt" <<EOF
sspt_pull() {
    true
}
sspt_version() {
    date +%Y%m%d
}
sspt_prettyver() {
    date +%Y%m%d
}
EOF
    fi
}
autogen_buildsys() {
    local REL_DIR="."
    local RELI_DIR="."
    local SSPT_FILE=".sspt"
    local CHANGED_DIR=""
    if [ -z "$DONT_LOOK_INTO_BUILD" ] && [ -d "build" ]; then
        pushd "build" >/dev/null
        CHANGED_DIR=1
        SSPT_FILE="../$SSPT_FILE"
        REL_DIR="./build"
        RELI_DIR="../"
    fi

    if [ -f "package.json" ]; then
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    (>&2 echo "NOTE: npm doesn't honor \$SSPT_DEST_DIR")
}
sspt_build() {
    true
}
sspt_install() {
    npm install
}
sspt_clean() {
    true
}
sspt_clean_config() {
    rm -rf "$REL_DIR/node_packages"
}
EOF
    elif [ -f "Cargo.toml" ]; then
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    (>&2 echo "You may want to edit the .sspt file to enable or disable some features.")
}
sspt_build() {
    cargo build --release
}
sspt_install() {
    cargo install --root \$SSPT_DEST_DIR
}
sspt_clean() {
    cargo clean --release
}
sspt_clean_config() {
    true
}
EOF
    elif [ -f "setup.py" ]; then
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    (>&2 echo "NOTE: sspt assumes that the setup.py script will be executed by the correct python binary.")
    # ensure it is executable
    chmod +x $REL_DIR/setup.py
}
sspt_build() {
    "$REL_DIR/setup.py" build
}
sspt_install() {
    "$REL_DIR/setup.py" install -O2 --prefix \$SSPT_DEST_DIR
}
sspt_clean() {
    "$REL_DIR/setup.py" clean
}
sspt_clean_config() {
    "$REL_DIR/setup.py" clean -a
}
EOF
    elif ! [ -z "$(ls *.ipkg)" ]; then
        local IPKG_FILE=$(ls *.ipkg | head -1) # ensure it's only 1 file
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    (>&2 echo "NOTE: idris doesn't honor \$SSPT_DEST_DIR")
}
sspt_build() {
    idris --build "$REL_DIR/$IPKG_FILE"
}
sspt_install() {
    idris --install "$REL_DIR/$IPKG_FILE" && idris --installdoc "$REL_DIR/$IPKG_FILE"
}
sspt_clean() {
    idris --clean "$REL_DIR/$IPKG_FILE"
}
sspt_clean_config() {
    true
}
EOF
    elif ! [ -z "$(ls *.sln)" ]; then
        local SLN_FILE=$(ls *.sln | head -1)
        local PROBABLE_PROJECT_NAME=${SLN_FILE%.*}
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    (>&2 echo "NOTE: the \`install' command for xbuild projects is extremely hacky, you might want to tweak it.")
}
sspt_build() {
    xbuild /p:Configuration=Release "$REL_DIR/$SLN_FILE"
}
sspt_install() {
    cp "$RELI_DIR/$PROBABLE_PROJECT_NAME/bin/Release/"*.exe \$SSPT_DEST_DIR/bin && \
        cp "$RELI_DIR/$PROBABLE_PROJECT_NAME/bin/Release/"*.dll \$SSPT_DEST_DIR/lib
}
sspt_clean() {
    xbuild /p:Configuration=Release "$REL_DIR/$SLN_FILE" /t:Clean
}
sspt_clean_config() {
    true
}
EOF
    elif [ -f "stack.yaml" ]; then
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    stack build --only-configure
    (>&2 echo "NOTE: stack doesn't honor \$SSPT_DEST_DIR, but installs" \
        "everything to \$XDG_CONFIG_HOME , which is also the default value" \
        "of \$SSPT_DEST_DIR .")
}
sspt_build() {
    stack build --ghc-options -j$(nproc)
}
sspt_install() {
    stack install
}
sspt_clean() {
    stack clean
}
sspt_clean_config() {
    stack clean --full
}
EOF
    elif ! [ -z "$(ls *.cabal)" ]; then
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    cabal configure -O2 --user --prefix=\$SSPT_DEST_DIR --ghc-option=-j$(nproc)
}
sspt_build() {
    cabal build --ghc-option=-j$(nproc)
}
sspt_install() {
    cabal install --prefix=\$SSPT_DEST_DIR
}
sspt_clean() {
    cabal clean -s
}
sspt_clean_config() {
    rm -rf "$REL_DIR/dist"
}
EOF
    elif [ -f "SConstruct" ]; then
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    (>&2 echo "NOTE: SCons cannot install packages.")
}
sspt_build() {
    scons
}
sspt_install() {
    (>&2 echo "NOTE: SCons cannot install packages.")
}
sspt_clean() {
    scons -c
}
sspt_clean_config() {
    true
}
EOF
    elif [ -f "build.gradle" ]; then
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    (>&2 echo "NOTE: Gradle cannot install packages.")
}
sspt_build() {
    grdle -a
}
sspt_install() {
    (>&2 echo "NOTE: Gradle cannot install packages.")
}
sspt_clean() {
    (>&2 echo "NOTE: Gradle cannot clean packages.")
}
sspt_clean_config() {
    true
}
EOF
    elif ! [ -z "$(ls *.sbt)" ]; then
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    (>&2 echo "NOTE: sbt cannot install packages.")
}
sspt_build() {
    sbt
}
sspt_install() {
    (>&2 echo "NOTE: sbt cannot install packages.")
}
sspt_clean() {
    (>&2 echo "NOTE: sbt cannot clean packages.")
}
sspt_clean_config() {
    true
}
EOF
    elif [ -f "BUILD" ]; then
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    (>&2 echo "NOTE: Bazel cannot install packages.")
}
sspt_build() {
    bazel build
}
sspt_install() {
    (>&2 echo "NOTE: Bazel cannot install packages.")
}
sspt_clean() {
    bazel clean
}
sspt_clean_config() {
    true
}
EOF
        (>&2 echo "NOTE: sspt cannot figure out which target to use. Please edit the .sstp file manually.")
        return 1
    elif [ -f "meson.build" ]; then
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    meson --backend ninja --buildtype release --strip --prefix \$SSPT_DEST_DIR "$REL_DIR/meson-build"
}
sspt_build() {
    (>&2 echo "NOTE: meson builds automatically install binaries," \
        "so the project will only be built when installing.")
}
sspt_install() {
    ninja
}
sspt_clean() {
    ninja clean
}
sspt_clean_config() {
    rm -rf "$REL_DIR/meson-build"
}
EOF
    elif [ -f "build.ninja" ]; then
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    (>&2 echo "NOTE: ninja cannot install packages.")
}
sspt_build() {
    ninja
}
sspt_install() {
    (>&2 echo "NOTE: ninja cannot install packages.")
}
sspt_clean() {
    ninja clean
}
sspt_clean_config() {
    true
}
EOF
    elif [ -f "build.xml" ]; then
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    (>&2 echo "NOTE: ant cannot install packages.")
}
sspt_build() {
    ant
}
sspt_install() {
    (>&2 echo "NOTE: ant cannot install packages.")
}
sspt_clean() {
    ant clean
}
sspt_clean_config() {
    true
}
EOF
    elif [ -f "pom.xml" ]; then
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    true
}
sspt_build() {
    mvn -B package
}
sspt_install() {
    mvn -B install
}
sspt_clean() {
    mvn -B clean
}
sspt_clean_config() {
    true
}
EOF
    elif [ -f "CMakeLists.txt" ]; then
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    mkdir -p "$REL_DIR/cmake-build"
    pushd "$REL_DIR/cmake-build" >/dev/null
    cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=\$SSPT_DEST_DIR
    popd >/dev/null
}
sspt_build() {
    pushd "$REL_DIR/cmake-build" >/dev/null
    make -j$(nproc)
    popd >/dev/null
}
sspt_install() {
    pushd "$REL_DIR/cmake-build" >/dev/null
    make install
    popd >/dev/null
}
sspt_clean() {
    pushd "$REL_DIR/cmake-build" >/dev/null
    make clean
    popd >/dev/null
}
sspt_clean_config() {
    rm -rf "$REL_DIR/cmake-build"
}
EOF
    elif ! [ -z "$(ls *.pro)" ]; then
        local PRO_FILE="$(ls *.pro | head -1)"

        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    qmake -makefile "$REL_DIR/$PRO_FILE"
}
sspt_build() {
    make -j$(nproc)
}
sspt_install() {
    make install PREFIX=\$SSPT_DEST_DIR prefix=\$SSPT_DEST_DIR
}
sspt_clean() {
    make clean
}
sspt_clean_config() {
    rm "$REL_DIR/*akefile"
}
EOF
    elif [ -f "./configure" ]; then
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    "$REL_DIR/configure" --prefix=\$SSPT_DEST_DIR
}
sspt_build() {
    make -j$(nproc)
}
sspt_install() {
    make install
}
sspt_clean() {
    make clean
}
sspt_clean_config() {
    rm -rf "$REL_DIR/"*akefile "$REL_DIR/"config.*
}
EOF
    elif [ -f "Makefile" ]; then
        cat >> "$SSPT_FILE" <<EOF
sspt_config() {
    true
}
sspt_build() {
    make -j$(nproc)
}
sspt_install() {
    make install PREFIX=\$SSPT_DEST_DIR prefix=\$SSPT_DEST_DIR
}
sspt_clean() {
    make clean
}
sspt_clean_config() {
    true
}
EOF
    elif ! [ -z "$CHANGED_DIR" ]; then
        # try top directory instead
        popd >/dev/null
        DONT_LOOK_INTO_BUILD=1 autogen_buildsys
        return $?
    else
        (>&2 echo "Could not detect how to compile the package. ")
        return 1
    fi

    if ! [ -z "$CHANGED_DIR" ];
        popd >/dev/null
    fi
}

autogen_cwd() {
    touch ".sspt"
    #echo "name=\"$(basename `pwd`)\"" >> ".sspt"
    autogen_vcs
    autogen_buildsys
    return $?
}

main() {
    local ESCAPED_PKG=`escape_string $1`

    case $1 in
        -h|-?|--help)
            print_help
            ;;
        *)
            egrep -q -e "^$ESCAPED_PKG " -f "$SSPT_SRC_DB_FILE"
            if [ $? -ne 0 ]; then
                (>&2 echo "Package '$1' doesn't exist.")
                exit 1
            fi

            local PACKAGE_DIR=$(egrep -e "^$ESCAPED_PKG " -f "$SSPT_SRC_DB_FILE" \
                | egrep -v -o -e "^[A-Za-z0-9_\-\.]* " | egrep -v -o -e " [A-Za-z0-9]$")

            pushd "$PACKAGE_DIR" >/dev/null
            autogen_cwd
            local RETVAL=$?
            popd >/dev/null
            exit $RETVAL
            ;;
    esac
}

if [ $# -eq 0 ]; then
    print_help
    exit
fi

main $@

