#!/bin/sh
set -e
#
# Pegasus for Linux Quick Install script
#
# For the installation steps, including how to verify the contents of
# this file, see:
#
#   https://pegasus.readthedocs.io/en/latest/getting-pegasus/
#
# This script is meant for quick & easy install via:
#
#   $ sudo curl -fsSL https://get.pegasus.org | /bin/bash -s -- --no-dry-run
#

usage() {
    cat <<-EOF
Specify only one of the following:
--dist      : Display detected operating system and exit
-h, --help  : Display this message and exit
--download  : Download the tarball for a user-level installation and exit.
--dry-run   : Do not install, just print commands [default]
--no-dry-run: Issue all the commands neeed to install Pegasus
EOF
    exit 0
}

command_exists() {
    command -v "$@" > /dev/null 2>&1
}

is_download() {
    [[ $DOWNLOAD ]]
}

is_dry_run() {
    [[ $DRY_RUN ]]
}

is_display_dist() {
    [[ $DIST ]]
}

is_darwin() {
    case "$(uname -s)" in
        *darwin* ) true ;;
        *Darwin* ) true ;;
        * ) false;;
    esac
}


# Check if this is a forked Linux distro
check_forked() {

    if [ "$ID" = 'linuxmint' ]; then
        # Linux Mint is an Ubuntu fork
        ID='ubuntu'
        VERSION_CODENAME=$UBUNTU_CODENAME
        case $VERSION_CODENAME in
            jammy) VERSION_ID=22.04;;
            noble) VERSION_ID=24.04;;
        esac
    elif is_darwin; then
        case ${VERSION_ID%%.*} in
            14) VERSION_CODENAME=Sonoma;;
            15) VERSION_CODENAME=Sequoia;;
        esac
    fi

    if is_display_dist; then
        cat <<-EOF
You're using '$ID' version '$VERSION_ID' codename '$VERSION_CODENAME'.
EOF
        exit 0
    fi
}


get_distribution() {
    if [[ $DISTRIBUTION ]]; then
        #
        # For testing purposes.  DISTRIBUTION is a space-separated tuple:
        #      ${ID} ${VERSION_ID} ${VERSION_CODENAME}
        # where $VERSION_CODENAME number is only set on Debian and Ubuntu.
        # Because the list is space-separated, it must be quoted (or escaped)
        # on the command-line.  The values generated by this script for the
        # supported platforms follow.
        #
        #     debian 11 bullseye
        #     debian 12 bookworm
        #     ubuntu 22 jammy
        #     ubuntu 24 noble
        #     almalinux 8
        #     almalinux 9
        #     rocky 8
        #     rocky 9
        #     opensuse-leap 15
        #     alpine 3
        #     macos 14
        #     macos 15
        #

        set -- $DISTRIBUTION
        ID=$1
        VERSION_ID=$2
        VERSION_CODENAME=$3
        return
    fi

    # Every system that we officially support has /etc/os-release
    if is_darwin; then
        ID="macos"
        VERSION_ID=$(sw_vers -v)
        VERSION_CODENAME=${VERSION_ID}
    else
        . /etc/os-release
    fi

    check_forked

    VERSION_ID=${VERSION_ID%%.*}

    ARCH=$(arch)

    if [[ $SHOW_DISTRIBUTION ]]; then
        echo "${ID} ${VERSION_ID} ${VERSION_CODENAME} ${ARCH}"
        exit 0
    fi
}

do_install() {
    # Figure out the distribution and version we are running on.
    # This will set $ID and $VERSION_ID.
    get_distribution

    user=$(id -un 2>/dev/null || true)

    if is_dry_run; then
        sh_c="echo"
    elif [ "$user" != 'root' ]; then
        if command_exists sudo; then
            sh_c='sudo -E sh -c'
        elif command_exists su; then
            sh_c='su -c'
        else
            cat >&2 <<-'EOF'
Error: this installer needs the ability to run commands as root.
We are unable to find either "sudo" or "su" available to make this happen.
EOF
            exit 1
        fi
    fi

    case $ID in
        scientific|centos|rhel|almalinux|rocky|suse|opensuse-leap|macos|alpine)
            repo_cmd="dnf --assumeyes"
            case $ID in
                alpine)
                    repo_cmd="apk"
                    ;;
                macos)
                    repo_cmd="brew"
                    ;;
                centos|scientific)
                    repo_cmd="yum --assumeyes"
                    ;;
                suse|opensuse-leap)
                    repo_cmd="zypper --non-interactive"
                    ;;
            esac
    esac

    echo
    echo "Installing Pegasus for ${ID} ${VERSION_ID}"

    # Run install binaries for each distro accordingly
    case $ID in
        macos)
            (
            if ! is_dry_run; then
                set -x
            fi

            $sh_c "${repo_cmd} tap pegasus-isi/tools"
            $sh_c "${repo_cmd} install pegasus"
            )
            ;;
        alpine)
            (
            if ! is_dry_run; then
                set -x
            fi

            $sh_c "${repo_cmd} add curl"
            $sh_c "curl -o /tmp/pegasus.tgz ${DOWNLOAD_URL}/${CHANNEL}/pegasus-binary-${CHANNEL}-${ARCH}_${ID}_${VERSION_ID}.tar.gz"
            $sh_c "tar -xf /tmp/pegasus.tgz -C /tmp"
            $sh_c "cp -rf /tmp/pegasus-${CHANNEL}/* /usr/"
            )
            ;;
        ubuntu|debian)
            (
            if ! is_dry_run; then
                set -x
            fi

            echo
    echo "Adding our repository"
            apt_get='DEBIAN_FRONTEND=noninteractive apt-get'

            # Install our repository key.
            $sh_c "${apt_get} update"
            $sh_c "${apt_get} install -y curl gnupg sqlite3"
            $sh_c "curl https://download.pegasus.isi.edu/pegasus/gpg.txt | apt-key add -"

            # Add our repository.
            PEGASUS_LIST=/etc/apt/sources.list.d/pegasus.list
            $sh_c "echo 'deb https://download.pegasus.isi.edu/pegasus/${ID} ${VERSION_CODENAME} main' > ${PEGASUS_LIST}"
            if [ "${REPO_SUFFIX}" ]; then
                sed -i "/$REPO_SUFFIX/s/^#//" ${PEGASUS_LIST}
            fi

            echo
    echo "Updating package lists"
            $sh_c "${apt_get} update"

            echo
    echo "Installing Pegasus binaries and dependencies"
            $sh_c "${apt_get} install -y pegasus"
            )
            ;;
        suse|opensuse-leap)
            (
            if ! is_dry_run; then
                set -x
            fi

            $sh_c "${repo_cmd} install tar gzip"
            $sh_c "curl -o /tmp/pegasus.tgz ${DOWNLOAD_URL}/${CHANNEL}/pegasus-binary-${CHANNEL}-${ARCH}_${ID}_${VERSION_ID}.tar.gz"
            $sh_c "tar -xf /tmp/pegasus.tgz -C /tmp"
            $sh_c "cp -rf /tmp/pegasus-${CHANNEL}/* /usr/"
            )
            ;;
        scientific|centos|rhel|almalinux|rocky|suse|opensuse-leap)
            (
            if ! is_dry_run; then
                set -x
            fi

            repo_dist=$ID
            case $ID in
                scientific|centos|rhel|almalinux|rocky)
                    repo_dist="el"
                    echo
                    echo "Installing EPEL"
                    epel_version=$VERSION_ID
                    $sh_c "${repo_cmd} install epel-release sqlite"
                    ;;
                suse|opensuse-leap)
                    repo_dist="leap"
                    ;;
            esac
            repo_suffix="${repo_dist}${VERSION_ID}"

            # Just to make our lives harder, the packages we need from
            # EPEL depend on repositories which are disabled by default,
            # and those repositories and how to enable them between
            # RHEL and Rocky and between version 7 and 8.
            #
            case ${ID}.${VERSION_ID} in
                almalinux.8|rocky.8 ) $sh_c "dnf -y install dnf-plugins-core"
                                 $sh_c "dnf config-manager --set-enabled PowerTools || dnf config-manager --set-enabled powertools"
                                 ;;
                almalinux.9|rocky.9 ) $sh_c "dnf -y install dnf-plugins-core"
                                 $sh_c "dnf config-manager --set-enabled devel"
                                 ;;
                # subscription-manager only works if you've already
                # "register"ed and "attach"ed the system.
                rhel.8 ) ARCH=$(/bin/arch)
                         $sh_c "subscription-manager repos --enable \"codeready-builder-for-rhel-8-${ARCH}-rpms\""
                         ;;
                rhel.9 ) ARCH=$(/bin/arch)
                         $sh_c "subscription-manager repos --enable \"codeready-builder-for-rhel-9-${ARCH}-rpms\""
                         ;;
            esac

            echo
            echo "Installing the Pegasus repo"
            $sh_c "curl --output /etc/yum.repos.d/pegasus.repo https://download.pegasus.isi.edu/pegasus/rhel/${VERSION_ID}/pegasus.repo"

            echo
            echo "Installing Pegasus"
            $sh_c "${repo_cmd} install pegasus"
            )
            ;;
        *)
            if [[ ! $ID ]]; then
                if is_darwin; then
                    echo
                    echo "Error: Unsupported operating system 'macOS'"
                    echo
                    exit 1
                fi
            fi
            echo
            echo "Error: Unsupported distribution '$ID'"
            echo
            exit 1
            ;;
    esac
    echo
}

do_download() {
    get_distribution

    TARBALL_DIR_URL="${DOWNLOAD_URL}/${CHANNEL}"

    OS_VERSION=$VERSION_ID
    case $ID in
        alpine)
            ;;
        ubuntu)
            OS_NAME="ubuntu"
            ;;
        debian)
            OS_NAME="deb"
            ;;
        scientific|rhel)
            OS_NAME="rhel"
            ;;
        almalinux)
            OS_NAME="rhel"
            ;;
        rocky)
            OS_NAME="rhel"
            ;;
        suse|opensuse-leap)
            OS_NAME="suse"
            ;;
        *)
            if is_darwin; then
                OS_NAME=macos
            else
                echo
                echo "Error: Unsupported distribution '$ID'"
                echo
                exit 1
            fi
            ;;
    esac

    TARBALL_NAME="pegasus-binary-${CHANNEL}-${ARCH}_${OS_NAME}_${OS_VERSION}.tar.gz"
    TARBALL_URL="${TARBALL_DIR_URL}/${TARBALL_NAME}"

    echo "Downloading to pegasus.tar.gz..."
    curl -fSL "${TARBALL_URL}" -o pegasus.tar.gz
}

# Set global defaults
CHANNEL="5.1.0dev"
DOWNLOAD_URL="https://download.pegasus.isi.edu/pegasus"
DRY_RUN=1
sh_c='sh -c'
unset DIST

# Process command-line options
while [ $# -gt 0 ]; do
    case $1 in
        --show-distribution)
            SHOW_DISTRIBUTION=TRUE
            ;;
        --distribution)
            DISTRIBUTION=$2
            if [[ ! $DISTRIBUTION ]]; then
                echo "--distribution requires an argument"
                exit 1
            fi
            shift
            ;;
        --no-dry-run)
            unset DRY_RUN
            ;;
        --dry-run)
            DRY_RUN=1
            ;;
        --dist)
            DIST=1
            ;;
        --download)
            DOWNLOAD=1
            ;;
        --help|-h)
            usage
            ;;
        *)
            echo "Illegal option $1"
            echo "Run $0 --help for usage"
            exit 1
            ;;
    esac
    shift
done

# wrapped up in functions so that we have some protection against only getting
# half the file during "curl | sh"

if is_download; then
    do_download
else
    do_install
fi

exit 0
